Introduction

Eras are a method of configuring cmsRun in different ways for different operating scenarios. For example, one could specify a `Run2_25ns` era and the required configuration changes for running in Run2 at 25ns bunch spacing would automatically be applied. To then run under another scenario, e.g. `Run2_HI`, one just changes the era and the configuration automatically adapts.

This functionality was previously achieved through the use of customisation functions. Using customisation functions does not scale very well however and has numerous disadvantages, just two of which are:

  • Configuration changes are in one place far away from the things they are changing. A developer changing the default configuration (in the relevant package) may not be aware of the numerous customisations (in an arbitrary location, usually SLHCUpgradeSimulations/Configuration/python) and can break things.
  • Customisations are difficult to mix together. Generally a new customisation function is required for every combination of running scenarios.

Available eras

(This table was created on 26/May/2016, so it is somewhat out of date. Some knowledgeable person should update this or provide a link to more recent information!)
Era Description Replaces customisation function
Run2_25ns Customs for 25 ns bunchspacing running in Run 2 during 2015 customisePostLS1
Run2_50ns Customs for 50 ns bunchspacing running in Run 2 during 2015 customisePostLS1_50ns
Run2_HI Customs for Heavy Ion running in Run 2 during 2015 customisePostLS1_HI
Run1 Being integrated, not available yet. This currently does nothing, and is intended to do so for the foreseeable future. It's useful for scripts that require an era specified. N/A
Run2_2016 Being integrated, not available yet. 25 ns bunchspacing operation with the Stage 2 L1 trigger N/A
Run3 As Run2_2016 with GE1/1 N/A
Phase2 25 ns bunchspacing operation for Run4 and beyond N/A

Each of these is actually a "chain" of eras added together to make the configuration easier, e.g. `Run2_25ns` is made up of `run2_common`, `run2_25ns_specific` and `stage1L1Trigger`. Generally, users should use the eras that start with a capital letter, the ones starting with a lower case letter are for internal use.

If you are a developer and want to configure your subdetector/scenario/whatever you will need a new era to work with. The approval process of doing this has not been finalised yet, I would suggest you raise the issue in one of the Tuesday Core Software meetings or start a thread on the framework hypernews forum.

The `Run2_<something>` eras have been implemented and validated. The runTheMatrix tests which test all new pull requests to CMSSW have been switched to use the eras instead of customisation functions.

Activating an era

Activating in cmsDriver

Simply add the --era <eraName1>,<eraName2>,<eraName3> option to your normal cmsDriver command. If you have more than one there should be no spaces between the commas and the era names.

As mentioned, the `Run2_25ns` era replaces the `customisePostLS1` customisation. So replace:

    --customise SLHCUpgradeSimulations/Configuration/postLS1Customs.customisePostLS1

with:

    --era Run2_25ns

Note that the era does not currently configure the pileup configuration (this may change in the future), only things like the trigger and pixel dynamic inefficiency. So it is quite easy to configure incompatible era and pileup options, e.g. `--era Run2_50ns --pileup AVE_140_BX_25ns` will have 25ns pileup applied but the pixel inefficiency for 50ns bunch spacing. It is your responsibility to make sure the era and pileup commands match.

Activating in a configuration file

It is generally advised you configure through cmsDriver (discussed above), but if you do have your own configuration files to run... Then do something similar to the following to set the era (substituting an appropriate process name and era name). The era should be passed to the constructor of the process object at the top of your configuration file.

import FWCore.ParameterSet.Config as cms
from Configuration.Eras.Era_Run2_2018_cff import Run2_2018
process = cms.Process("Sim",Run2_2018)

More than one can be specified. For example

process = cms.Process('HLT', Run2_25ns, HypotheticalOtherEra)

You are responsible for making sure the eras you supply make sense for the rest of the configuration. See the note above about mismatching the pileup bunch spacing and era.

Configuring using an era

This section is for developers who want to change the configuration of their module if a particular era is active. The `run2_common` era (one of the `Run2_25ns` components) is used as an example, but the other eras can be configured in the same way. It is the components that should be configured in your python files, so that new eras can easily be created by including the correct components. The available "sub-era" components are:

(as of 21/Oct/2015)

Sub-era Description Used In
run2_common Customs relevant to all Run 2 scenarios Run2_25ns, Run2_50ns, Run2_HI, Run2_2016
run2_25ns_specific 25 ns bunchspacing specific changes Run2_25ns, Run2_2016
run2_50ns_specific 50 ns bunchspacing specific changes Run2_50ns
run2_HI_specific Heavy ion specific changes Run2_HI
fastSim Changes specific to FastSim N/A, cmsDriver automatically enables it if the "--fast" option is specified
stage1L1Trigger Changes for the Stage 1 L1 trigger Run2_25ns, Run2_50ns, Run2_HI. N.B. Having it in Run2_50ns is probably a mistake, need to check with trigger experts. Yes indeed, fixed here
stage2L1Trigger Being integrated, not available yet. Changes for the Stage 2 trigger which will run in 2016 Run2_2016
Run1 Being integrated, not available yet. It is not foreseen that this will have any changes applied to it. This is itself a "top-level" era with no components.

All changes to a module should be done in the same python file that the module is declared in. cmsRun will only execute those changes if the era specified is active.

Simple parameter changes

Each era object has a method toModify that can be used to make simple parameter changes. The syntax is eraObject.toModify( moduleName, parameterName=newValue ). Here's an example of how to make a simple change.

import FWCore.ParameterSet.Config as cms

myProducer = cms.EDProducer( "MyProducerType",
    generalParameter = cms.string("valueForAllScenarios"),
    customisedParameter = cms.string("valueForDefaultScenario")
)

#
# Everything above this line is how it would be before eras were introduced.
# Now do some customisation for a particular running scenario using the era.
#
# First need to import the available eras from the standard location
from Configuration.StandardSequences.Eras import eras

# Then make a change for run2
eras.run2_common.toModify( myProducer, customisedParameter=cms.string("valueForRun2") )

# You can change the parameter for other scenarios as well. If the run3 era existed
# (it doesn't) you could specify a value for this or any other parameter.
eras.run3.toModify( myProducer, customisedParameter=cms.string("valueForRun3") )

# You can also specify more than one parameter at a time, and add parameters that
# didn't previously exist.
eras.run5.toModify( myProducer, customisedParameter=cms.string("valueForRun5"), newParameter=cms.string("parameter only in run5") )

Removing parameters

The toModify method can also be used to remove a parameter which was previously defined. This is done by setting the value of the parameter to None.

import FWCore.ParameterSet.Config as cms

myProducer = cms.EDProducer( "MyProducerType",
    generalParameter = cms.string("valueForAllScenarios"),
    onlyNeededSometimesParameter = cms.string("valueForDefaultScenario")
)

# First need to import the available eras from the standard location
from Configuration.StandardSequences.Eras import eras

# For run 2 we get rid of onlyNeededSometimesParameter
eras.run2_common.toModify( myProducer, onlyNeededSometimesParameter =None )

Modifying parameters of PSets

Parameters which are parts of embedded PSets can also be modified via the use of a python dictionary.
...
myProducer = cms.EDProducer( "MyProducerType",
    generalParameter = cms.string("valueForAllScenarios"),
    aPSet = cms.PSet( aParameter = cms.int32(1),
                      toChangeParameter = cms.int32(5))
)

#This is equivalent to myProducer.aPSet.toChangeParameter = 10
eras.run2_common.toModify( myProducer, aPSet = dict(toChangeParameter = 10) )

This syntax can be used to

  • remove parameters using None
  • add new parameters by using the new parameter's name in the dictionary
  • change parameters of PSets embedded arbitrarily far within other PSets

...
myProducer = cms.EDProducer( "MyProducerType",
    aPSet = cms.PSet( anOptionalParameter = cms.int32(1),
                      embeddedPSet = cms.PSet( toChange = cms.int32(5) )
    )
)

#Example of a more complex change
eras.run2_common.toModify( myProducer, 
    aPSet = dict(anOptionalParameter = None,
                 embeddedPSet = dict(toChange = 10,
                                     newParameter = cms.string("Value") ) 
                 )
)

Replacing whole objects

If a simple modification of the object is insufficient to make the change, it is possible to completely replace one object with another one via the eras. This is accomplished using the toReplaceWith method.

...
myProducer = cms.EDProducer( "MyProducerType",
    simpleParameter = cms.bool(True)
)

#Change module type 
eras.run2_common.toReplaceWith( myProducer, 
                                cms.EDProducer("AnotherProducerType", 
                                                otherParameters = cms.int32(0) )
)

One can use toReplaceWith to change objects which do not have parameters such as Sequence, Path and EndPath.

...
aSequence = cms.Sequence( moduleA + moduleB + moduleNotNeededForRun2)

#create a run2 sequence 
# NOTE: start name with _ since import will ignore that variable
_run2_aSequence = aSequence.copy()
_run2_aSequence.remove(moduleNotNeededForRun2)

#Specify we want to use our other sequence 
eras.run2_common.toReplaceWith( aSequence, 
                                _run2_aSequence)
)

"if" statements (DISALLOWED)

The following method is no longer allowed and will be removed in the future.

You can simply query an era to see if it is active with the "isChosen" method, then do something specific if it is. For example:

import FWCore.ParameterSet.Config as cms

myProducer = cms.EDProducer( "MyProducerType",
    generalParameter = cms.string("valueForAllScenarios"),
    customisedParameter = cms.string("valueForDefaultScenario")
)

from Configuration.StandardSequences.Eras import eras

if eras.run2_common.isChosen() :
    myProducer.customisedParameter=cms.string("valueForRun2")

This is however discouraged, because it makes it harder to track changes. For example, functionality might be added in the future to add the option of tracing all changes an era makes, so that one could see the information in one place. Using these "if" constructs would make that far more difficult.

More involved changes (deprecated)

Note: this mechanism is being deprecated because of the improvements to toModify and toReplaceWith. Please make every effort to use those mechanisms instead.

If the change you want to make needs to have some logic, or it is more complicated than a simple change, you can specify a function to modify the module configuration. This is done by passing a callable named func to toModify. This callable should take the object to be modified as the only argument. Note that this effectively means you can't make simple changes (as described above) on a parameter named "func".

As an example:

myProducer = cms.EDProducer( "MyProducerType",
# ...the rest of the default declaration trimmed for brevity...

from Configuration.StandardSequences.Eras import eras

def _modifyMyModuleForRun2( moduleObject ) :
    for item in moduleObject.parameterList :
        item.value+=9

eras.run2_common.toModify( myProducer, func=_modifyMyModuleForRun2 )

You can name the function anything you want, but you are advised to start it with an underscore so that it is not imported with process.load(...) commands and potentially cause name clashes.

Modifying the whole process object

Sometimes the whole process object needs to be changed, for example to remove or add things to the sequence. This can be done by writing a function that takes the process object as its only argument, but for technical reasons the syntax to add this to an era is a bit different. The function is passed to the makeProcessModifier method of the era, which creates an object which must be assigned a unique name. Without going into the technicalities, it's because these changes can only be applied if the object returned from makeProcessModifier is loaded into the Process. Using a unique name guarantees that even if the python module is imported into another python module the object will not be overwritten. This unique name can be anything, but to avoid naming clashes you are advised to include the filename of the python file, and add an underscore to the end e.g. modify<pythonFilename>ForRun2_. The underscore on the end doesn't mean anything to python, but cms.Process doesn't allow underscores in module names so name clashes are avoided there.

As an example:

def _modifyDigiToRawForRun2( theProcess ) : # Note - this isn't the name that needs to be unique
    """
    Modifies the DigiToRaw sequence for running in Run 2
    """
    theProcess.load("L1Trigger.L1TCommon.l1tDigiToRaw_cfi")
    # Note that this function is applied before the objects in this file are added
    # to the process. So things declared in this file should be used "bare", i.e.
    # not with "theProcess." in front of them. l1tDigiToRaw is an exception because
    # it is not declared in this file but loaded into the process in the "load"
    # statement above.
    l1tDigiToRawSeq = cms.Sequence( gctDigiToRaw + theProcess.l1tDigiToRaw )
    DigiToRaw.replace( gctDigiToRaw, l1tDigiToRawSeq )

# A unique name is required for this object, so I'll call it "modify<python filename>ForRun2_"
modifyConfigurationStandardSequencesDigiToRawForRun2_ = eras.run2_common.makeProcessModifier( _modifyDigiToRawForRun2 )

Chaining eras together

Eras can be bundled together, so that they can be referred to as one name. For example, each of `Run2_25ns`,`Run2_50ns` and `Run2_HI` are actually made up of "sub-eras". This is just to make configuring them easier - all of them contain the `run2_common` era, then each one as specific parts, e.g. `run2_50ns_specific` for `Run2_50ns`.

As a hypothetical example, one could have a trackerPhase2 era that configures the tracker upgrade; a hcalRebuild era that configures the HCal upgrade; and endcapShashlik and endcapHGCal that configure different endcap options. The entire upgraded detector could be configured by creating one chained set of eras of trackerPhase2, hcalRebuild and endcapShashlik (called, say, ShashlikFullDetector); and another chained set of trackerPhase2, hcalRebuild and endcapHGCal (called, say, HGCalFullDetector). This way a tracker developer only needs to worry about maintaining one era, rather than making duplicate changes in all the eras that use the upgraded tracker, in this example ShashlikFullDetector and HGCalFullDetector.

As mentioned previously, the current convention is to use an initial capital letter for an era that the user can specify, lower case for internal use eras.

Specifying these chained eras is probably the job of the core software group. Get in touch with them if you have any suggestions.

Using both Eras and fillDescriptions for a module

An established practice is to use fillDescriptions() to generate moduleLabelDefault_cfi.py, and explicitly create moduleLabel_cfi.py with

from package.subpackage.moduleLabelDefault_cfi import moduleLabelDefault as _moduleLabelDefault
...
moduleLabel = _moduleLabelDefault.clone()
...
modifier1.toModify(moduleLabel, ...)
modifier2.toModify(moduleLabel, ...)

Questions

If you have any questions, in the first instance it's probably best to contact Mark Grimes. Chris Jones and David Lange are also experts.

Edit | Attach | Watch | Print version | History: r17 < r16 < r15 < r14 < r13 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r17 - 2019-12-10 - DavidDagenhart
 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    CMSPublic All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2021 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
or Ideas, requests, problems regarding TWiki? use Discourse or Send feedback