CMS 3D CMS Logo

EcalTPGStripStatus_PayloadInspector.cc
Go to the documentation of this file.
7 
8 // the data format of the condition to be inspected
10 
11 #include "TH2F.h"
12 #include "TCanvas.h"
13 #include "TStyle.h"
14 #include "TLine.h"
15 #include "TLatex.h"
16 
17 #include <string>
18 #include <array>
19 #include <memory>
20 
21 namespace {
22  enum { NTCC = 108, NTower = 28, NStrip = 5, NXtal = 5 };
23  enum { IX_MIN = 1, IY_MIN = 1, IX_MAX = 100, IY_MAX = 100 }; // endcaps lower and upper bounds on x and y
24 
25  /***********************************************
26  2d plot of ECAL TPGStripStatus of 1 IOV
27  ************************************************/
28  class EcalTPGStripStatusPlot : public cond::payloadInspector::PlotImage<EcalTPGStripStatus> {
29  public:
30  EcalTPGStripStatusPlot() : cond::payloadInspector::PlotImage<EcalTPGStripStatus>("ECAL TPGStripStatus - map ") {
31  setSingleIov(true);
32  }
33 
34  bool fill(const std::vector<std::tuple<cond::Time_t, cond::Hash> >& iovs) override {
35  TH2F* endc_p = new TH2F("EE+", "EE+ TPG Strip Status", IX_MAX, IX_MIN, IX_MAX + 1, IY_MAX, IY_MIN, IY_MAX + 1);
36  TH2F* endc_m = new TH2F("EE-", "EE- TPG Strip Status", IX_MAX, IX_MIN, IX_MAX + 1, IY_MAX, IY_MIN, IY_MAX + 1);
37  int EEstat[2] = {0, 0};
38 
39  std::string mappingFile = "Geometry/EcalMapping/data/EEMap.txt";
40  std::ifstream f(edm::FileInPath(mappingFile).fullPath().c_str());
41  if (!f.good()) {
42  std::cout << "EcalTPGStripStatus File EEMap.txt not found" << std::endl;
43  throw cms::Exception("FileNotFound");
44  }
45 
46  uint32_t rawEE[NTCC][NTower][NStrip][NXtal];
47  int NbrawEE[NTCC][NTower][NStrip];
48  for (int TCC = 0; TCC < NTCC; TCC++)
49  for (int TT = 0; TT < NTower; TT++)
50  for (int ST = 0; ST < NStrip; ST++)
51  NbrawEE[TCC][TT][ST] = 0;
52  while (!f.eof()) {
53  int ix, iy, iz, CL;
54  int dccid, towerid, pseudostrip_in_SC, xtal_in_pseudostrip;
55  int tccid, tower, pseudostrip_in_TCC, pseudostrip_in_TT;
56  f >> ix >> iy >> iz >> CL >> dccid >> towerid >> pseudostrip_in_SC >> xtal_in_pseudostrip >> tccid >> tower >>
57  pseudostrip_in_TCC >> pseudostrip_in_TT;
58  EEDetId detid(ix, iy, iz, EEDetId::XYMODE);
59  uint32_t rawId = detid.denseIndex();
60  if (tccid > NTCC || tower > NTower || pseudostrip_in_TT > NStrip || xtal_in_pseudostrip > NXtal)
61  std::cout << " tccid " << tccid << " tower " << tower << " pseudostrip_in_TT " << pseudostrip_in_TT
62  << " xtal_in_pseudostrip " << xtal_in_pseudostrip << std::endl;
63  else {
64  rawEE[tccid - 1][tower - 1][pseudostrip_in_TT - 1][xtal_in_pseudostrip - 1] = rawId;
65  NbrawEE[tccid - 1][tower - 1][pseudostrip_in_TT - 1]++;
66  }
67  } // read EEMap file
68  f.close();
69  double wei[2] = {0., 0.};
70 
71  auto iov = iovs.front();
72  std::shared_ptr<EcalTPGStripStatus> payload = fetchPayload(std::get<1>(iov));
73  unsigned int run = std::get<0>(iov);
74  if (payload.get()) {
75  const EcalTPGStripStatusMap& stripMap = (*payload).getMap();
76  // std::cout << " tower map size " << stripMap.size() << std::endl;
78  for (itSt = stripMap.begin(); itSt != stripMap.end(); ++itSt) {
79  if (itSt->second > 0) {
80  // let's decode the ID
81  int strip = itSt->first / 8;
82  int pseudostrip = strip & 0x7;
83  strip /= 8;
84  int tt = strip & 0x7F;
85  strip /= 128;
86  int tccid = strip & 0x7F;
87  int NbXtalInStrip = NbrawEE[tccid - 1][tt - 1][pseudostrip - 1];
88  if (NbXtalInStrip != NXtal)
89  std::cout << " Strip TCC " << tccid << " TT " << tt << " ST " << pseudostrip << " Nx Xtals "
90  << NbXtalInStrip << std::endl;
91  // std::cout << " Strip TCC " << tccid << " TT " << tt << " ST " << pseudostrip
92  // << " Nx Xtals " << NbXtalInStrip << std::endl;
93  for (int Xtal = 0; Xtal < NbXtalInStrip; Xtal++) {
94  uint32_t rawId = rawEE[tccid - 1][tt - 1][pseudostrip - 1][Xtal];
95  // std::cout << " rawid " << rawId << std::endl;
97  float x = (float)detid.ix();
98  float y = (float)detid.iy();
99  int iz = detid.zside();
100  if (iz == -1)
101  iz++;
102  if (Xtal == 0)
103  wei[iz] += 1.;
104  if (iz == 0) {
105  endc_m->Fill(x + 0.5, y + 0.5, wei[iz]);
106  EEstat[0]++;
107  } else {
108  endc_p->Fill(x + 0.5, y + 0.5, wei[iz]);
109  EEstat[1]++;
110  }
111  // std::cout << " x " << x << " y " << y << " z " << iz << std::endl;
112  }
113  }
114  }
115  } // payload
116  // std::cout << " nb strip EE- " << wei[0] << " EE+ " << wei[1] << std::endl;
117 
118  gStyle->SetPalette(1);
119  gStyle->SetOptStat(0);
120  const Int_t NRGBs = 5;
121  const Int_t NCont = 255;
122 
123  Double_t stops[NRGBs] = {0.00, 0.34, 0.61, 0.84, 1.00};
124  Double_t red[NRGBs] = {0.00, 0.00, 0.87, 1.00, 0.51};
125  Double_t green[NRGBs] = {0.00, 0.81, 1.00, 0.20, 0.00};
126  Double_t blue[NRGBs] = {0.51, 1.00, 0.12, 0.00, 0.00};
127  TColor::CreateGradientColorTable(NRGBs, stops, red, green, blue, NCont);
128  gStyle->SetNumberContours(NCont);
129  // TCanvas canvas("CC map","CC map", 1600, 450);
130  Double_t w = 1200;
131  Double_t h = 650;
132  TCanvas canvas("c", "c", w, h);
133  // canvas.SetWindowSize(w + (w - canvas.GetWw()), h + (h - canvas.GetWh()));
134 
135  TLatex t1;
136  t1.SetNDC();
137  t1.SetTextAlign(26);
138  t1.SetTextSize(0.05);
139  t1.DrawLatex(0.5, 0.96, Form("Ecal TPGStripStatus, IOV %i", run));
140 
141  float xmi[2] = {0.0, 0.5};
142  float xma[2] = {0.5, 1.0};
143  std::array<std::unique_ptr<TPad>, 2> pad;
144  for (int obj = 0; obj < 2; obj++) {
145  pad[obj] = std::make_unique<TPad>(Form("p_%i", obj), Form("p_%i", obj), xmi[obj], 0.0, xma[obj], 0.94);
146  pad[obj]->Draw();
147  }
148 
149  pad[0]->cd();
150  DrawEE(endc_m, 0., wei[0]);
151  t1.SetTextSize(0.03);
152  t1.DrawLatex(0.15, 0.92, Form("%i crystals", EEstat[0]));
153  pad[1]->cd();
154  DrawEE(endc_p, 0., wei[1]);
155  t1.DrawLatex(0.15, 0.92, Form("%i crystals", EEstat[1]));
156 
157  std::string ImageName(m_imageFileName);
158  canvas.SaveAs(ImageName.c_str());
159  return true;
160  } // fill method
161  };
162 
163  /***************************************************************
164  2d plot of ECAL TPGStripStatus difference between 2 IOVs
165  ****************************************************************/
166  template <cond::payloadInspector::IOVMultiplicity nIOVs, int ntags>
167  class EcalTPGStripStatusDiffBase : public cond::payloadInspector::PlotImage<EcalTPGStripStatus, nIOVs, ntags> {
168  public:
169  EcalTPGStripStatusDiffBase()
170  : cond::payloadInspector::PlotImage<EcalTPGStripStatus, nIOVs, ntags>("ECAL TPGStripStatus difference") {}
171 
172  bool fill() override {
173  TH2F* endc_p = new TH2F("EE+", "EE+ TPG Strip Status", IX_MAX, IX_MIN, IX_MAX + 1, IY_MAX, IY_MIN, IY_MAX + 1);
174  TH2F* endc_m = new TH2F("EE-", "EE- TPG Strip Status", IX_MAX, IX_MIN, IX_MAX + 1, IY_MAX, IY_MIN, IY_MAX + 1);
175  int EEstat[2][2] = {{0, 0}, {0, 0}};
176 
177  std::string mappingFile = "Geometry/EcalMapping/data/EEMap.txt";
178  std::ifstream f(edm::FileInPath(mappingFile).fullPath().c_str());
179  if (!f.good()) {
180  std::cout << "EcalTPGStripStatus File EEMap.txt not found" << std::endl;
181  throw cms::Exception("FileNotFound");
182  }
183 
184  uint32_t rawEE[NTCC][NTower][NStrip][NXtal];
185  int NbrawEE[NTCC][NTower][NStrip];
186  for (int TCC = 0; TCC < NTCC; TCC++)
187  for (int TT = 0; TT < NTower; TT++)
188  for (int ST = 0; ST < NStrip; ST++)
189  NbrawEE[TCC][TT][ST] = 0;
190  while (!f.eof()) {
191  int ix, iy, iz, CL;
192  int dccid, towerid, pseudostrip_in_SC, xtal_in_pseudostrip;
193  int tccid, tower, pseudostrip_in_TCC, pseudostrip_in_TT;
194  f >> ix >> iy >> iz >> CL >> dccid >> towerid >> pseudostrip_in_SC >> xtal_in_pseudostrip >> tccid >> tower >>
195  pseudostrip_in_TCC >> pseudostrip_in_TT;
196  EEDetId detid(ix, iy, iz, EEDetId::XYMODE);
197  uint32_t rawId = detid.denseIndex();
198  if (tccid > NTCC || tower > NTower || pseudostrip_in_TT > NStrip || xtal_in_pseudostrip > NXtal)
199  std::cout << " tccid " << tccid << " tower " << tower << " pseudostrip_in_TT " << pseudostrip_in_TT
200  << " xtal_in_pseudostrip " << xtal_in_pseudostrip << std::endl;
201  else {
202  rawEE[tccid - 1][tower - 1][pseudostrip_in_TT - 1][xtal_in_pseudostrip - 1] = rawId;
203  NbrawEE[tccid - 1][tower - 1][pseudostrip_in_TT - 1]++;
204  }
205  } // read EEMap file
206  f.close();
207 
208  unsigned int run[2] = {0, 0};
209  int vEE[100];
210  int istat = 0;
211  std::string l_tagname[2];
212  auto iovs = cond::payloadInspector::PlotBase::getTag<0>().iovs;
213  l_tagname[0] = cond::payloadInspector::PlotBase::getTag<0>().name;
214  auto firstiov = iovs.front();
215  run[0] = std::get<0>(firstiov);
216  std::tuple<cond::Time_t, cond::Hash> lastiov;
217  if (ntags == 2) {
218  auto tag2iovs = cond::payloadInspector::PlotBase::getTag<1>().iovs;
219  l_tagname[1] = cond::payloadInspector::PlotBase::getTag<1>().name;
220  lastiov = tag2iovs.front();
221  } else {
222  lastiov = iovs.back();
223  l_tagname[1] = l_tagname[0];
224  }
225  run[1] = std::get<0>(lastiov);
226  for (int irun = 0; irun < nIOVs; irun++) {
227  std::shared_ptr<EcalTPGStripStatus> payload;
228  if (irun == 0) {
229  payload = this->fetchPayload(std::get<1>(firstiov));
230  } else {
231  payload = this->fetchPayload(std::get<1>(lastiov));
232  }
233  if (payload.get()) {
234  const EcalTPGStripStatusMap& stripMap = (*payload).getMap();
235  // std::cout << " tower map size " << stripMap.size() << std::endl;
237  for (itSt = stripMap.begin(); itSt != stripMap.end(); ++itSt) {
238  if (itSt->second > 0) {
239  int ID = itSt->first / 8;
240  if (irun == 0 && istat < 100) {
241  vEE[istat] = ID;
242  // std::cout << " strip " << ID << " found in run 1" << std::endl;
243  istat++;
244  if (istat == 100)
245  std::cout << " limit on number of strips reached, stop keeping others" << std::endl;
246  } else {
247  bool found = false;
248  for (int is = 0; is < istat; is++) {
249  // std::cout << " checking " << ID << " against " << vEE[is] << std::endl;
250  if (vEE[is] == ID) {
251  // std::cout << " strip " << ID << " already in run 1" << std::endl;
252  found = true;
253  vEE[is] = -1;
254  break;
255  }
256  }
257  if (!found) {
258  // std::cout << " strip " << ID << " new, plot it" << std::endl;
259  // let's decode the ID
260  int strip = ID;
261  int pseudostrip = strip & 0x7;
262  strip /= 8;
263  int tt = strip & 0x7F;
264  strip /= 128;
265  int tccid = strip & 0x7F;
266  int NbXtalInStrip = NbrawEE[tccid - 1][tt - 1][pseudostrip - 1];
267  if (NbXtalInStrip != NXtal)
268  std::cout << " Strip TCC " << tccid << " TT " << tt << " ST " << pseudostrip << " Nx Xtals "
269  << NbXtalInStrip << std::endl;
270  for (int Xtal = 0; Xtal < NbXtalInStrip; Xtal++) {
271  uint32_t rawId = rawEE[tccid - 1][tt - 1][pseudostrip - 1][Xtal];
272  // std::cout << " rawid " << rawId << std::endl;
274  float x = (float)detid.ix();
275  float y = (float)detid.iy();
276  int iz = detid.zside();
277  if (iz == -1)
278  iz++;
279  if (iz == 0) {
280  endc_m->Fill(x + 0.5, y + 0.5, 1.);
281  EEstat[0][0]++;
282  } else {
283  endc_p->Fill(x + 0.5, y + 0.5, 1.);
284  EEstat[1][0]++;
285  }
286  // std::cout << " x " << x << " y " << y << " z " << iz << std::endl;
287  } // loop over crystals in strip
288  } // new strip
289  } // second run
290  }
291  } // loop over strips
292  } // payload
293  else
294  return false;
295  // std::cout << " nb of strips " << istat << std::endl;
296  } // loop over IOVs
297 
298  // now check if strips have disappered
299  for (int is = 0; is < istat; is++) {
300  if (vEE[is] != -1) {
301  // std::cout << " strip " << vEE[is] << " not found in run 2, plot it" << std::endl;
302  // let's decode the ID
303  int strip = vEE[is];
304  int pseudostrip = strip & 0x7;
305  strip /= 8;
306  int tt = strip & 0x7F;
307  strip /= 128;
308  int tccid = strip & 0x7F;
309  int NbXtalInStrip = NbrawEE[tccid - 1][tt - 1][pseudostrip - 1];
310  if (NbXtalInStrip != NXtal)
311  std::cout << " Strip TCC " << tccid << " TT " << tt << " ST " << pseudostrip << " Nx Xtals "
312  << NbXtalInStrip << std::endl;
313  for (int Xtal = 0; Xtal < NbXtalInStrip; Xtal++) {
314  uint32_t rawId = rawEE[tccid - 1][tt - 1][pseudostrip - 1][Xtal];
315  // std::cout << " rawid " << rawId << std::endl;
317  float x = (float)detid.ix();
318  float y = (float)detid.iy();
319  int iz = detid.zside();
320  if (iz == -1)
321  iz++;
322  if (iz == 0) {
323  endc_m->Fill(x + 0.5, y + 0.5, -1.);
324  EEstat[0][1]++;
325  } else {
326  endc_p->Fill(x + 0.5, y + 0.5, -1.);
327  EEstat[1][1]++;
328  }
329  // std::cout << " x " << x << " y " << y << " z " << iz << std::endl;
330  } // loop over crystals in strip
331  } // new strip
332  } // loop over run 1 strips
333 
334  gStyle->SetPalette(1);
335  gStyle->SetOptStat(0);
336  const Int_t NRGBs = 5;
337  const Int_t NCont = 255;
338 
339  Double_t stops[NRGBs] = {0.00, 0.34, 0.61, 0.84, 1.00};
340  Double_t red[NRGBs] = {0.00, 0.00, 0.87, 1.00, 0.51};
341  Double_t green[NRGBs] = {0.00, 0.81, 1.00, 0.20, 0.00};
342  Double_t blue[NRGBs] = {0.51, 1.00, 0.12, 0.00, 0.00};
343  TColor::CreateGradientColorTable(NRGBs, stops, red, green, blue, NCont);
344  gStyle->SetNumberContours(NCont);
345  // TCanvas canvas("CC map","CC map", 1600, 450);
346  Double_t w = 1200;
347  Double_t h = 650;
348  TCanvas canvas("c", "c", w, h);
349  // canvas.SetWindowSize(w + (w - canvas.GetWw()), h + (h - canvas.GetWh()));
350 
351  TLatex t1;
352  t1.SetNDC();
353  t1.SetTextAlign(26);
354  int len = l_tagname[0].length() + l_tagname[1].length();
355  if (ntags == 2) {
356  if (len < 180) {
357  t1.SetTextSize(0.03);
358  t1.DrawLatex(0.5, 0.96, Form("%s %i - %s %i", l_tagname[1].c_str(), run[1], l_tagname[0].c_str(), run[0]));
359  } else {
360  t1.SetTextSize(0.05);
361  t1.DrawLatex(0.5, 0.96, Form("Ecal TPGStripStatus, IOV %i - %i", run[1], run[0]));
362  }
363  } else {
364  t1.SetTextSize(0.05);
365  t1.DrawLatex(0.5, 0.96, Form("%s, IOV %i - %i", l_tagname[0].c_str(), run[1], run[0]));
366  }
367 
368  float xmi[2] = {0.0, 0.5};
369  float xma[2] = {0.5, 1.0};
370  std::array<std::unique_ptr<TPad>, 2> pad;
371  for (int obj = 0; obj < 2; obj++) {
372  pad[obj] = std::make_unique<TPad>(Form("p_%i", obj), Form("p_%i", obj), xmi[obj], 0.0, xma[obj], 0.94);
373  pad[obj]->Draw();
374  }
375 
376  pad[0]->cd();
377  DrawEE(endc_m, -1.0, 1.0);
378  t1.SetTextSize(0.03);
379  t1.DrawLatex(0.15, 0.92, Form("new %i old %i", EEstat[0][0], EEstat[0][1]));
380  pad[1]->cd();
381  DrawEE(endc_p, -1.0, 1.0);
382  t1.DrawLatex(0.15, 0.92, Form("new %i old %i", EEstat[1][0], EEstat[1][1]));
383 
384  std::string ImageName(this->m_imageFileName);
385  canvas.SaveAs(ImageName.c_str());
386  return true;
387  } // fill method
388  }; // class EcalTPGStripStatusDiffBase
389  using EcalTPGStripStatusDiffOneTag = EcalTPGStripStatusDiffBase<cond::payloadInspector::SINGLE_IOV, 1>;
390  using EcalTPGStripStatusDiffTwoTags = EcalTPGStripStatusDiffBase<cond::payloadInspector::SINGLE_IOV, 2>;
391 
392  /*****************************************
393  2d plot of EcalTPGStripStatus Error Summary of 1 IOV
394  ******************************************/
395  class EcalTPGStripStatusSummaryPlot : public cond::payloadInspector::PlotImage<EcalTPGStripStatus> {
396  public:
397  EcalTPGStripStatusSummaryPlot()
398  : cond::payloadInspector::PlotImage<EcalTPGStripStatus>("Ecal TPGStrip Status Summary - map ") {
399  setSingleIov(true);
400  }
401 
402  bool fill(const std::vector<std::tuple<cond::Time_t, cond::Hash> >& iovs) override {
403  auto iov = iovs.front(); //get reference to 1st element in the vector iovs
404  std::shared_ptr<EcalTPGStripStatus> payload =
405  fetchPayload(std::get<1>(iov)); //std::get<1>(iov) refers to the Hash in the tuple iov
406  unsigned int run = std::get<0>(iov); //referes to Time_t in iov.
407  TH2F* align; //pointer to align which is a 2D histogram
408 
409  int NbRows = 1;
410  int NbColumns = 2;
411 
412  if (payload.get()) { //payload is an iov retrieved from payload using hash.
413  const EcalTPGStripStatusMap& stripMap = (*payload).getMap();
414 
415  align = new TH2F("Ecal TPGStrip Status Summary",
416  "Total NumberOfMasked",
417  NbColumns,
418  0,
419  NbColumns,
420  NbRows,
421  0,
422  NbRows);
423 
424  int NbMaskedTT = 0;
425 
426  for (EcalTPGStripStatusMapIterator it = stripMap.begin(); it != stripMap.end(); ++it)
427  if ((*it).second > 0)
428  NbMaskedTT++;
429 
430  align->Fill(0.5, 0.5, stripMap.size());
431  align->Fill(1.5, 0.5, NbMaskedTT);
432 
433  } // if payload.get()
434  else
435  return false;
436 
437  gStyle->SetPalette(1);
438  gStyle->SetOptStat(0);
439  TCanvas canvas("CC map", "CC map", 1000, 1000);
440  TLatex t1;
441  t1.SetNDC();
442  t1.SetTextAlign(26);
443  t1.SetTextSize(0.04);
444  t1.SetTextColor(2);
445  t1.DrawLatex(0.5, 0.96, Form("Endcap:Number of masked Trigger Strips, IOV %i", run));
446 
447  TPad pad("pad", "pad", 0.0, 0.0, 1.0, 0.94);
448  pad.Draw();
449  pad.cd();
450  align->Draw("TEXT");
451 
452  drawTable(NbRows, NbColumns);
453 
454  align->GetXaxis()->SetTickLength(0.);
455  align->GetXaxis()->SetLabelSize(0.);
456  align->GetYaxis()->SetTickLength(0.);
457  align->GetYaxis()->SetLabelSize(0.);
458 
459  std::string ImageName(m_imageFileName);
460  canvas.SaveAs(ImageName.c_str());
461  return true;
462  } // fill method
463  };
464 
465 } // namespace
466 
467 // Register the classes as boost python plugin
469  PAYLOAD_INSPECTOR_CLASS(EcalTPGStripStatusPlot);
470  PAYLOAD_INSPECTOR_CLASS(EcalTPGStripStatusDiffOneTag);
471  PAYLOAD_INSPECTOR_CLASS(EcalTPGStripStatusDiffTwoTags);
472  PAYLOAD_INSPECTOR_CLASS(EcalTPGStripStatusSummaryPlot);
473 }
static EEDetId detIdFromDenseIndex(uint32_t din)
Definition: EEDetId.h:220
T w() const
uint32_t ID
Definition: Definitions.h:24
static const int XYMODE
Definition: EEDetId.h:335
int ix() const
Definition: EEDetId.h:77
void DrawEE(TH2F *endc, float min, float max)
Definition: EcalDrawUtils.h:29
#define PAYLOAD_INSPECTOR_CLASS(CLASS_NAME)
Definition: TTTypes.h:54
uint32_t denseIndex() const
Definition: EEDetId.h:192
double f[11][100]
#define PAYLOAD_INSPECTOR_MODULE(PAYLOAD_TYPENAME)
ALPAKA_FN_ACC ALPAKA_FN_INLINE uint32_t ix(uint32_t id)
int zside() const
Definition: EEDetId.h:71
def canvas(sub, attr)
Definition: svgfig.py:482
ALPAKA_FN_ACC ALPAKA_FN_INLINE uint32_t iy(uint32_t id)
std::map< uint32_t, uint16_t > EcalTPGStripStatusMap
The Signals That Services Can Subscribe To This is based on ActivityRegistry h
Helper function to determine trigger accepts.
Definition: Activities.doc:4
void drawTable(int nbRows, int nbColumns)
Definition: EcalDrawUtils.h:91
std::shared_ptr< PayloadType > fetchPayload(const cond::Hash &payloadHash)
int iy() const
Definition: EEDetId.h:83
std::map< uint32_t, uint16_t >::const_iterator EcalTPGStripStatusMapIterator