Esempio n. 1
0
    def digits(self):
        """
        Configure processing of Digits
        """
        digitConf = CaloDigitConf()
        digitConf.Context = "Offline"
        digitConf.OutputLevel = self.getProp('OutputLevel')
        digitConf.EnableDigitsOnDemand = self.getProp('EnableRecoOnDemand')
        digitConf.CreateADCs = self.getProp('CreateADCs')
        digitConf.Verbose = self.getProp('Verbose')
        if self.getProp('NoSpdPrs'):
            digitConf.Detectors = ['Ecal', 'Hcal']
            # deactivate Spd/Prs in DecoderDB
            from DAQSys.Decoders import DecoderDB
            from DAQSys.DecoderClass import Decoder
            Decoder("CaloDigitsFromRaw/SpdFromRaw",
                    active=False,
                    conf=DecoderDB)
            Decoder("CaloDigitsFromRaw/PrsFromRaw",
                    active=False,
                    conf=DecoderDB)

        return digitConf.digits()
Esempio n. 2
0
TAlignment().WriteCondSubDetList = ['VP']
TAlignment().EigenValueThreshold = 100
TAlignment().UsePreconditioning = True
TAlignment().UseLocalFrame = True
# include survey constraints

surveyconstraints = SurveyConstraints()
surveyconstraints.VP()

# Convert Calo ReadoutStatus to ProcStatus
caloBanks = GaudiSequencer("CaloBanksHandler")
caloDetectors = [
    det for det in ['Spd', 'Prs', 'Ecal', 'Hcal'] if det in detectors
]
CaloDigitConf(ReadoutStatusConvert=True,
              Sequence=caloBanks,
              Detectors=caloDetectors)
GaudiSequencer("EscherSequencer").Members += [caloBanks]

# New NoSPDPRS switches
noSPDPRS = False
if [det for det in ['Spd', 'Prs'] if det not in detectors]:
    noSPDPRS = True
CaloProcessor().setProp("NoSpdPrs", noSPDPRS)
GlobalRecoConf().setProp("NoSpdPrs", noSPDPRS)


def doMyChanges():
    GaudiSequencer("HltFilterSeq").Members = []

Esempio n. 3
0
    def configureSequences(self, withMC, handleLumi, vetoHltErrorEvents):
        brunelSeq = GaudiSequencer("BrunelSequencer")
        brunelSeq.Context = self.getProp("Context")
        ApplicationMgr().TopAlg += [ brunelSeq ]
        brunelSeq.Members += [ "ProcessPhase/Init" ]
        physicsSeq = GaudiSequencer( "PhysicsSeq" )

        # Treatment of luminosity events
        if handleLumi:
            lumiSeq = GaudiSequencer("LumiSeq")

            # Prepare the FSR
            if self.getProp("WriteFSR"):
                self.setOtherProps(LumiAlgsConf(),["Context","DataType","InputType","Simulation"])
                lumiCounters = GaudiSequencer("LumiCounters")
                lumiSeq.Members += [ lumiCounters ]
                LumiAlgsConf().LumiSequencer = lumiCounters

            # Trigger masks changed in 2016, see LHCBPS-1486
            if self.getProp( "DataType" ) in self.Run1DataTypes or self.getProp( "DataType" ) in [ "2015" ]:
                physFilterRequireMask = [ 0x0, 0x4, 0x0 ]
                lumiFilterRequireMask = [ 0x0, 0x2, 0x0 ]
            else:
                physFilterRequireMask = [ 0x0, 0x0, 0x80000000 ]
                lumiFilterRequireMask = [ 0x0, 0x0, 0x40000000 ]

            # Filter out Lumi only triggers from further processing, but still write to output
            from Configurables import HltRoutingBitsFilter
            physFilter = HltRoutingBitsFilter( "PhysFilter", RequireMask = physFilterRequireMask )
            physicsSeq.Members += [ physFilter ]
            lumiFilter = HltRoutingBitsFilter( "LumiFilter", RequireMask = lumiFilterRequireMask )
            lumiSeq.Members += [ lumiFilter, physFilter ]
            lumiSeq.ModeOR = True

            # Sequence to be executed if physics sequence not called (nano events)
            notPhysSeq = GaudiSequencer("NotPhysicsSeq")
            notPhysSeq.ModeOR = True
            notPhysSeq.Members = [ physFilter ]

            brunelSeq.Members += [ lumiSeq, notPhysSeq ]
            
        # Hlt decreports decoders
        from DAQSys.Decoders import DecoderDB
        from Configurables import LoKi__HDRFilter, AddToProcStatus
        hltStages = ('Hlt1',) if self.getProp('OnlineMode') else ('Hlt1', 'Hlt2')
        hltDecoders = []
        hltErrorFilters = []
        hltFilters = []
        for stage in hltStages:
            decoder = DecoderDB["HltDecReportsDecoder/%sDecReportsDecoder" % stage].setup()
            hltDecoders += [decoder]            # decode DecReports
            # identifies events that are not of type ErrorEvent
            errorFilterCode = "HLT_PASS_RE('%s(?!ErrorEvent).*Decision')" % stage
            hltErrorFilter = LoKi__HDRFilter('%sErrorFilter' % stage, Code = errorFilterCode, Location = decoder.OutputHltDecReportsLocation)
            hltErrorFilters += [decoder, hltErrorFilter] # and apply filter
            
            filterCode = self.getProp(stage + "FilterCode")
            if filterCode:
                hltFilter = LoKi__HDRFilter('%sFilter' % stage, Code = filterCode, Location = decoder.OutputHltDecReportsLocation)
                hltFilters += [decoder, hltFilter]

        # Do not process events flagged as error in Hlt, but still write procstatus
        if vetoHltErrorEvents:
            """
            By Patrick Koppenburg, 16/6/2011
            """
            # Make a sequence that selects HltErrorEvents
            hltErrorFilterSeq = GaudiSequencer("HltErrorFilterSeq")
            if handleLumi: hltErrorFilterSeq.Members = [ physFilter ]       # protect against lumi (that doesn't have decreports)
            hltErrorFilterSeq.Members += hltErrorFilters

            # Sequence to be executed if HltErrorFilter is failing to set ProcStatus
            hltErrorSeq = GaudiSequencer("HltErrorSeq", ModeOR = True, ShortCircuit = True) # anti-logic
            addToProc = AddToProcStatus("HltErrorProc", Reason = "HltError", Subsystem = "Hlt") # write a procstatus
            hltErrorSeq.Members += [hltErrorFilterSeq, addToProc]      # only run if hltErrorFilterSeq fails
            brunelSeq.Members   += [hltErrorSeq]                       # add this sequece to Brunel _before_ physseq
            physicsSeq.Members  += [hltErrorFilterSeq]                 # take good events in physics seq

        # Filter events based on HLT decisions if filters were specified
        if hltFilters:
            hltFilterSeq = GaudiSequencer("HltFilterSeq")
            hltFilterSeq.Members = hltFilters
            physicsSeq.Members += [hltFilterSeq]

        # Convert Calo ReadoutStatus to ProcStatus
        caloBanks=GaudiSequencer("CaloBanksHandler")
        caloDetectors = [det for det in ['Spd','Prs','Ecal','Hcal'] if det in self.getProp("Detectors")]
        CaloDigitConf(ReadoutStatusConvert=True,Sequence=caloBanks,Detectors=caloDetectors)
        physicsSeq.Members += [caloBanks]
        
        # Decode L0 (and HLT if not already done)
        trgSeq = GaudiSequencer("DecodeTriggerSeq")
        l0TrgSeq = GaudiSequencer("L0TriggerSeq")
        if self.getProp( "DataType" ) not in [ "2008", "2009" ]:
            trgSeq.Members += hltDecoders
        trgSeq.Members += [ l0TrgSeq ]
        physicsSeq.Members += [ trgSeq ]
        L0Conf().L0Sequencer = l0TrgSeq
        if self.getProp("RecL0Only"):
            # Setup L0 filtering if requested, runs L0 before Reco
            L0Conf().FilterL0FromRaw = True
            self.setOtherProps( L0Conf(), ["DataType"] )
        else:
            L0Conf().DecodeL0DU = True

        if not self.isPropertySet("MainSequence"):
            if withMC:
                mainSeq = self.DefaultMCSequence
            else:
                mainSeq = self.DefaultSequence
            self.MainSequence = mainSeq
        physicsSeq.Members += self.getProp("MainSequence")
        from Configurables import ProcessPhase
        outputPhase = ProcessPhase("Output")
        brunelSeq.Members  += [ physicsSeq ]
        brunelSeq.Members  += [ outputPhase ]
DataOnDemandSvc().AlgMap["Raw/Muon/Coords"] = "MuonRec"
DataOnDemandSvc().AlgMap["DAQ/ODIN"] = "createODIN"
DataOnDemandSvc().AlgMap[
    "Raw/Rich/Digits"] = "Rich::DAQ::RawBufferToRichDigitsAlg/RichRawEventToDigits"

RawBankToSTClusterAlg("createITClusters").DetType = "IT"
RawBankToSTLiteClusterAlg("createITLiteClusters").DetType = "IT"

RawBankToSTClusterAlg("createUTClusters").DetType = "UT"
RawBankToSTLiteClusterAlg("createUTLiteClusters").DetType = "UT"

#Moved to ST/STTools/python/STTools/STOfflineConf, as with TT and IT
#from Configurables import STOfflinePosition
#UT = STOfflinePosition('ToolSvc.UTClusterPosition')
#UT.DetType = "UT"

DecodeVeloRawBuffer("createVeloClusters").DecodeToVeloClusters = True
DecodeVeloRawBuffer("createVeloClusters").DecodeToVeloLiteClusters = False
DecodeVeloRawBuffer("createVeloLiteClusters").DecodeToVeloClusters = False
DecodeVeloRawBuffer("createVeloLiteClusters").DecodeToVeloLiteClusters = True

Rich__DAQ__RawBufferToRichDigitsAlg(
    "RichRawEventToDigits").DecodeBufferOnly = False
# Calorimeters
from Configurables import CaloDigitConf
CaloDigitConf(EnableDigitsOnDemand=True).applyConf()

importOptions("$L0DUOPTS/L0OnDemand.opts")

print __doc__
Esempio n. 5
0
    def applyConf(self):
        _log.info('Apply CaloProcessor configuration for %s and %s',
                  self.getProp('RecList'), self.getProp('PIDList'))

        self.printConf()

        knownMasks = ['3x3', '2x2', 'SwissCross']

        for tag in self.getProp('ClusterEnergyMasks'):
            if tag not in knownMasks:
                raise AttributeError, 'ClusterEnergyMasks contains unknown tag' + tag + ' -should be in' + knownMasks
        for tag in self.getProp('ClusterPositionMasks'):
            if tag not in knownMasks:
                raise AttributeError, 'PositionEnergyMasks contains unknown tag ' + tag + ' -should be in' + knownMasks

        from Configurables import (
            GaudiSequencer, ChargedProtoParticleAddEcalInfo,
            ChargedProtoParticleAddBremInfo, ChargedProtoParticleAddHcalInfo,
            ChargedProtoParticleAddPrsInfo, ChargedProtoParticleAddSpdInfo,
            ChargedProtoParticleMaker, ChargedProtoCombineDLLsAlg)

        fullSeq = []

        if self.getName() == 'CaloProcessor' and (self.getProp('Context') == ''
                                                  or self.getProp('Context')
                                                  == 'CaloProcessor'):
            self.setProp(
                'Context', 'Offline'
            )  # default is Offline is neither context nor name is specified

        # prepare the NoSpdPrs configuration
        if self.getProp('NoSpdPrs'):
            self.setProp('UseSpd', False)
            self.setProp('UsePrs', False)
            self.setProp('UseSpdE', False)
            self.setProp('UsePrsE', False)
            # configure the public getter tool
            from Configurables import ToolSvc, CaloGetterTool
            tsvc = ToolSvc()
            tsvc.addTool(CaloGetterTool, name="CaloGetter")
            tsvc.CaloGetter.DetectorMask = 12

        # overwrite Reco & PID onDemand
        dod = self.getProp('EnableOnDemand')
        pdod = self.getProp('ProtoOnDemand')

        if dod:
            pdod = dod
        self.setProp('EnableRecoOnDemand', dod)

        ## define the calo sequence
        caloSeq = []

        doReco = self.getProp('CaloReco')
        doPIDs = self.getProp('CaloPIDs')
        skipNeutrals = self.getProp('SkipNeutrals')
        skipCharged = self.getProp('SkipCharged')
        context = self.getProp('Context')

        # CaloReco sequence
        recoSeq = getAlgo(GaudiSequencer, "CaloRecoFor" + self.getName(),
                          context)
        recoSeq.Members[:] = []
        recList = self.getProp('RecList')

        # configure all components by default (DoD)
        forceOnDemand = self.getProp('ForceOnDemand')
        if forceOnDemand:
            self.setProp('EnableOnDemand', 'True')
            self.setProp('EnableRecoOnDemand', 'True')
            dig = self.digits()
            clu = self.clusters()
            pho = self.photons()
            mer = self.mergedPi0s()
            ele = self.electrons()

        #  add only the requested components to the sequence
        if 'Digits' in recList:
            addAlgs(recoSeq, self.digits())
            CaloDigitConf().printConf()
        if 'Clusters' in recList:
            addAlgs(recoSeq, self.clusters())
            if 'Digits' not in recList:
                CaloDigitConf().printConf()

        if not skipNeutrals:
            if 'Photons' in recList: addAlgs(recoSeq, self.photons())
            if 'MergedPi0s' in recList or 'SplitPhotons' in recList:
                addAlgs(recoSeq, self.mergedPi0s())
        if not skipCharged:
            if 'Electrons' in recList: addAlgs(recoSeq, self.electrons())

        # CaloPIDs sequence
        #        pidSeq = getAlgo( GaudiSequencer , "CaloPIDsSeq" , context )
        #        addAlgs ( pidSeq , self.caloPIDs  () )

        pidSeq = self.caloPIDs()

        # update CaloSequence
        if doReco:
            addAlgs(caloSeq, recoSeq)
        if doPIDs:
            addAlgs(caloSeq, pidSeq)

        ## propagate the global properties
        setTheProperty(caloSeq, 'Context', self.getProp('Context'))
        setTheProperty(caloSeq, 'MeasureTime', self.getProp('MeasureTime'))
        if self.isPropertySet("OutputLevel"):
            setTheProperty(caloSeq, 'OutputLevel', self.getProp('OutputLevel'))

        ######## ProtoParticle update ##########
        protoSeq = []
        cProtoSeq = []
        nProtoSeq = []
        #  ProtoParticle locations
        nloc = self.getProp('NeutralProtoLocation')
        cloc = self.getProp('ChargedProtoLocation')
        # try automatic location if not explicit for HLT's sequence
        if hltContext(self.getProp('Context')):
            if nloc == '':
                if nloc.find('/') == -1:
                    nloc = context + '/ProtoP/Neutrals'
                else:
                    nloc = context.replace('/', '/ProtoP/', 1) + '/Neutrals'
            if cloc == '':
                if cloc.find('/') == -1:
                    cloc = context + '/ProtoP/Charged'
                else:
                    cloc = context.replace('/', '/ProtoP/', 1) + '/Charged'

        # Confuse Configurable
        if cloc != '':
            if cloc.find('/Event/') != 0:
                cloc = '/Event/' + cloc

        if nloc != '':
            if nloc.find('/Event/') != 0:
                nloc = '/Event/' + nloc

        # ChargedProtoParticle
        if not self.getProp('SkipCharged'):
            suffix = "For" + self.getName()
            ecal = getAlgo(ChargedProtoParticleAddEcalInfo,
                           "ChargedProtoPAddEcal" + suffix, context)
            brem = getAlgo(ChargedProtoParticleAddBremInfo,
                           "ChargedProtoPAddBrem" + suffix, context)
            hcal = getAlgo(ChargedProtoParticleAddHcalInfo,
                           "ChargedProtoPAddHcal" + suffix, context)
            if not self.getProp('NoSpdPrs'):
                prs = getAlgo(ChargedProtoParticleAddPrsInfo,
                              "ChargedProtoPAddPrs" + suffix, context)
                spd = getAlgo(ChargedProtoParticleAddSpdInfo,
                              "ChargedProtoPAddSpd" + suffix, context)
            comb = getAlgo(ChargedProtoCombineDLLsAlg,
                           "ChargedProtoPCombineDLLs" + suffix, context)

            # ChargedProtoP Maker on demand (not in any sequencer)  ####
            maker = getAlgo(ChargedProtoParticleMaker, "ChargedProtoMaker",
                            context, cloc, pdod)
            # protoPMaker settings (from GlobalRecoConf)
            from Configurables import DelegatingTrackSelector, GaudiSequencer
            ## ppConf = GlobalRecoConf('DummyConf',RecoSequencer=GaudiSequencer('DummySeq'))
            ##ttypes = ppConf.getProp('TrackTypes')
            ##tcuts  = ppConf.getProp('TrackCuts')

            ttypes = self.getProp('TrackTypes')
            tcuts = self.getProp('TrackCuts')

            maker.addTool(DelegatingTrackSelector, name="TrackSelector")
            maker.TrackSelector.TrackTypes = ttypes
            from Configurables import TrackSelector
            for type in ttypes:
                maker.TrackSelector.addTool(TrackSelector, name=type)
                ts = getattr(maker.TrackSelector, type)
                ts.TrackTypes = [type]
                if type in tcuts:
                    for name, cut in tcuts[type].iteritems():
                        ts.setProp("Min" + name, cut[0])
                        ts.setProp("Max" + name, cut[1])
            #########################################
            if cloc != '':
                maker.Output = cloc

        ## confuse configurable on purpose
            _locs = self.getProp('TrackLocations')
            _elocs = []
            for l in _locs:
                if l.find('/Event/') != 0:
                    l = '/Event/' + l
                _elocs.append(l)

            if not hltContext(self.getProp('Context')) and _elocs:
                maker.Inputs = _elocs

            # location
            if cloc != '':
                ecal.ProtoParticleLocation = cloc
                brem.ProtoParticleLocation = cloc
                hcal.ProtoParticleLocation = cloc
                if not self.getProp('NoSpdPrs'):
                    prs.ProtoParticleLocation = cloc
                    spd.ProtoParticleLocation = cloc
                comb.ProtoParticleLocation = cloc
            # Fill the sequence
            cpSeq = getAlgo(GaudiSequencer,
                            self.getName() + "ChargedProtoPCaloUpdateSeq",
                            context)
            cpSeq.Members = [ecal, brem, hcal]
            if not self.getProp('NoSpdPrs'):
                cpSeq.Members += [prs, spd]
            cpSeq.Members += [comb]
            addAlgs(protoSeq, cpSeq)
            addAlgs(cProtoSeq, cpSeq.Members)

        # NeutralProtoParticleProtoP components
        if not self.getProp('SkipNeutrals'):
            from Configurables import NeutralProtoPAlg
            suffix = "For" + self.getName()
            neutral = getAlgo(NeutralProtoPAlg, "NeutralProtoPMaker" + suffix,
                              context)
            # location
            if nloc != '':
                neutral.ProtoParticleLocation = nloc
            # fill the sequence
            addAlgs(protoSeq, neutral)
            addAlgs(nProtoSeq, neutral)

        ## propagate the global properties
        setTheProperty(protoSeq, 'Context', self.getProp('Context'))
        setTheProperty(protoSeq, 'MeasureTime', self.getProp('MeasureTime'))
        if self.isPropertySet("OutputLevel"):
            setTheProperty(protoSeq, 'OutputLevel',
                           self.getProp('OutputLevel'))

        setTheProperty(nProtoSeq, 'Context', self.getProp('Context'))
        setTheProperty(nProtoSeq, 'MeasureTime', self.getProp('MeasureTime'))
        if self.isPropertySet("OutputLevel"):
            setTheProperty(nProtoSeq, 'OutputLevel',
                           self.getProp('OutputLevel'))

        setTheProperty(cProtoSeq, 'Context', self.getProp('Context'))
        setTheProperty(cProtoSeq, 'MeasureTime', self.getProp('MeasureTime'))
        if self.isPropertySet("OutputLevel"):
            setTheProperty(cProtoSeq, 'OutputLevel',
                           self.getProp('OutputLevel'))

        # Full sequence
        addAlgs(fullSeq, caloSeq)
        addAlgs(fullSeq, protoSeq)

        ## define the sequencers
        if self.isPropertySet('Sequence'):
            main = self.getProp('Sequence')
            main.Members[:] = []
            addAlgs(main, fullSeq)
            _log.info('Configure full sequence %s with ' % main.name())
            _log.info('    Reco : %s ' % self.getProp('RecList'))
            _log.info('    PIDs : %s ' % self.getProp('PIDList'))
            _log.info('    and ProtoParticle update')
            if self.getProp('Verbose'):
                _log.info(prntCmp(main))

        if self.isPropertySet('CaloSequencer'):
            calo = self.getProp('CaloSequencer')
            calo.Members[:] = []
            addAlgs(calo, caloSeq)
            _log.info('Configure caloSequencer  : %s ' % calo.name())
            if self.getProp('Verbose'):
                _log.info(prntCmp(calo))

        if self.isPropertySet('ProtoSequencer'):
            proto = self.getProp('ProtoSequencer')
            proto.Members[:] = []
            addAlgs(proto, protoSeq)
            _log.info('Configure protoSequencer  : %s ' % proto.name())
            if self.getProp('Verbose'):
                _log.info(prntCmp(proto))

        if self.isPropertySet('ChargedProtoSequencer'):
            cproto = self.getProp('ChargedProtoSequencer')
            cproto.Members[:] = []
            addAlgs(cproto, cProtoSeq)
            _log.info('Configure chargedProtoSequencer  : %s ' % cproto.name())
            if self.getProp('Verbose'):
                _log.info(prntCmp(cproto))

        if self.isPropertySet('NeutralProtoSequencer'):
            nproto = self.getProp('NeutralProtoSequencer')
            nproto.Members[:] = []
            addAlgs(nproto, nProtoSeq)
            _log.info('Configure neutralProtoSequencer  : %s ' % nproto.name())
            if self.getProp('Verbose'):
                _log.info(prntCmp(nproto))

        if self.getProp('EnableOnDemand'):
            _log.info("CaloProcessor onDemand enabled")
            if self.getProp('Verbose'):
                _log.info(printOnDemand())
Esempio n. 6
0
    def applyConf(self):
        """
        Calorimeter Reconstruction Configuration
        """

        self.printConf()

        _log.info('Apply CaloRecoConf configuration for %s ',
                  self.getProp('RecList'))

        recList = self.getProp('RecList')
        skipNeutrals = self.getProp('SkipNeutrals')
        skipCharged = self.getProp('SkipCharged')
        forceOnDemand = self.getProp('ForceOnDemand')

        seq = []

        # configure all components for DoD
        if forceOnDemand:
            _log.info('Force Data-On-Demand for all components')
            self.setProp('EnableRecoOnDemand', 'True')
            self.digits()
            self.clusters()
            self.photons()
            self.mergedPi0s()
            self.electrons()

        if self.getProp('NoSpdPrs'):
            self.setProp('UseSpd', False)
            self.setProp('UsePrs', False)
            self.setProp('UseSpdE', False)
            self.setProp('UsePrsE', False)
            # configure the public getter tool
            from Configurables import ToolSvc, CaloGetterTool
            tsvc = ToolSvc()
            tsvc.addTool(CaloGetterTool, name="CaloGetter")
            tsvc.CaloGetter.DetectorMask = 12

        # add only the requested components to the sequence
        if 'Digits' in recList:
            addAlgs(seq, self.digits())
            CaloDigitConf().printConf()
        if 'Clusters' in recList:
            addAlgs(seq, self.clusters())
            if 'Digits' not in recList:
                CaloDigitConf().printConf()
        if not skipNeutrals:
            if 'Photons' in recList: addAlgs(seq, self.photons())
            if 'MergedPi0s' in recList or 'SplitPhotons' in recList:
                addAlgs(seq, self.mergedPi0s())
        if not skipCharged:
            if 'Electrons' in recList: addAlgs(seq, self.electrons())

        setTheProperty(seq, 'Context', self.getProp('Context'))
        setTheProperty(seq, 'MeasureTime', self.getProp('MeasureTime'))
        if self.isPropertySet("OutputLevel"):
            setTheProperty(seq, 'OutputLevel', self.getProp('OutputLevel'))

        if self.isPropertySet('Sequence'):
            main = self.getProp('Sequence')
            addAlgs(main, seq)
            _log.info('Configure main Calo Reco Sequence  : %s ' % main.name())
            if self.getProp('Verbose'):
                _log.info(prntCmp(main))
        else:
            _log.info('Configure Calorimeter Reco blocks ')
            if self.getProp('Verbose'):
                _log.info(prntCmp(seq))

        if self.getProp('EnableRecoOnDemand'):
            _log.info("CaloReco onDemand enabled")
            if self.getProp('Verbose'):
                _log.info(printOnDemand())