CMS 3D CMS Logo

L1TCaloLayer1.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: L1Trigger/L1TCaloLayer1
4 // Class: L1TCaloLayer1
5 //
13 //
14 // Original Author: Sridhara Rao Dasu
15 // Created: Thu, 08 Oct 2015 09:20:16 GMT
16 //
17 //
18 
19 // system include files
20 #include <memory>
21 
22 // user include files
25 
28 
30 
33 
34 #include "L1Trigger/L1TCaloLayer1/src/UCTLayer1.hh"
35 #include "L1Trigger/L1TCaloLayer1/src/UCTCrate.hh"
36 #include "L1Trigger/L1TCaloLayer1/src/UCTCard.hh"
37 #include "L1Trigger/L1TCaloLayer1/src/UCTRegion.hh"
38 #include "L1Trigger/L1TCaloLayer1/src/UCTTower.hh"
39 
40 #include "L1Trigger/L1TCaloLayer1/src/UCTGeometry.hh"
41 #include "L1Trigger/L1TCaloLayer1/src/UCTLogging.hh"
42 
46 
48 
49 #include "L1Trigger/L1TCaloLayer1/src/L1TCaloLayer1FetchLUTs.hh"
50 
51 using namespace l1t;
52 using namespace l1tcalo;
53 
54 //
55 // class declaration
56 //
57 
59 public:
60  explicit L1TCaloLayer1(const edm::ParameterSet&);
61 
62  static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
63 
64 private:
65  void produce(edm::Event&, const edm::EventSetup&) override;
66 
67  void beginRun(edm::Run const&, edm::EventSetup const&) override;
68 
69  //virtual void endRun(edm::Run const&, edm::EventSetup const&) override;
70  //virtual void beginLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&) override;
71  //virtual void endLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&) override;
72 
73  // ----------member data ---------------------------
74 
79 
80  std::vector<std::array<std::array<std::array<uint32_t, nEtBins>, nCalSideBins>, nCalEtaBins> > ecalLUT;
81  std::vector<std::array<std::array<std::array<uint32_t, nEtBins>, nCalSideBins>, nCalEtaBins> > hcalLUT;
82  std::vector<std::array<std::array<uint32_t, nEtBins>, nHfEtaBins> > hfLUT;
83 
84  std::vector<unsigned int> ePhiMap;
85  std::vector<unsigned int> hPhiMap;
86  std::vector<unsigned int> hfPhiMap;
87 
88  std::vector<UCTTower*> twrList;
89 
90  bool useLSB;
91  bool useCalib;
92  bool useECALLUT;
93  bool useHCALLUT;
94  bool useHFLUT;
95  bool verbose;
98  int fwVersion;
99 
100  std::unique_ptr<UCTLayer1> layer1;
101 };
102 
103 //
104 // constants, enums and typedefs
105 //
106 
107 //
108 // static data member definitions
109 //
110 
111 //
112 // constructors and destructor
113 //
115  : ecalTPSource(consumes<EcalTrigPrimDigiCollection>(iConfig.getParameter<edm::InputTag>("ecalToken"))),
116  hcalTPSource(consumes<HcalTrigPrimDigiCollection>(iConfig.getParameter<edm::InputTag>("hcalToken"))),
117  towerPutToken{produces<CaloTowerBxCollection>()},
118  regionPutToken{produces<L1CaloRegionCollection>()},
119  ePhiMap(72 * 2, 0),
120  hPhiMap(72 * 2, 0),
121  hfPhiMap(72 * 2, 0),
122  useLSB(iConfig.getParameter<bool>("useLSB")),
123  useCalib(iConfig.getParameter<bool>("useCalib")),
124  useECALLUT(iConfig.getParameter<bool>("useECALLUT")),
125  useHCALLUT(iConfig.getParameter<bool>("useHCALLUT")),
126  useHFLUT(iConfig.getParameter<bool>("useHFLUT")),
127  verbose(iConfig.getParameter<bool>("verbose")),
128  unpackHcalMask(iConfig.getParameter<bool>("unpackHcalMask")),
129  unpackEcalMask(iConfig.getParameter<bool>("unpackEcalMask")),
130  fwVersion(iConfig.getParameter<int>("firmwareVersion")) {
131  // See UCTLayer1.hh for firmware version definitions
132  layer1 = std::make_unique<UCTLayer1>(fwVersion);
133 
134  vector<UCTCrate*> crates = layer1->getCrates();
135  for (uint32_t crt = 0; crt < crates.size(); crt++) {
136  vector<UCTCard*> cards = crates[crt]->getCards();
137  for (uint32_t crd = 0; crd < cards.size(); crd++) {
138  vector<UCTRegion*> regions = cards[crd]->getRegions();
139  for (uint32_t rgn = 0; rgn < regions.size(); rgn++) {
140  vector<UCTTower*> towers = regions[rgn]->getTowers();
141  for (uint32_t twr = 0; twr < towers.size(); twr++) {
142  twrList.push_back(towers[twr]);
143  }
144  }
145  }
146  }
147 
148  // This sort corresponds to the sort condition on
149  // the output CaloTowerBxCollection
150  std::sort(twrList.begin(), twrList.end(), [](UCTTower* a, UCTTower* b) {
151  return CaloTools::caloTowerHash(a->caloEta(), a->caloPhi()) < CaloTools::caloTowerHash(b->caloEta(), b->caloPhi());
152  });
153 }
154 
155 //
156 // member functions
157 //
158 
159 // ------------ method called to produce the data ------------
161  using namespace edm;
162 
164  iEvent.getByToken(ecalTPSource, ecalTPs);
166  iEvent.getByToken(hcalTPSource, hcalTPs);
167 
168  CaloTowerBxCollection towersColl;
169  L1CaloRegionCollection rgnCollection;
170 
171  uint32_t expectedTotalET = 0;
172  if (!layer1->clearEvent()) {
173  LOG_ERROR << "UCT: Failed to clear event" << std::endl;
174  return;
175  }
176 
177  for (const auto& ecalTp : *ecalTPs) {
178  if (unpackEcalMask && ((ecalTp.sample(0).raw() >> 13) & 0x1))
179  continue;
180  int caloEta = ecalTp.id().ieta();
181  int caloPhi = ecalTp.id().iphi();
182  int et = ecalTp.compressedEt();
183  bool fgVeto = ecalTp.fineGrain();
184  UCTTowerIndex t = UCTTowerIndex(caloEta, caloPhi);
185  if (!layer1->setECALData(t, fgVeto, et)) {
186  LOG_ERROR << "UCT: Failed loading an ECAL tower" << std::endl;
187  return;
188  }
189  expectedTotalET += et;
190  }
191 
192  if (hcalTPs.isValid()) {
193  for (const auto& hcalTp : *hcalTPs) {
194  if (unpackHcalMask && ((hcalTp.sample(0).raw() >> 13) & 0x1))
195  continue;
196  int caloEta = hcalTp.id().ieta();
197  uint32_t absCaloEta = std::abs(caloEta);
198  // Tower 29 is not used by Layer-1
199  if (absCaloEta == 29) {
200  continue;
201  }
202  // Prevent usage of HF TPs with Layer-1 emulator if HCAL TPs are old style
203  else if (hcalTp.id().version() == 0 && absCaloEta > 29) {
204  continue;
205  } else if (absCaloEta <= 41) {
206  int caloPhi = hcalTp.id().iphi();
207  int et = hcalTp.SOI_compressedEt();
208  bool fg = hcalTp.t0().fineGrain(0);
209  bool fg2 = hcalTp.t0().fineGrain(1);
210  if (caloPhi <= 72) {
211  UCTTowerIndex t = UCTTowerIndex(caloEta, caloPhi);
212  uint32_t featureBits = 0;
213  if (fg)
214  featureBits |= 0b01;
215  // fg2 should only be set for HF
216  if (absCaloEta > 29 && fg2)
217  featureBits |= 0b10;
218  if (!layer1->setHCALData(t, featureBits, et)) {
219  LOG_ERROR << "caloEta = " << caloEta << "; caloPhi =" << caloPhi << std::endl;
220  LOG_ERROR << "UCT: Failed loading an HCAL tower" << std::endl;
221  return;
222  }
223  expectedTotalET += et;
224  } else {
225  LOG_ERROR << "Illegal Tower: caloEta = " << caloEta << "; caloPhi =" << caloPhi << "; et = " << et
226  << std::endl;
227  }
228  } else {
229  LOG_ERROR << "Illegal Tower: caloEta = " << caloEta << std::endl;
230  }
231  }
232  }
233 
234  //Process
235  if (!layer1->process()) {
236  LOG_ERROR << "UCT: Failed to process layer 1" << std::endl;
237  }
238 
239  int theBX = 0; // Currently we only read and process the "hit" BX only
240 
241  for (uint32_t twr = 0; twr < twrList.size(); twr++) {
242  CaloTower caloTower;
243  caloTower.setHwPt(twrList[twr]->et()); // Bits 0-8 of the 16-bit word per the interface protocol document
244  caloTower.setHwEtRatio(twrList[twr]->er()); // Bits 9-11 of the 16-bit word per the interface protocol document
245  caloTower.setHwQual(twrList[twr]->miscBits()); // Bits 12-15 of the 16-bit word per the interface protocol document
246  caloTower.setHwEta(twrList[twr]->caloEta()); // caloEta = 1-28 and 30-41
247  caloTower.setHwPhi(twrList[twr]->caloPhi()); // caloPhi = 1-72
248  caloTower.setHwEtEm(twrList[twr]->getEcalET()); // This is provided as a courtesy - not available to hardware
249  caloTower.setHwEtHad(twrList[twr]->getHcalET()); // This is provided as a courtesy - not available to hardware
250  towersColl.push_back(theBX, caloTower);
251  }
252 
253  iEvent.emplace(towerPutToken, std::move(towersColl));
254 
255  UCTGeometry g;
256  vector<UCTCrate*> crates = layer1->getCrates();
257  for (uint32_t crt = 0; crt < crates.size(); crt++) {
258  vector<UCTCard*> cards = crates[crt]->getCards();
259  for (uint32_t crd = 0; crd < cards.size(); crd++) {
260  vector<UCTRegion*> regions = cards[crd]->getRegions();
261  for (uint32_t rgn = 0; rgn < regions.size(); rgn++) {
262  uint32_t rawData = regions[rgn]->rawData();
263  uint32_t regionData = rawData & 0x0000FFFF;
264  uint32_t crate = regions[rgn]->getCrate();
265  uint32_t card = regions[rgn]->getCard();
266  uint32_t region = regions[rgn]->getRegion();
267  bool negativeEta = regions[rgn]->isNegativeEta();
268  uint32_t rPhi = g.getUCTRegionPhiIndex(crate, card);
269  if (region < NRegionsInCard) { // We only store the Barrel and Endcap - HF has changed in the upgrade
270  uint32_t rEta =
271  10 -
272  region; // UCT region is 0-6 for B/E but GCT eta goes 0-21, 0-3 -HF, 4-10 -B/E, 11-17 +B/E, 18-21 +HF
273  if (!negativeEta)
274  rEta = 11 + region; // Positive eta portion is offset by 11
275  rgnCollection.push_back(L1CaloRegion((uint16_t)regionData, (unsigned)rEta, (unsigned)rPhi, (int16_t)0));
276  }
277  }
278  }
279  }
280  iEvent.emplace(regionPutToken, std::move(rgnCollection));
281 }
282 
283 // ------------ method called when starting to processes a run ------------
284 void L1TCaloLayer1::beginRun(const edm::Run& iRun, const edm::EventSetup& iSetup) {
285  if (!L1TCaloLayer1FetchLUTs(iSetup,
286  ecalLUT,
287  hcalLUT,
288  hfLUT,
289  ePhiMap,
290  hPhiMap,
291  hfPhiMap,
292  useLSB,
293  useCalib,
294  useECALLUT,
295  useHCALLUT,
296  useHFLUT,
297  fwVersion)) {
298  LOG_ERROR << "L1TCaloLayer1::beginRun: failed to fetch LUTS - using unity" << std::endl;
299  std::array<std::array<std::array<uint32_t, nEtBins>, nCalSideBins>, nCalEtaBins> eCalLayer1EtaSideEtArray;
300  std::array<std::array<std::array<uint32_t, nEtBins>, nCalSideBins>, nCalEtaBins> hCalLayer1EtaSideEtArray;
301  std::array<std::array<uint32_t, nEtBins>, nHfEtaBins> hfLayer1EtaEtArray;
302  ecalLUT.push_back(eCalLayer1EtaSideEtArray);
303  hcalLUT.push_back(hCalLayer1EtaSideEtArray);
304  hfLUT.push_back(hfLayer1EtaEtArray);
305  }
306  for (uint32_t twr = 0; twr < twrList.size(); twr++) {
307  // Map goes minus 1 .. 72 plus 1 .. 72 -> 0 .. 143
308  int iphi = twrList[twr]->caloPhi();
309  int ieta = twrList[twr]->caloEta();
310  if (ieta < 0) {
311  iphi -= 1;
312  } else {
313  iphi += 71;
314  }
315  twrList[twr]->setECALLUT(&ecalLUT[ePhiMap[iphi]]);
316  twrList[twr]->setHCALLUT(&hcalLUT[hPhiMap[iphi]]);
317  twrList[twr]->setHFLUT(&hfLUT[hfPhiMap[iphi]]);
318  }
319 }
320 
321 // ------------ method called when ending the processing of a run ------------
322 /*
323  void
324  L1TCaloLayer1::endRun(edm::Run const&, edm::EventSetup const&)
325  {
326  }
327 */
328 
329 // ------------ method called when starting to processes a luminosity block ------------
330 /*
331  void
332  L1TCaloLayer1::beginLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&)
333  {
334  }
335 */
336 
337 // ------------ method called when ending the processing of a luminosity block ------------
338 /*
339  void
340  L1TCaloLayer1::endLuminosityBlock(edm::LuminosityBlock const&, edm::EventSetup const&)
341  {
342  }
343 */
344 
345 // ------------ method fills 'descriptions' with the allowed parameters for the module ------------
347  //The following says we do not know what parameters are allowed so do no validation
348  // Please change this to state exactly what you do use, even if it is no parameters
350  desc.setUnknown();
351  descriptions.addDefault(desc);
352 }
353 
354 //define this as a plug-in
356 /* vim: set ts=8 sw=2 tw=0 et :*/
HLT_FULL_cff.towers
towers
Definition: HLT_FULL_cff.py:36358
amcDumpToRaw_cfi.fwVersion
fwVersion
Definition: amcDumpToRaw_cfi.py:11
L1TCaloLayer1::hfPhiMap
std::vector< unsigned int > hfPhiMap
Definition: L1TCaloLayer1.cc:86
CaloTools.h
L1TCaloLayer1::useECALLUT
bool useECALLUT
Definition: L1TCaloLayer1.cc:92
L1TCaloLayer1::hcalTPSource
edm::EDGetTokenT< HcalTrigPrimDigiCollection > hcalTPSource
Definition: L1TCaloLayer1.cc:76
simCaloStage2Layer1Digis_cfi.useHCALLUT
useHCALLUT
Definition: simCaloStage2Layer1Digis_cfi.py:15
L1CaloRegion
A calorimeter trigger region (sum of 4x4 trigger towers)
Definition: L1CaloRegion.h:21
L1TCaloLayer1::unpackHcalMask
bool unpackHcalMask
Definition: L1TCaloLayer1.cc:96
L1TCaloLayer1::fwVersion
int fwVersion
Definition: L1TCaloLayer1.cc:98
L1TCaloLayer1::ecalLUT
std::vector< std::array< std::array< std::array< uint32_t, nEtBins >, nCalSideBins >, nCalEtaBins > > ecalLUT
Definition: L1TCaloLayer1.cc:80
edm::Run
Definition: Run.h:45
edm::EDGetTokenT
Definition: EDGetToken.h:33
edm
HLT enums.
Definition: AlignableModifier.h:19
edm::EDPutTokenT< CaloTowerBxCollection >
HLT_FULL_cff.InputTag
InputTag
Definition: HLT_FULL_cff.py:89281
L1TCaloLayer1::unpackEcalMask
bool unpackEcalMask
Definition: L1TCaloLayer1.cc:97
edm::ParameterSetDescription
Definition: ParameterSetDescription.h:52
l1tstage2_dqm_sourceclient-live_cfg.rawData
rawData
Definition: l1tstage2_dqm_sourceclient-live_cfg.py:162
L1TCaloLayer1::regionPutToken
edm::EDPutTokenT< L1CaloRegionCollection > regionPutToken
Definition: L1TCaloLayer1.cc:78
EDProducer.h
edm::SortedCollection
Definition: SortedCollection.h:49
L1TCaloLayer1::verbose
bool verbose
Definition: L1TCaloLayer1.cc:95
l1t::CaloTower::setHwEtRatio
void setHwEtRatio(int ratio)
Definition: CaloTower.cc:31
L1TStage2Emulator_cff.unpackEcalMask
unpackEcalMask
Definition: L1TStage2Emulator_cff.py:13
edm::Handle
Definition: AssociativeIterator.h:50
l1t::CaloTower
Definition: CaloTower.h:12
L1TCaloLayer1::produce
void produce(edm::Event &, const edm::EventSetup &) override
Definition: L1TCaloLayer1.cc:160
L1TCaloLayer1::useHCALLUT
bool useHCALLUT
Definition: L1TCaloLayer1.cc:93
LEDCalibrationChannels.iphi
iphi
Definition: LEDCalibrationChannels.py:64
BXVector
Definition: BXVector.h:15
MakerMacros.h
testProducerWithPsetDescEmpty_cfi.x1
x1
Definition: testProducerWithPsetDescEmpty_cfi.py:33
DEFINE_FWK_MODULE
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
L1TCaloLayer1::useHFLUT
bool useHFLUT
Definition: L1TCaloLayer1.cc:94
L1TCaloLayer1::hfLUT
std::vector< std::array< std::array< uint32_t, nEtBins >, nHfEtaBins > > hfLUT
Definition: L1TCaloLayer1.cc:82
CaloTower.h
l1t::L1Candidate::setHwQual
void setHwQual(int qual)
Definition: L1Candidate.h:31
HcalDigiCollections.h
fillDescriptions
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
EcalDigiCollections.h
L1TCaloLayer1::useCalib
bool useCalib
Definition: L1TCaloLayer1.cc:91
verbose
static constexpr int verbose
Definition: HLTExoticaSubAnalysis.cc:25
L1TCaloLayer1::layer1
std::unique_ptr< UCTLayer1 > layer1
Definition: L1TCaloLayer1.cc:100
l1t::CaloTower::setHwEtEm
void setHwEtEm(int et)
Definition: CaloTower.cc:27
L1TCaloLayer1::useLSB
bool useLSB
Definition: L1TCaloLayer1.cc:90
L1TCaloLayer1::hcalLUT
std::vector< std::array< std::array< std::array< uint32_t, nEtBins >, nCalSideBins >, nCalEtaBins > > hcalLUT
Definition: L1TCaloLayer1.cc:81
b
double b
Definition: hdecay.h:118
edm::ConfigurationDescriptions
Definition: ConfigurationDescriptions.h:28
simCaloStage2Layer1Digis_cfi.useCalib
useCalib
Definition: simCaloStage2Layer1Digis_cfi.py:13
LEDCalibrationChannels.ieta
ieta
Definition: LEDCalibrationChannels.py:63
edm::ParameterSet
Definition: ParameterSet.h:47
a
double a
Definition: hdecay.h:119
Event.h
l1t
delete x;
Definition: CaloConfig.h:22
L1TCaloLayer1::twrList
std::vector< UCTTower * > twrList
Definition: L1TCaloLayer1.cc:88
L1TCaloLayer1FetchLUTs
bool L1TCaloLayer1FetchLUTs(const edm::EventSetup &iSetup, std::vector< std::array< std::array< std::array< uint32_t, nEtBins >, nCalSideBins >, nCalEtaBins > > &eLUT, std::vector< std::array< std::array< std::array< uint32_t, nEtBins >, nCalSideBins >, nCalEtaBins > > &hLUT, std::vector< std::array< std::array< uint32_t, nEtBins >, nHfEtaBins > > &hfLUT, std::vector< unsigned int > &ePhiMap, std::vector< unsigned int > &hPhiMap, std::vector< unsigned int > &hfPhiMap, bool useLSB, bool useCalib, bool useECALLUT, bool useHCALLUT, bool useHFLUT, int fwVersion)
Definition: L1TCaloLayer1FetchLUTs.cc:29
jetUpdater_cfi.sort
sort
Definition: jetUpdater_cfi.py:29
L1TCaloLayer1::hPhiMap
std::vector< unsigned int > hPhiMap
Definition: L1TCaloLayer1.cc:85
HLT_FULL_cff.region
region
Definition: HLT_FULL_cff.py:88267
L1CaloCollections.h
iEvent
int iEvent
Definition: GenABIO.cc:224
edm::stream::EDProducer
Definition: EDProducer.h:38
EgHLTOffHistBins_cfi.et
et
Definition: EgHLTOffHistBins_cfi.py:8
l1t::L1Candidate::setHwPt
void setHwPt(int pt)
Definition: L1Candidate.h:28
l1t::L1Candidate::setHwEta
void setHwEta(int eta)
Definition: L1Candidate.h:29
edm::EventSetup
Definition: EventSetup.h:58
L1TCaloLayer1
Definition: L1TCaloLayer1.cc:58
L1TCaloLayer1::towerPutToken
edm::EDPutTokenT< CaloTowerBxCollection > towerPutToken
Definition: L1TCaloLayer1.cc:77
L1TCaloLayer1::beginRun
void beginRun(edm::Run const &, edm::EventSetup const &) override
Definition: L1TCaloLayer1.cc:284
simCaloStage2Layer1Digis_cfi.useHFLUT
useHFLUT
Definition: simCaloStage2Layer1Digis_cfi.py:16
L1TCaloLayer1::L1TCaloLayer1
L1TCaloLayer1(const edm::ParameterSet &)
Definition: L1TCaloLayer1.cc:114
submitPVResolutionJobs.desc
string desc
Definition: submitPVResolutionJobs.py:251
eostools.move
def move(src, dest)
Definition: eostools.py:511
L1CaloRegionCollection
std::vector< L1CaloRegion > L1CaloRegionCollection
Definition: L1CaloCollections.h:11
Frameworkfwd.h
L1TStage2Emulator_cff.unpackHcalMask
unpackHcalMask
Definition: L1TStage2Emulator_cff.py:14
l1t::L1Candidate::setHwPhi
void setHwPhi(int phi)
Definition: L1Candidate.h:30
AlignmentPI::regions
regions
Definition: AlignmentPayloadInspectorHelper.h:76
L1TCaloLayer1::ePhiMap
std::vector< unsigned int > ePhiMap
Definition: L1TCaloLayer1.cc:84
funct::abs
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
ParameterSet.h
L1TCaloLayer1::fillDescriptions
static void fillDescriptions(edm::ConfigurationDescriptions &descriptions)
Definition: L1TCaloLayer1.cc:346
edm::HandleBase::isValid
bool isValid() const
Definition: HandleBase.h:70
edm::Event
Definition: Event.h:73
submitPVValidationJobs.t
string t
Definition: submitPVValidationJobs.py:644
edm::ConfigurationDescriptions::addDefault
void addDefault(ParameterSetDescription const &psetDescription)
Definition: ConfigurationDescriptions.cc:99
L1TCaloLayer1::ecalTPSource
edm::EDGetTokenT< EcalTrigPrimDigiCollection > ecalTPSource
Definition: L1TCaloLayer1.cc:75
l1t::CaloTower::setHwEtHad
void setHwEtHad(int et)
Definition: CaloTower.cc:29
BXVector::push_back
void push_back(int bx, T object)
LOG_ERROR
#define LOG_ERROR
Definition: CSCDQM_Logger.h:40
simCaloStage2Layer1Digis_cfi.useECALLUT
useECALLUT
Definition: simCaloStage2Layer1Digis_cfi.py:14
g
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e g
Definition: Activities.doc:4
L1CaloRegion.h
simCaloStage2Layer1Digis_cfi.useLSB
useLSB
Definition: simCaloStage2Layer1Digis_cfi.py:12