Skip to content

Commit

Permalink
Use mayConsumes in VolumeBasedMagneticFieldESProducerFromDB
Browse files Browse the repository at this point in the history
The module decides which geometry to read from the database by
reading the value stored in the MagFieldConfig EventSetup object.
The decision cannot be made at module configuration time, only at
run time. Therefore mayConsumes must be used.

Unit tests were added to guarantee the module's behavior is the
same after this change.
  • Loading branch information
Dr15Jones authored and oshadura committed Oct 21, 2019
1 parent 478c2e7 commit 12e01e3
Show file tree
Hide file tree
Showing 9 changed files with 481 additions and 76 deletions.
Expand Up @@ -20,6 +20,7 @@
#include "FWCore/Framework/interface/ESTransientHandle.h"
#include "FWCore/Framework/interface/EventSetup.h"
#include "FWCore/ParameterSet/interface/ParameterSet.h"
#include "FWCore/Utilities/interface/ESProductTag.h"

#include "DetectorDescription/Core/interface/DDCompactView.h"
#include "FWCore/Framework/interface/ModuleFactory.h"
Expand Down Expand Up @@ -51,106 +52,148 @@ namespace magneticfield {
class VolumeBasedMagneticFieldESProducerFromDB : public edm::ESProducer {
public:
VolumeBasedMagneticFieldESProducerFromDB(const edm::ParameterSet& iConfig);
// forbid copy ctor and assignment op.
VolumeBasedMagneticFieldESProducerFromDB(const VolumeBasedMagneticFieldESProducerFromDB&) = delete;
const VolumeBasedMagneticFieldESProducerFromDB& operator=(const VolumeBasedMagneticFieldESProducerFromDB&) = delete;

std::shared_ptr<MagFieldConfig const> chooseConfigViaParameter(const IdealMagneticFieldRecord& iRecord);
std::shared_ptr<MagFieldConfig const> chooseConfigAtRuntime(const IdealMagneticFieldRecord& iRecord);

std::unique_ptr<MagneticField> produce(const IdealMagneticFieldRecord& iRecord);

static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);

private:
// forbid copy ctor and assignment op.
VolumeBasedMagneticFieldESProducerFromDB(const VolumeBasedMagneticFieldESProducerFromDB&) = delete;
const VolumeBasedMagneticFieldESProducerFromDB& operator=(const VolumeBasedMagneticFieldESProducerFromDB&) = delete;
std::string closerNominalLabel(float current);
static std::string_view closerNominalLabel(float current);

edm::ESGetToken<MagFieldConfig, MagFieldConfigRcd> mayGetConfigToken_;
edm::ESGetToken<RunInfo, RunInfoRcd> runInfo_;
edm::ESGetToken<MagFieldConfig, MagFieldConfigRcd> knownFromParamConfigToken_;

edm::ParameterSet pset;
std::vector<int> nominalCurrents;
std::vector<std::string> nominalLabels;
//NOTE: change of record since this MagFieldConfig was chosen based on data
// from the record RunInfoRcd so therefore has a dependency upon that record
edm::ESGetToken<MagFieldConfig, IdealMagneticFieldRecord> chosenConfigToken_;

edm::ESGetToken<FileBlob, MFGeometryFileRcd> mayConsumeBlobToken_;
const int current_;
const bool debug_;
};
} // namespace magneticfield

VolumeBasedMagneticFieldESProducerFromDB::VolumeBasedMagneticFieldESProducerFromDB(const edm::ParameterSet& iConfig)
: pset(iConfig) {
setWhatProduced(this, pset.getUntrackedParameter<std::string>("label", ""));
nominalCurrents = {-1, 0, 9558, 14416, 16819, 18268, 19262};
nominalLabels = {"3.8T", "0T", "2T", "3T", "3.5T", "3.8T", "4T"};
}
: current_(iConfig.getParameter<int>("valueOverride")),
debug_(iConfig.getUntrackedParameter<bool>("debugBuilder")) {
std::string const myConfigLabel = "VBMFESChoice";
//Based on configuration, pick algorithm to produce the proper MagFieldConfig with a specific label
if (current_ < 0) {
//We do not know what to get until we first read RunInfo
setWhatProduced(
this, &VolumeBasedMagneticFieldESProducerFromDB::chooseConfigAtRuntime, edm::es::Label(myConfigLabel))
.setMayConsume(
mayGetConfigToken_,
[](auto const& iGet, edm::ESTransientHandle<RunInfo> iHandle) {
return iGet("", closerNominalLabel(iHandle->m_avg_current));
},
edm::ESProductTag<RunInfo, RunInfoRcd>("", ""));

// ------------ method called to produce the data ------------
std::unique_ptr<MagneticField> VolumeBasedMagneticFieldESProducerFromDB::produce(
const IdealMagneticFieldRecord& iRecord) {
bool debug = pset.getUntrackedParameter<bool>("debugBuilder", false);

// Get value of the current from condition DB
float current = pset.getParameter<int>("valueOverride");
string message;
if (current < 0) {
ESHandle<RunInfo> rInfo;
iRecord.getRecord<RunInfoRcd>().get(rInfo);
current = rInfo->m_avg_current;
message = " (from RunInfo DB)";
} else {
message = " (from valueOverride card)";
//we know exactly what we are going to get
setWhatProduced(
this, &VolumeBasedMagneticFieldESProducerFromDB::chooseConfigViaParameter, edm::es::Label(myConfigLabel))
.setConsumes(runInfo_)
.setConsumes(knownFromParamConfigToken_, edm::ESInputTag(""s, std::string(closerNominalLabel(current_))));
}
string configLabel = closerNominalLabel(current);

// Get configuration
ESHandle<MagFieldConfig> confESH;
iRecord.getRecord<MagFieldConfigRcd>().get(configLabel, confESH);
const MagFieldConfig* conf = &*confESH;
auto const label = iConfig.getUntrackedParameter<std::string>("label");
auto const myConfigTag = edm::ESInputTag(iConfig.getParameter<std::string>("@module_label"), myConfigLabel);

//We use the MagFieldConfig created above to decide which FileBlob to use
setWhatProduced(this, label)
.setMayConsume(
mayConsumeBlobToken_,
[](auto const& iGet, edm::ESTransientHandle<MagFieldConfig> iConfig) {
if (iConfig->version == "parametrizedMagneticField") {
return iGet.nothing();
}
return iGet("", std::to_string(iConfig->geometryVersion));
},
edm::ESProductTag<MagFieldConfig, IdealMagneticFieldRecord>(myConfigTag))
.setConsumes(chosenConfigToken_, myConfigTag); //Use same tag as the choice
}

std::shared_ptr<MagFieldConfig const> VolumeBasedMagneticFieldESProducerFromDB::chooseConfigAtRuntime(
IdealMagneticFieldRecord const& iRcd) {
edm::ESHandle<MagFieldConfig> config = iRcd.getHandle(mayGetConfigToken_);

//just forward what we just got but do not take ownership
return std::shared_ptr<MagFieldConfig const>(config.product(), [](auto*) {});
}

std::shared_ptr<MagFieldConfig const> VolumeBasedMagneticFieldESProducerFromDB::chooseConfigViaParameter(
const IdealMagneticFieldRecord& iRecord) {
auto config = iRecord.getHandle(knownFromParamConfigToken_);

edm::LogInfo("MagneticField|AutoMagneticField")
<< "Current: " << current << message << "; using map configuration with label: " << configLabel << endl
<< "Version: " << conf->version << " geometryVersion: " << conf->geometryVersion
<< " slaveFieldVersion: " << conf->slaveFieldVersion;
//just forward what we just got but do not take ownership
return std::shared_ptr<MagFieldConfig const>(config.product(), [](auto*) {});
}

// ------------ method called to produce the data ------------
std::unique_ptr<MagneticField> VolumeBasedMagneticFieldESProducerFromDB::produce(
const IdealMagneticFieldRecord& iRecord) {
auto const& conf = iRecord.getTransientHandle(chosenConfigToken_);

// Get the parametrized field
std::unique_ptr<MagneticField> paramField =
ParametrizedMagneticFieldFactory::get(conf->slaveFieldVersion, conf->slaveFieldParameters);

if (conf->version == "parametrizedMagneticField") {
// The map consist of only the parametrization in this case
return paramField;
} else {
// Full VolumeBased map + parametrization
MagGeoBuilderFromDDD builder(conf->version, conf->geometryVersion, debug);

// Set scaling factors
if (!conf->keys.empty()) {
builder.setScaling(conf->keys, conf->values);
}

// Set specification for the grid tables to be used.
if (!conf->gridFiles.empty()) {
builder.setGridFiles(conf->gridFiles);
}

// Build the geomeytry (DDDCompactView) from the DB blob
// (code taken from GeometryReaders/XMLIdealGeometryESSource/src/XMLIdealMagneticFieldGeometryESProducer.cc)
edm::ESTransientHandle<FileBlob> gdd;
iRecord.getRecord<MFGeometryFileRcd>().get(std::to_string(conf->geometryVersion), gdd);

auto cpv = std::make_unique<DDCompactView>(DDName("cmsMagneticField:MAGF"));
DDLParser parser(*cpv);
parser.getDDLSAX2FileHandler()->setUserNS(true);
parser.clearFiles();
std::unique_ptr<std::vector<unsigned char> > tb = (*gdd).getUncompressedBlob();
parser.parse(*tb, tb->size());
cpv->lockdown();

builder.build(*cpv);

// Build the VB map. Ownership of the parametrization is transferred to it
return std::make_unique<VolumeBasedMagneticField>(conf->geometryVersion,
builder.barrelLayers(),
builder.endcapSectors(),
builder.barrelVolumes(),
builder.endcapVolumes(),
builder.maxR(),
builder.maxZ(),
paramField.release(),
true);
}

// Full VolumeBased map + parametrization
MagGeoBuilderFromDDD builder(conf->version, conf->geometryVersion, debug_);

// Set scaling factors
if (!conf->keys.empty()) {
builder.setScaling(conf->keys, conf->values);
}

// Set specification for the grid tables to be used.
if (!conf->gridFiles.empty()) {
builder.setGridFiles(conf->gridFiles);
}

// Build the geometry (DDDCompactView) from the DB blob
// (code taken from GeometryReaders/XMLIdealGeometryESSource/src/XMLIdealMagneticFieldGeometryESProducer.cc)

auto const& blob = iRecord.getTransientHandle(mayConsumeBlobToken_);

DDCompactView cpv{DDName("cmsMagneticField:MAGF")};
DDLParser parser(cpv);
parser.getDDLSAX2FileHandler()->setUserNS(true);
parser.clearFiles();
std::unique_ptr<std::vector<unsigned char> > tb = blob->getUncompressedBlob();
parser.parse(*tb, tb->size());
cpv.lockdown();

builder.build(cpv);

// Build the VB map. Ownership of the parametrization is transferred to it
return std::make_unique<VolumeBasedMagneticField>(conf->geometryVersion,
builder.barrelLayers(),
builder.endcapSectors(),
builder.barrelVolumes(),
builder.endcapVolumes(),
builder.maxR(),
builder.maxZ(),
paramField.release(),
true);
}

std::string VolumeBasedMagneticFieldESProducerFromDB::closerNominalLabel(float current) {
std::string_view VolumeBasedMagneticFieldESProducerFromDB::closerNominalLabel(float current) {
constexpr std::array<int, 7> nominalCurrents = {{-1, 0, 9558, 14416, 16819, 18268, 19262}};
constexpr std::array<std::string_view, 7> nominalLabels = {{"3.8T", "0T", "2T", "3T", "3.5T", "3.8T", "4T"}};

int i = 0;
for (; i < (int)nominalLabels.size() - 1; i++) {
if (2 * current < nominalCurrents[i] + nominalCurrents[i + 1])
Expand All @@ -159,4 +202,13 @@ std::string VolumeBasedMagneticFieldESProducerFromDB::closerNominalLabel(float c
return nominalLabels[i];
}

void VolumeBasedMagneticFieldESProducerFromDB::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
edm::ParameterSetDescription desc;
desc.addUntracked<bool>("debugBuilder", false);
desc.add<int>("valueOverride", -1)->setComment("Force value of current (in A); take the value from DB if < 0.");
desc.addUntracked<std::string>("label", "");

descriptions.addDefault(desc);
}

DEFINE_FWK_EVENTSETUP_MODULE(VolumeBasedMagneticFieldESProducerFromDB);
2 changes: 2 additions & 0 deletions MagneticField/GeomBuilder/test/BuildFile.xml
Expand Up @@ -8,3 +8,5 @@
<use name="CondFormats/MFObjects"/>
<flags EDM_PLUGIN="1"/>
</library>

<test name="MagneticFieldGeomBuilderTest" command="testMagneticFieldDB.sh"/>
102 changes: 102 additions & 0 deletions MagneticField/GeomBuilder/test/python/testMagneticFieldDB_cfg.py
@@ -0,0 +1,102 @@
#


import FWCore.ParameterSet.Config as cms

process = cms.Process("MAGNETICFIELDTEST")
process.maxEvents.input = 6

process.source = cms.Source("EmptySource",
firstLuminosityBlockForEachRun = cms.untracked.VLuminosityBlockID(
cms.LuminosityBlockID(10,1),
cms.LuminosityBlockID(20,2),
cms.LuminosityBlockID(30,3),
cms.LuminosityBlockID(40,4),
cms.LuminosityBlockID(50,5),
cms.LuminosityBlockID(60,6)
),
numberEventsInLuminosityBlock =cms.untracked.uint32(1)
)

process.add_( cms.ESProducer("RunInfoTestESProducer",
runInfos = cms.VPSet(cms.PSet(run = cms.int32(10), avg_current = cms.double(0.)),
cms.PSet(run = cms.int32(20), avg_current = cms.double(9000.)),
cms.PSet(run = cms.int32(30), avg_current = cms.double(14000.)),
cms.PSet(run = cms.int32(40), avg_current = cms.double(17000.)),
cms.PSet(run = cms.int32(50), avg_current = cms.double(18000.)),
cms.PSet(run = cms.int32(60), avg_current = cms.double(19000.)),
) ) )

process.riSource = cms.ESSource("EmptyESSource", recordName = cms.string("RunInfoRcd"),
iovIsRunNotTime = cms.bool(True),
firstValid = cms.vuint32(10,20,30,40,50,60))

process.load("MagneticField.Engine.volumeBasedMagneticFieldFromDB_cfi")

process.load("Configuration/StandardSequences/CondDBESSource_cff")
from Configuration.AlCa.GlobalTag import GlobalTag
process.GlobalTag = GlobalTag(process.GlobalTag, 'auto:mc', '')

#configuration of GlobalTag comes from MagneticField/Engine/test/testMagneticFieldDB.py
process.GlobalTag.toGet = cms.VPSet(
cms.PSet(record = cms.string("MFGeometryFileRcd"),
tag = cms.string("MFGeometry_160812"),
connect = cms.string("frontier://FrontierProd/CMS_CONDITIONS"),
label = cms.untracked.string("160812")
),
# Configurations
cms.PSet(record = cms.string("MagFieldConfigRcd"),
tag = cms.string("MFConfig_71212_0T"),
connect = cms.string("frontier://FrontierProd/CMS_CONDITIONS"),
label = cms.untracked.string("0T")
),
cms.PSet(record = cms.string("MagFieldConfigRcd"),
tag = cms.string("MFConfig_71212_2T"),
connect = cms.string("frontier://FrontierProd/CMS_CONDITIONS"),
label = cms.untracked.string("2T")
),
cms.PSet(record = cms.string("MagFieldConfigRcd"), # version 160812, 3T (good also for Run1)
tag = cms.string("MFConfig_160812_Run2_3T"),
connect = cms.string("frontier://FrontierProd/CMS_CONDITIONS"),
label = cms.untracked.string("3T")
),
cms.PSet(record = cms.string("MagFieldConfigRcd"), # version 160812, 3.5T (good also for Run1)
tag = cms.string("MFConfig_160812_Run2_3_5T"),
# connect = cms.string("frontier://PromptProd/CMS_CONDITIONS"),
connect = cms.string("frontier://FrontierProd/CMS_CONDITIONS"),
label = cms.untracked.string("3.5T")
),
cms.PSet(record = cms.string("MagFieldConfigRcd"), # version 160812, 3.8T
tag = cms.string("MFConfig_160812_Run2_3_8T"), #Run 2, version 160812, 3.8T (single IOV, for MC)
# connect = cms.string("frontier://PromptProd/CMS_CONDITIONS"),
connect = cms.string("frontier://FrontierProd/CMS_CONDITIONS"),
label = cms.untracked.string("3.8T")
),
cms.PSet(record = cms.string("MagFieldConfigRcd"),
tag = cms.string("MFConfig_71212_4T"),
connect = cms.string("frontier://FrontierProd/CMS_CONDITIONS"),
label = cms.untracked.string("4T")
),
)

process.MessageLogger = cms.Service("MessageLogger",
categories = cms.untracked.vstring("MagneticField"),
destinations = cms.untracked.vstring("cout"),
cout = cms.untracked.PSet(
noLineBreaks = cms.untracked.bool(True),
threshold = cms.untracked.string("WARNING"),
WARNING = cms.untracked.PSet(
limit = cms.untracked.int32(0)
),
MagneticField = cms.untracked.PSet(
limit = cms.untracked.int32(10000000)
)
)
)


process.testMagneticField = cms.EDAnalyzer("testMagneticField"
)

process.p1 = cms.Path(process.testMagneticField)

0 comments on commit 12e01e3

Please sign in to comment.