CMS 3D CMS Logo

OnlineBeamMonitor.cc
Go to the documentation of this file.
1 /*
2  * \file OnlineBeamMonitor.cc
3  * \author Lorenzo Uplegger/FNAL
4  * modified by Simone Gennai INFN/Bicocca
5  */
6 
21 #include <memory>
22 
23 #include <numeric>
24 
25 using namespace std;
26 using namespace edm;
27 using namespace reco;
28 
29 //----------------------------------------------------------------------------------------------------------------------
31  : monitorName_(ps.getUntrackedParameter<string>("MonitorName")),
32  bsTransientToken_(
34  bsHLTToken_(
36  bsLegacyToken_(
38  numberOfValuesToSave_(0) {
39  if (!monitorName_.empty())
40  monitorName_ = monitorName_ + "/";
41 
42  processedLumis_.clear();
43 
44  varNamesV_.push_back("x");
45  varNamesV_.push_back("y");
46  varNamesV_.push_back("z");
47  varNamesV_.push_back("sigmaX");
48  varNamesV_.push_back("sigmaY");
49  varNamesV_.push_back("sigmaZ");
50 
51  //histoByCategoryNames_.insert(pair<string, string>("run", "Coordinate"));
52  //histoByCategoryNames_.insert(pair<string, string>("run", "PrimaryVertex fit-DataBase"));
53  //histoByCategoryNames_.insert(pair<string, string>("run", "PrimaryVertex fit-BeamFit"));
54  //histoByCategoryNames_.insert(pair<string, string>("run", "PrimaryVertex fit-Scalers"));
55  //histoByCategoryNames_.insert(pair<string, string>("run", "PrimaryVertex-DataBase"));
56  //histoByCategoryNames_.insert(pair<string, string>("run", "PrimaryVertex-BeamFit"));
57  //histoByCategoryNames_.insert(pair<string, string>("run", "PrimaryVertex-Scalers"));
58 
59  histoByCategoryNames_.insert(pair<string, string>("lumi", "Lumibased BeamSpotHLT"));
60  histoByCategoryNames_.insert(pair<string, string>("lumi", "Lumibased BeamSpotLegacy"));
61  histoByCategoryNames_.insert(pair<string, string>("lumi", "Lumibased BeamSpotTransient"));
62 
63  for (const auto& itV : varNamesV_) {
64  for (const auto& itM : histoByCategoryNames_) {
65  histosMap_[itV][itM.first][itM.second] = nullptr;
66  }
67  }
68 }
69 
72 
73  ps.addUntracked<std::string>("MonitorName", "YourSubsystemName");
74  iDesc.addDefault(ps);
75 }
76 
77 //----------------------------------------------------------------------------------------------------------------------
78 void OnlineBeamMonitor::bookHistograms(DQMStore::IBooker& ibooker,
79  edm::Run const& iRun,
80  edm::EventSetup const& iSetup) {
81  string name;
82  string title;
83  int firstLumi = 1;
84  int lastLumi = 3000;
85  for (auto& itM : histosMap_) {
86  //Making histos per Lumi
87  // x,y,z,sigmaX,sigmaY,sigmaZ
88  for (auto& itMM : itM.second) {
89  if (itMM.first != "run") {
90  for (auto& itMMM : itMM.second) {
91  name = string("h") + itM.first + itMMM.first;
92  title = itM.first + "_{0} " + itMMM.first;
93  if (itMM.first == "lumi") {
94  ibooker.setCurrentFolder(monitorName_ + "Debug");
95  itMMM.second = ibooker.book1D(name, title, lastLumi - firstLumi + 1, firstLumi - 0.5, lastLumi + 0.5);
96  itMMM.second->setEfficiencyFlag();
97  } else {
98  LogInfo("OnlineBeamMonitorClient") << "Unrecognized category " << itMM.first;
99  }
100  if (itMMM.second != nullptr) {
101  if (itMMM.first.find('-') != string::npos) {
102  itMMM.second->setAxisTitle(string("#Delta ") + itM.first + "_{0} (cm)", 2);
103  } else {
104  itMMM.second->setAxisTitle(itM.first + "_{0} (cm)", 2);
105  }
106  itMMM.second->setAxisTitle("Lumisection", 1);
107  }
108  }
109  }
110  }
111  }
112 
113  // create and cd into new folder
114  ibooker.setCurrentFolder(monitorName_ + "Validation");
115  //Book histograms
116  bsChoice_ = ibooker.book1D("bsChoice",
117  "Choice between HLT (+1) and Legacy (-1) BS",
118  lastLumi - firstLumi + 1,
119  firstLumi - 0.5,
120  lastLumi + 0.5);
121  bsChoice_->setAxisTitle("Lumisection", 1);
122  bsChoice_->setAxisTitle("Choice", 2);
123 }
124 
125 //----------------------------------------------------------------------------------------------------------------------
126 std::shared_ptr<onlinebeammonitor::NoCache> OnlineBeamMonitor::globalBeginLuminosityBlock(
127  const LuminosityBlock& iLumi, const EventSetup& iSetup) const {
128  // Always create a beamspot group for each lumi weather we have results or not! Each Beamspot will be of unknown type!
129 
130  processedLumis_.push_back(iLumi.id().luminosityBlock());
131  //Read BeamSpot from DB
133  ESHandle<BeamSpotOnlineObjects> bsLegacyHandle;
134  ESHandle<BeamSpotObjects> bsTransientHandle;
135 
136  if (auto bsHLTHandle = iSetup.getHandle(bsHLTToken_)) {
137  auto const& spotDB = *bsHLTHandle;
138 
139  // translate from BeamSpotObjects to reco::BeamSpot
140  BeamSpot::Point apoint(spotDB.GetX(), spotDB.GetY(), spotDB.GetZ());
141 
143  for (int i = 0; i < 7; ++i) {
144  for (int j = 0; j < 7; ++j) {
145  matrix(i, j) = spotDB.GetCovariance(i, j);
146  }
147  }
148 
149  beamSpotsMap_["HLT"] =
150  BeamSpot(apoint, spotDB.GetSigmaZ(), spotDB.Getdxdz(), spotDB.Getdydz(), spotDB.GetBeamWidthX(), matrix);
151 
152  BeamSpot* aSpot = &(beamSpotsMap_["HLT"]);
153 
154  aSpot->setBeamWidthY(spotDB.GetBeamWidthY());
155  aSpot->setEmittanceX(spotDB.GetEmittanceX());
156  aSpot->setEmittanceY(spotDB.GetEmittanceY());
157  aSpot->setbetaStar(spotDB.GetBetaStar());
158 
159  if (spotDB.GetBeamType() == 2) {
160  aSpot->setType(reco::BeamSpot::Tracker);
161  } else {
162  aSpot->setType(reco::BeamSpot::Fake);
163  }
164  //LogInfo("OnlineBeamMonitor")
165  // << *aSpot << std::endl;
166  } else {
167  LogInfo("OnlineBeamMonitor") << "Database BeamSpot is not valid at lumi: " << iLumi.id().luminosityBlock();
168  }
169  if (auto bsLegacyHandle = iSetup.getHandle(bsLegacyToken_)) {
170  auto const& spotDB = *bsLegacyHandle;
171  // translate from BeamSpotObjects to reco::BeamSpot
172  BeamSpot::Point apoint(spotDB.GetX(), spotDB.GetY(), spotDB.GetZ());
173 
175  for (int i = 0; i < 7; ++i) {
176  for (int j = 0; j < 7; ++j) {
177  matrix(i, j) = spotDB.GetCovariance(i, j);
178  }
179  }
180 
181  beamSpotsMap_["Legacy"] =
182  BeamSpot(apoint, spotDB.GetSigmaZ(), spotDB.Getdxdz(), spotDB.Getdydz(), spotDB.GetBeamWidthX(), matrix);
183 
184  BeamSpot* aSpot = &(beamSpotsMap_["Legacy"]);
185 
186  aSpot->setBeamWidthY(spotDB.GetBeamWidthY());
187  aSpot->setEmittanceX(spotDB.GetEmittanceX());
188  aSpot->setEmittanceY(spotDB.GetEmittanceY());
189  aSpot->setbetaStar(spotDB.GetBetaStar());
190 
191  if (spotDB.GetBeamType() == 2) {
192  aSpot->setType(reco::BeamSpot::Tracker);
193  } else {
194  aSpot->setType(reco::BeamSpot::Fake);
195  }
196  //LogInfo("OnlineBeamMonitor")
197  // << *aSpot << std::endl;
198  } else {
199  LogInfo("OnlineBeamMonitor") << "Database BeamSpot is not valid at lumi: " << iLumi.id().luminosityBlock();
200  }
201  if (auto bsTransientHandle = iSetup.getHandle(bsTransientToken_)) {
202  auto const& spotDB = *bsTransientHandle;
203 
204  // translate from BeamSpotObjects to reco::BeamSpot
205  BeamSpot::Point apoint(spotDB.GetX(), spotDB.GetY(), spotDB.GetZ());
206 
208  for (int i = 0; i < 7; ++i) {
209  for (int j = 0; j < 7; ++j) {
210  matrix(i, j) = spotDB.GetCovariance(i, j);
211  }
212  }
213 
214  beamSpotsMap_["Transient"] =
215  BeamSpot(apoint, spotDB.GetSigmaZ(), spotDB.Getdxdz(), spotDB.Getdydz(), spotDB.GetBeamWidthX(), matrix);
216 
217  BeamSpot* aSpot = &(beamSpotsMap_["Transient"]);
218 
219  aSpot->setBeamWidthY(spotDB.GetBeamWidthY());
220  aSpot->setEmittanceX(spotDB.GetEmittanceX());
221  aSpot->setEmittanceY(spotDB.GetEmittanceY());
222  aSpot->setbetaStar(spotDB.GetBetaStar());
223 
224  if (spotDB.GetBeamType() == 2) {
225  aSpot->setType(reco::BeamSpot::Tracker);
226  } else {
227  aSpot->setType(reco::BeamSpot::Fake);
228  }
229  //LogInfo("OnlineBeamMonitor")
230  // << *aSpot << std::endl;
231  } else {
232  LogInfo("OnlineBeamMonitor") << "Database BeamSpot is not valid at lumi: " << iLumi.id().luminosityBlock();
233  }
234  return nullptr;
235 }
236 
237 //----------------------------------------------------------------------------------------------------------------------
239  //Setting up the choice
240  if (beamSpotsMap_.find("Transient") != beamSpotsMap_.end()) {
241  if (beamSpotsMap_.find("HLT") != beamSpotsMap_.end() &&
242  beamSpotsMap_["Transient"].x0() == beamSpotsMap_["HLT"].x0()) {
243  bsChoice_->setBinContent(iLumi.id().luminosityBlock(), 1);
244  bsChoice_->setBinError(iLumi.id().luminosityBlock(), 0.05);
245  } else if (beamSpotsMap_.find("Legacy") != beamSpotsMap_.end() &&
246  beamSpotsMap_["Transient"].x0() == beamSpotsMap_["Legacy"].x0()) {
247  bsChoice_->setBinContent(iLumi.id().luminosityBlock(), -1);
248  bsChoice_->setBinError(iLumi.id().luminosityBlock(), 0.05);
249  } else {
250  bsChoice_->setBinContent(iLumi.id().luminosityBlock(), -10);
251  bsChoice_->setBinError(iLumi.id().luminosityBlock(), 0.05);
252  }
253  } else {
254  bsChoice_->setBinContent(iLumi.id().luminosityBlock(), 0);
255  bsChoice_->setBinError(iLumi.id().luminosityBlock(), 0.05);
256  }
257 
258  // "PV,BF..." Value,Error
259  map<std::string, pair<double, double> > resultsMap;
260  vector<pair<double, double> > vertexResults;
261  MonitorElement* histo = nullptr;
262  for (const auto& itV : varNamesV_) {
263  resultsMap.clear();
264  for (const auto& itBS : beamSpotsMap_) {
265  if (itBS.second.type() == BeamSpot::Tracker) {
266  if (itV == "x") {
267  resultsMap[itBS.first] = pair<double, double>(itBS.second.x0(), itBS.second.x0Error());
268  } else if (itV == "y") {
269  resultsMap[itBS.first] = pair<double, double>(itBS.second.y0(), itBS.second.y0Error());
270  } else if (itV == "z") {
271  resultsMap[itBS.first] = pair<double, double>(itBS.second.z0(), itBS.second.z0Error());
272  } else if (itV == "sigmaX") {
273  resultsMap[itBS.first] = pair<double, double>(itBS.second.BeamWidthX(), itBS.second.BeamWidthXError());
274  } else if (itV == "sigmaY") {
275  resultsMap[itBS.first] = pair<double, double>(itBS.second.BeamWidthY(), itBS.second.BeamWidthYError());
276  } else if (itV == "sigmaZ") {
277  resultsMap[itBS.first] = pair<double, double>(itBS.second.sigmaZ(), itBS.second.sigmaZ0Error());
278  } else {
279  LogInfo("OnlineBeamMonitor") << "The histosMap_ has been built with the name " << itV
280  << " that I can't recognize!";
281  }
282  }
283  }
284 
285  for (const auto& itM : histoByCategoryNames_) {
286  if ((histo = histosMap_[itV][itM.first][itM.second]) == nullptr)
287  continue;
288  if (itM.second == "Lumibased BeamSpotHLT") {
289  if (resultsMap.find("HLT") != resultsMap.end()) {
290  histo->setBinContent(iLumi.id().luminosityBlock(), resultsMap["HLT"].first);
291  histo->setBinError(iLumi.id().luminosityBlock(), resultsMap["HLT"].second);
292  }
293  } else if (itM.second == "Lumibased BeamSpotLegacy") {
294  if (resultsMap.find("Legacy") != resultsMap.end()) {
295  histo->setBinContent(iLumi.id().luminosityBlock(), resultsMap["Legacy"].first);
296  histo->setBinError(iLumi.id().luminosityBlock(), resultsMap["Legacy"].second);
297  }
298  } else if (itM.second == "Lumibased BeamSpotTransient") {
299  if (resultsMap.find("Transient") != resultsMap.end()) {
300  histo->setBinContent(iLumi.id().luminosityBlock(), resultsMap["Transient"].first);
301  histo->setBinError(iLumi.id().luminosityBlock(), resultsMap["Transient"].second);
302  }
303  } else {
304  LogInfo("OnlineBeamMonitor") << "The histosMap_ have a histogram named " << itM.second
305  << " that I can't recognize in this loop!";
306  }
307  }
308  }
309 }
310 
312  if (processedLumis_.empty()) {
313  return;
314  }
315 
316  const double bigNumber = 1000000.;
317  std::sort(processedLumis_.begin(), processedLumis_.end());
318  int firstLumi = *processedLumis_.begin();
319  int lastLumi = *(--processedLumis_.end());
320  bsChoice_->getTH1()->GetXaxis()->SetRangeUser(firstLumi - 0.5, lastLumi + 0.5);
321  for (auto& itH : histosMap_) {
322  for (auto& itHH : itH.second) {
323  double min = bigNumber;
324  double max = -bigNumber;
325  if (itHH.first != "run") {
326  for (auto& itHHH : itHH.second) {
327  if (itHHH.second != nullptr) {
328  for (int bin = 1; bin <= itHHH.second->getTH1()->GetNbinsX(); bin++) {
329  if (itHHH.second->getTH1()->GetBinError(bin) != 0 || itHHH.second->getTH1()->GetBinContent(bin) != 0) {
330  if (itHHH.first == "Lumibased BeamSpotHLT" || itHHH.first == "Lumibased BeamSpotLegacy" ||
331  itHHH.first == "Lumibased BeamSpotTransient") {
332  if (min > itHHH.second->getTH1()->GetBinContent(bin)) {
333  min = itHHH.second->getTH1()->GetBinContent(bin);
334  }
335  if (max < itHHH.second->getTH1()->GetBinContent(bin)) {
336  max = itHHH.second->getTH1()->GetBinContent(bin);
337  }
338  } else {
339  LogInfo("OnlineBeamMonitorClient") << "The histosMap_ have a histogram named " << itHHH.first
340  << " that I can't recognize in this loop!";
341  }
342  }
343  }
344  }
345  }
346  for (auto& itHHH : itHH.second) {
347  if (itHHH.second != nullptr) {
348  if (itHHH.first == "Lumibased BeamSpotHLT" || itHHH.first == "Lumibased BeamSpotLegacy" ||
349  itHHH.first == "Lumibased BeamSpotTransient") {
350  if ((max == -bigNumber && min == bigNumber) || max - min == 0) {
351  itHHH.second->getTH1()->SetMinimum(itHHH.second->getTH1()->GetMinimum() - 0.01);
352  itHHH.second->getTH1()->SetMaximum(itHHH.second->getTH1()->GetMaximum() + 0.01);
353  } else {
354  itHHH.second->getTH1()->SetMinimum(min - 0.1 * (max - min));
355  itHHH.second->getTH1()->SetMaximum(max + 0.1 * (max - min));
356  }
357  } else {
358  LogInfo("OnlineBeamMonitorClient")
359  << "The histosMap_ have a histogram named " << itHHH.first << " that I can't recognize in this loop!";
360  }
361  itHHH.second->getTH1()->GetXaxis()->SetRangeUser(firstLumi - 0.5, lastLumi + 0.5);
362  }
363  }
364  }
365  }
366  }
367 }
PVFitter.h
BeamSpotOnlineHLTObjectsRcd
Definition: BeamSpotOnlineHLTObjectsRcd.h:24
dqm::impl::MonitorElement
Definition: MonitorElement.h:98
Handle.h
OnlineBeamMonitor::bookHistograms
void bookHistograms(DQMStore::IBooker &, edm::Run const &, edm::EventSetup const &) override
Definition: OnlineBeamMonitor.cc:78
mps_fire.i
i
Definition: mps_fire.py:355
reco::BeamSpot::setBeamWidthY
void setBeamWidthY(double v)
Definition: BeamSpot.h:105
OnlineBeamMonitor::varNamesV_
std::vector< std::string > varNamesV_
Definition: OnlineBeamMonitor.h:69
MessageLogger.h
makeMuonMisalignmentScenario.matrix
list matrix
Definition: makeMuonMisalignmentScenario.py:141
ESHandle.h
align::BeamSpot
Definition: StructureType.h:89
BeamSpotTransientObjectsRcd
Definition: BeamSpotTransientObjectsRcd.h:27
OnlineBeamMonitor::bsChoice_
MonitorElement * bsChoice_
Definition: OnlineBeamMonitor.h:63
edm::LuminosityBlock
Definition: LuminosityBlock.h:50
OnlineBeamMonitor::processedLumis_
std::vector< int > processedLumis_
Definition: OnlineBeamMonitor.h:61
edm::Run
Definition: Run.h:45
min
T min(T a, T b)
Definition: MathUtil.h:58
LuminosityBlock.h
edm
HLT enums.
Definition: AlignableModifier.h:19
OnlineBeamMonitor::histosMap_
HistosContainer histosMap_
Definition: OnlineBeamMonitor.h:67
edm::LogInfo
Definition: MessageLogger.h:254
edm::ParameterSetDescription
Definition: ParameterSetDescription.h:52
timingPdfMaker.histo
histo
Definition: timingPdfMaker.py:279
OnlineBeamMonitor::histoByCategoryNames_
std::multimap< std::string, std::string > histoByCategoryNames_
Definition: OnlineBeamMonitor.h:70
reco
fixed size matrix
Definition: AlignmentAlgorithmBase.h:45
align::Tracker
Definition: StructureType.h:70
MakerMacros.h
OnlineBeamMonitor::monitorName_
std::string monitorName_
Definition: OnlineBeamMonitor.h:53
DEFINE_FWK_MODULE
#define DEFINE_FWK_MODULE(type)
Definition: MakerMacros.h:16
BeamSpot.h
OnlineBeamMonitor::bsTransientToken_
edm::ESGetToken< BeamSpotObjects, BeamSpotTransientObjectsRcd > bsTransientToken_
Definition: OnlineBeamMonitor.h:54
Service.h
reco::BeamSpot
Definition: BeamSpot.h:21
reco::BeamSpot::Tracker
Definition: BeamSpot.h:24
Run.h
edm::ESHandle
Definition: DTSurvey.h:22
reco::BeamSpot::Fake
Definition: BeamSpot.h:24
BeamSpotOnlineLegacyObjectsRcd
Definition: BeamSpotOnlineLegacyObjectsRcd.h:24
edm::Transition::BeginLuminosityBlock
OnlineBeamMonitor::bsHLTToken_
edm::ESGetToken< BeamSpotOnlineObjects, BeamSpotOnlineHLTObjectsRcd > bsHLTToken_
Definition: OnlineBeamMonitor.h:55
dqm::impl::MonitorElement::getTH1
virtual TH1 * getTH1()
Definition: MonitorElement.cc:969
edm::ConfigurationDescriptions
Definition: ConfigurationDescriptions.h:28
AlCaHLTBitMon_QueryRunRegistry.string
string
Definition: AlCaHLTBitMon_QueryRunRegistry.py:256
edm::ParameterSetDescription::addUntracked
ParameterDescriptionBase * addUntracked(U const &iLabel, T const &value)
Definition: ParameterSetDescription.h:100
edm::ParameterSet
Definition: ParameterSet.h:36
edm::Transition
Transition
Definition: Transition.h:12
SiStripPI::max
Definition: SiStripPayloadInspectorHelper.h:169
OnlineBeamMonitor::dqmEndRun
void dqmEndRun(edm::Run const &, edm::EventSetup const &) override
Definition: OnlineBeamMonitor.cc:311
edm::LuminosityBlockID::luminosityBlock
LuminosityBlockNumber_t luminosityBlock() const
Definition: LuminosityBlockID.h:42
edm::LuminosityBlockBase::id
LuminosityBlockID id() const
Definition: LuminosityBlockBase.h:44
edm::EventSetup::getHandle
ESHandle< T > getHandle(const ESGetToken< T, R > &iToken) const
Definition: EventSetup.h:141
OnlineBeamMonitor::beamSpotsMap_
BeamSpotContainer beamSpotsMap_
Definition: OnlineBeamMonitor.h:66
OnlineBeamMonitor::globalBeginLuminosityBlock
std::shared_ptr< onlinebeammonitor::NoCache > globalBeginLuminosityBlock(const edm::LuminosityBlock &iLumi, const edm::EventSetup &iSetup) const override
Definition: OnlineBeamMonitor.cc:126
BeamSpotObjects
Definition: BeamSpotObjects.h:20
edm::EventSetup
Definition: EventSetup.h:57
reco::BeamSpot::CovarianceMatrix
math::Error< dimension >::type CovarianceMatrix
Definition: BeamSpot.h:29
OnlineBeamMonitor.h
newFWLiteAna.bin
bin
Definition: newFWLiteAna.py:161
overlapproblemtsosanalyzer_cfi.title
title
Definition: overlapproblemtsosanalyzer_cfi.py:7
OnlineBeamMonitor::bsLegacyToken_
edm::ESGetToken< BeamSpotOnlineObjects, BeamSpotOnlineLegacyObjectsRcd > bsLegacyToken_
Definition: OnlineBeamMonitor.h:56
dqm::impl::MonitorElement::setBinContent
virtual void setBinContent(int binx, double content)
set content of bin (1-D)
Definition: MonitorElement.cc:691
OnlineBeamMonitor::OnlineBeamMonitor
OnlineBeamMonitor(const edm::ParameterSet &)
Definition: OnlineBeamMonitor.cc:30
std
Definition: JetResolutionObject.h:76
BeamSpotOnlineObjects
Definition: BeamSpotOnlineObjects.h:25
dqm::impl::MonitorElement::setBinError
virtual void setBinError(int binx, double error)
set uncertainty on content of bin (1-D)
Definition: MonitorElement.cc:709
Skims_PA_cff.name
name
Definition: Skims_PA_cff.py:17
EventSetup.h
OnlineBeamMonitor::globalEndLuminosityBlock
void globalEndLuminosityBlock(const edm::LuminosityBlock &iLumi, const edm::EventSetup &iSetup) override
Definition: OnlineBeamMonitor.cc:238
BeamFitter.h
ConsumesCollector.h
reco::BeamSpot::Point
math::XYZPoint Point
point in the space
Definition: BeamSpot.h:27
View.h
OnlineBeamMonitor
Definition: OnlineBeamMonitor.h:31
dqmiolumiharvest.j
j
Definition: dqmiolumiharvest.py:66
edm::ConfigurationDescriptions::addDefault
void addDefault(ParameterSetDescription const &psetDescription)
Definition: ConfigurationDescriptions.cc:99
dqm::impl::MonitorElement::setAxisTitle
virtual void setAxisTitle(const std::string &title, int axis=1)
set x-, y- or z-axis title (axis=1, 2, 3 respectively)
Definition: MonitorElement.cc:800
OnlineBeamMonitor::fillDescriptions
static void fillDescriptions(edm::ConfigurationDescriptions &)
Definition: OnlineBeamMonitor.cc:70