diff --git a/DQMOffline/Alignment/BuildFile.xml b/DQMOffline/Alignment/BuildFile.xml
index 40bf762dc0dfb..c2d4ce13b9fa3 100644
--- a/DQMOffline/Alignment/BuildFile.xml
+++ b/DQMOffline/Alignment/BuildFile.xml
@@ -14,4 +14,5 @@
+
diff --git a/DQMOffline/Alignment/interface/DiMuonMassBiasClient.h b/DQMOffline/Alignment/interface/DiMuonMassBiasClient.h
new file mode 100644
index 0000000000000..ae1b093e9acfd
--- /dev/null
+++ b/DQMOffline/Alignment/interface/DiMuonMassBiasClient.h
@@ -0,0 +1,98 @@
+#ifndef DQMOffline_Alignment_DiMuonMassBiasClient_h
+#define DQMOffline_Alignment_DiMuonMassBiasClient_h
+// -*- C++ -*-
+//
+// Package: DQMOffline/Alignment
+// Class : DiMuonMassBiasClient
+//
+// DQM class to plot di-muon mass bias in different kinematics bins
+
+// system includes
+#include
+
+// user includes
+#include "DQMServices/Core/interface/DQMEDHarvester.h"
+#include "DQMServices/Core/interface/DQMStore.h"
+#include "DataFormats/GeometryCommonDetAlgo/interface/Measurement1D.h"
+#include "FWCore/Framework/interface/ESHandle.h"
+#include "FWCore/Framework/interface/EventSetup.h"
+#include "FWCore/Framework/interface/LuminosityBlock.h"
+#include "FWCore/Framework/interface/MakerMacros.h"
+#include "FWCore/Framework/interface/Run.h"
+#include "FWCore/ParameterSet/interface/ParameterSet.h"
+
+namespace diMuonMassBias {
+
+ struct fitOutputs {
+ public:
+ fitOutputs(const Measurement1D& bias, const Measurement1D& width) : m_bias(bias), m_width(width) {}
+
+ // getters
+ const Measurement1D getBias() { return m_bias; }
+ const Measurement1D getWidth() { return m_width; }
+
+ private:
+ Measurement1D m_bias;
+ Measurement1D m_width;
+ };
+
+ // helper functions to fill arrays from vectors
+ inline void fillArrayF(float* x, const edm::ParameterSet& cfg, const char* name) {
+ auto v = cfg.getParameter>(name);
+ assert(v.size() == 3);
+ std::copy(std::begin(v), std::end(v), x);
+ }
+
+ inline void fillArrayI(int* x, const edm::ParameterSet& cfg, const char* name) {
+ auto v = cfg.getParameter>(name);
+ assert(v.size() == 3);
+ std::copy(std::begin(v), std::end(v), x);
+ }
+} // namespace diMuonMassBias
+
+class DiMuonMassBiasClient : public DQMEDHarvester {
+public:
+ /// Constructor
+ DiMuonMassBiasClient(const edm::ParameterSet& ps);
+
+ /// Destructor
+ ~DiMuonMassBiasClient() override;
+
+ static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
+
+protected:
+ /// BeginJob
+ void beginJob(void) override;
+
+ /// BeginRun
+ void beginRun(edm::Run const& run, edm::EventSetup const& eSetup) override;
+
+ /// EndJob
+ void dqmEndJob(DQMStore::IBooker& ibooker_, DQMStore::IGetter& igetter_) override;
+
+private:
+ /// book MEs
+ void bookMEs(DQMStore::IBooker& ibooker);
+ void getMEsToHarvest(DQMStore::IGetter& igetter);
+ diMuonMassBias::fitOutputs fitVoigt(TH1* hist, const bool& fitBackground = false) const;
+
+ // data members
+ const std::string TopFolder_;
+ const bool fitBackground_;
+ const bool debugMode_;
+
+ float meanConfig_[3]; /* parmaeters for the fit: mean */
+ float widthConfig_[3]; /* parameters for the fit: width */
+ float sigmaConfig_[3]; /* parmaeters for the fit: sigma */
+
+ // list of histograms to harvest
+ std::vector MEtoHarvest_;
+
+ // the histograms to be filled
+ std::map meanProfiles_;
+ std::map widthProfiles_;
+
+ // the histograms than need to be fit and displays
+ std::map harvestTargets_;
+};
+#endif
diff --git a/DQMOffline/Alignment/python/ALCARECOTkAlDQM_cff.py b/DQMOffline/Alignment/python/ALCARECOTkAlDQM_cff.py
index 2988fff7bc38f..2b6d38bbaf2be 100644
--- a/DQMOffline/Alignment/python/ALCARECOTkAlDQM_cff.py
+++ b/DQMOffline/Alignment/python/ALCARECOTkAlDQM_cff.py
@@ -3,6 +3,7 @@
import DQMOffline.Alignment.TkAlCaRecoMonitor_cfi
import DQMOffline.Alignment.DiMuonVertexMonitor_cfi
import DQMOffline.Alignment.DiMuonMassBiasMonitor_cfi
+import DQMOffline.Alignment.DiMuonMassBiasClient_cfi
#Below all DQM modules for TrackerAlignment AlCaRecos are instantiated.
######################################################
@@ -86,7 +87,11 @@
FolderName = "AlCaReco/"+__selectionName
)
-ALCARECOTkAlDiMuonAndVertexDQM = cms.Sequence(ALCARECOTkAlDiMuonAndVertexTkAlDQM + ALCARECOTkAlDiMuonAndVertexVtxDQM + ALCARECOTkAlDiMuonMassBiasDQM )
+ALCARECOTkAlDiMuonMassBiasClient = DQMOffline.Alignment.DiMuonMassBiasClient_cfi.DiMuonMassBiasClient.clone(
+ FolderName = "AlCaReco/"+__selectionName
+)
+
+ALCARECOTkAlDiMuonAndVertexDQM = cms.Sequence(ALCARECOTkAlDiMuonAndVertexTkAlDQM + ALCARECOTkAlDiMuonAndVertexVtxDQM + ALCARECOTkAlDiMuonMassBiasDQM + ALCARECOTkAlDiMuonMassBiasClient)
#########################################################
#############--- TkAlZMuMuHI ---########################
diff --git a/DQMOffline/Alignment/python/DiMuonMassBiasClient_cfi.py b/DQMOffline/Alignment/python/DiMuonMassBiasClient_cfi.py
new file mode 100644
index 0000000000000..dc53a0e40c9a0
--- /dev/null
+++ b/DQMOffline/Alignment/python/DiMuonMassBiasClient_cfi.py
@@ -0,0 +1,36 @@
+import FWCore.ParameterSet.Config as cms
+
+from DQMServices.Core.DQMEDHarvester import DQMEDHarvester
+
+DiMuonMassBiasClient = DQMEDHarvester("DiMuonMassBiasClient",
+ FolderName = cms.string('DiMuonMassBiasMonitor'),
+ fitBackground = cms.bool(False),
+ debugMode = cms.bool(False),
+ fit_par = cms.PSet(
+ mean_par = cms.vdouble(
+ 90.,
+ 60.,
+ 120.
+ ),
+ width_par = cms.vdouble(
+ 5.0,
+ 0.0,
+ 120.0
+ ),
+ sigma_par = cms.vdouble(
+ 5.0,
+ 0.0,
+ 120.0
+ )
+ ),
+ MEtoHarvest = cms.vstring(
+ 'DiMuMassVsMuMuPhi',
+ 'DiMuMassVsMuMuEta',
+ 'DiMuMassVsMuPlusPhi',
+ 'DiMuMassVsMuPlusEta',
+ 'DiMuMassVsMuMinusPhi',
+ 'DiMuMassVsMuMinusEta',
+ 'DiMuMassVsMuMuDeltaEta',
+ 'DiMuMassVsCosThetaCS'
+ )
+ )
diff --git a/DQMOffline/Alignment/src/DiMuonMassBiasClient.cc b/DQMOffline/Alignment/src/DiMuonMassBiasClient.cc
new file mode 100644
index 0000000000000..9d7f8ae87cf61
--- /dev/null
+++ b/DQMOffline/Alignment/src/DiMuonMassBiasClient.cc
@@ -0,0 +1,258 @@
+// user includes
+#include "DQMOffline/Alignment/interface/DiMuonMassBiasClient.h"
+#include "DataFormats/Histograms/interface/DQMToken.h"
+#include "FWCore/MessageLogger/interface/MessageLogger.h"
+#include "FWCore/ServiceRegistry/interface/Service.h"
+
+// RooFit includes
+#include "TCanvas.h"
+#include "RooAddPdf.h"
+#include "RooDataHist.h"
+#include "RooExponential.h"
+#include "RooGaussian.h"
+#include "RooPlot.h"
+#include "RooRealVar.h"
+#include "RooVoigtian.h"
+
+//-----------------------------------------------------------------------------------
+DiMuonMassBiasClient::DiMuonMassBiasClient(edm::ParameterSet const& iConfig)
+ : TopFolder_(iConfig.getParameter("FolderName")),
+ fitBackground_(iConfig.getParameter("fitBackground")),
+ debugMode_(iConfig.getParameter("debugMode")),
+ MEtoHarvest_(iConfig.getParameter>("MEtoHarvest"))
+//-----------------------------------------------------------------------------------
+{
+ edm::LogInfo("DiMuonMassBiasClient") << "DiMuonMassBiasClient::Constructing DiMuonMassBiasClient ";
+
+ consumes(edm::InputTag("DiMuonMassBiasMonitor", "DQMGenerationDiMuonMassBiasMonitorRun"));
+ consumes(edm::InputTag("DiMuonMassBiasMonitor", "DQMGenerationDiMuonMassBiasMonitorLumi"));
+
+ // fill the parameters for the fit
+ edm::ParameterSet fit_par = iConfig.getParameter("fit_par");
+ diMuonMassBias::fillArrayF(meanConfig_, fit_par, "mean_par");
+ diMuonMassBias::fillArrayF(widthConfig_, fit_par, "width_par");
+ diMuonMassBias::fillArrayF(sigmaConfig_, fit_par, "sigma_par");
+
+ if (debugMode_) {
+ edm::LogPrint("DiMuonMassBiasClient")
+ << "mean: " << meanConfig_[0] << " (" << meanConfig_[1] << "," << meanConfig_[2] << ") " << std::endl;
+ edm::LogPrint("DiMuonMassBiasClient")
+ << "width: " << widthConfig_[0] << " (" << widthConfig_[1] << "," << widthConfig_[2] << ")" << std::endl;
+ edm::LogPrint("DiMuonMassBiasClient")
+ << "sigma: " << sigmaConfig_[0] << " (" << sigmaConfig_[1] << "," << sigmaConfig_[2] << ")" << std::endl;
+ }
+}
+
+//-----------------------------------------------------------------------------------
+DiMuonMassBiasClient::~DiMuonMassBiasClient()
+//-----------------------------------------------------------------------------------
+{
+ edm::LogInfo("DiMuonMassBiasClient") << "DiMuonMassBiasClient::Deleting DiMuonMassBiasClient ";
+}
+
+//-----------------------------------------------------------------------------------
+void DiMuonMassBiasClient::beginJob(void)
+//-----------------------------------------------------------------------------------
+{
+ edm::LogInfo("DiMuonMassBiasClient") << "DiMuonMassBiasClient::beginJob done";
+}
+
+//-----------------------------------------------------------------------------------
+void DiMuonMassBiasClient::beginRun(edm::Run const& run, edm::EventSetup const& eSetup)
+//-----------------------------------------------------------------------------------
+{
+ edm::LogInfo("DiMuonMassBiasClient") << "DiMuonMassBiasClient:: Begining of Run";
+}
+
+//-----------------------------------------------------------------------------------
+void DiMuonMassBiasClient::bookMEs(DQMStore::IBooker& iBooker)
+//-----------------------------------------------------------------------------------
+{
+ iBooker.setCurrentFolder(TopFolder_ + "/DiMuonMassBiasMonitor/MassBias/Profiles");
+ for (const auto& [key, ME] : harvestTargets_) {
+ if (ME == nullptr) {
+ edm::LogError("DiMuonMassBiasClient") << "could not find MonitorElement for key: " << key << std::endl;
+ continue;
+ }
+
+ const auto& title = ME->getTitle();
+ const auto& xtitle = ME->getAxisTitle(1);
+ const auto& ytitle = ME->getAxisTitle(2);
+ const auto& nbins = ME->getNbinsX();
+ const auto& xmin = ME->getAxisMin(1);
+ const auto& xmax = ME->getAxisMax(1);
+ MonitorElement* meanToBook =
+ iBooker.book1D(("Mean" + key), (title + ";" + xtitle + ";" + ytitle), nbins, xmin, xmax);
+ meanProfiles_.insert({key, meanToBook});
+
+ MonitorElement* sigmaToBook =
+ iBooker.book1D(("Sigma" + key), (title + ";" + xtitle + ";" + "#sigma of " + ytitle), nbins, xmin, xmax);
+ widthProfiles_.insert({key, sigmaToBook});
+ }
+}
+
+//-----------------------------------------------------------------------------------
+void DiMuonMassBiasClient::getMEsToHarvest(DQMStore::IGetter& iGetter)
+//-----------------------------------------------------------------------------------
+{
+ std::string inFolder = TopFolder_ + "/DiMuonMassBiasMonitor/MassBias/";
+
+ //loop on the list of histograms to harvest
+ for (const auto& hname : MEtoHarvest_) {
+ MonitorElement* toHarvest = iGetter.get(inFolder + hname);
+
+ if (toHarvest == nullptr) {
+ edm::LogError("DiMuonMassBiasClient") << "could not find input MonitorElement: " << inFolder + hname << std::endl;
+ continue;
+ }
+
+ harvestTargets_.insert({hname, toHarvest});
+ }
+}
+
+//-----------------------------------------------------------------------------------
+void DiMuonMassBiasClient::dqmEndJob(DQMStore::IBooker& ibooker, DQMStore::IGetter& igetter)
+//-----------------------------------------------------------------------------------
+{
+ edm::LogInfo("DiMuonMassBiasClient") << "DiMuonMassBiasClient::endLuminosityBlock";
+
+ getMEsToHarvest(igetter);
+ bookMEs(ibooker);
+
+ for (const auto& [key, ME] : harvestTargets_) {
+ if (debugMode_)
+ edm::LogPrint("DiMuonMassBiasClient") << "dealing with key: " << key << std::endl;
+ TH2F* bareHisto = ME->getTH2F();
+ for (int bin = 1; bin <= ME->getNbinsX(); bin++) {
+ if (debugMode_)
+ edm::LogPrint("DiMuonMassBiasClient") << "dealing with bin: " << bin << std::endl;
+ TH1D* Proj = bareHisto->ProjectionY(Form("%s_proj_%i", key.c_str(), bin), bin, bin);
+ diMuonMassBias::fitOutputs results = fitVoigt(Proj);
+
+ // fill the mean profiles
+ const Measurement1D& bias = results.getBias();
+ meanProfiles_[key]->setBinContent(bin, bias.value());
+ meanProfiles_[key]->setBinError(bin, bias.error());
+
+ // fill the width profiles
+ const Measurement1D& width = results.getWidth();
+ widthProfiles_[key]->setBinContent(bin, width.value());
+ widthProfiles_[key]->setBinError(bin, width.error());
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------------
+diMuonMassBias::fitOutputs DiMuonMassBiasClient::fitVoigt(TH1* hist, const bool& fitBackground) const
+//-----------------------------------------------------------------------------------
+{
+ TCanvas* c1 = new TCanvas();
+ if (debugMode_) {
+ c1->Clear();
+ c1->SetLeftMargin(0.15);
+ c1->SetRightMargin(0.10);
+ }
+
+ // silence messages
+ RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);
+
+ Double_t xmin = hist->GetXaxis()->GetXmin();
+ Double_t xmax = hist->GetXaxis()->GetXmax();
+
+ if (debugMode_) {
+ edm::LogPrint("DiMuonMassBiasClient") << "fitting range: (" << xmin << "-" << xmax << ")" << std::endl;
+ }
+
+ RooRealVar InvMass("InvMass", "di-muon mass M(#mu^{+}#mu^{-}) [GeV]", xmin, xmax);
+ RooPlot* frame = InvMass.frame();
+ RooDataHist datahist("datahist", "datahist", InvMass, RooFit::Import(*hist));
+ datahist.plotOn(frame);
+
+ RooRealVar mean("#mu", "mean", meanConfig_[0], meanConfig_[1], meanConfig_[2]); //90.0, 60.0, 120.0
+ RooRealVar width("width", "width", widthConfig_[0], widthConfig_[1], widthConfig_[2]); // 5.0, 0.0, 120.0
+ RooRealVar sigma("#sigma", "sigma", sigmaConfig_[0], sigmaConfig_[1], sigmaConfig_[2]); // 5.0, 0.0, 120.0
+ RooVoigtian voigt("voigt", "voigt", InvMass, mean, width, sigma);
+
+ RooRealVar lambda("#lambda", "slope", -0.01, -100., 1.);
+ RooExponential expo("expo", "expo", InvMass, lambda);
+
+ RooRealVar b("N_{b}", "Number of background events", 0, hist->GetEntries() / 10.);
+ RooRealVar s("N_{s}", "Number of signal events", 0, hist->GetEntries());
+
+ RooAddPdf fullModel("fullModel", "Signal + Background Model", RooArgList(voigt, expo), RooArgList(s, b));
+ if (fitBackground_) {
+ fullModel.fitTo(datahist, RooFit::PrintLevel(-1), RooFit::Save(), RooFit::Range(xmin, xmax));
+ fullModel.plotOn(frame, RooFit::LineColor(kRed));
+ fullModel.plotOn(frame, RooFit::Components(expo), RooFit::LineStyle(kDashed)); //Other option
+ fullModel.paramOn(frame, RooFit::Layout(0.65, 0.90, 0.90));
+ } else {
+ voigt.fitTo(datahist, RooFit::PrintLevel(-1), RooFit::Save(), RooFit::Range(xmin, xmax));
+ voigt.plotOn(frame, RooFit::LineColor(kRed)); //this will show fit overlay on canvas
+ voigt.paramOn(frame, RooFit::Layout(0.65, 0.90, 0.90)); //this will display the fit parameters on canvas
+ }
+
+ // Redraw data on top and print / store everything
+ datahist.plotOn(frame);
+ frame->GetYaxis()->SetTitle("n. of events");
+ TString histName = hist->GetName();
+ frame->SetName("frame" + histName);
+ frame->SetTitle(hist->GetTitle());
+ frame->Draw();
+
+ if (debugMode_) {
+ c1->Print("fit_debug" + histName + ".pdf");
+ }
+ delete c1;
+
+ float mass_mean = mean.getVal();
+ float mass_sigma = sigma.getVal();
+
+ float mass_mean_err = mean.getError();
+ float mass_sigma_err = sigma.getError();
+
+ Measurement1D resultM(mass_mean, mass_mean_err);
+ Measurement1D resultW(mass_sigma, mass_sigma_err);
+
+ return diMuonMassBias::fitOutputs(resultM, resultW);
+}
+
+//-----------------------------------------------------------------------------------
+void DiMuonMassBiasClient::fillDescriptions(edm::ConfigurationDescriptions& descriptions)
+//-----------------------------------------------------------------------------------
+{
+ edm::ParameterSetDescription desc;
+ desc.add("FolderName", "DiMuonMassBiasMonitor");
+ desc.add("fitBackground", false);
+ desc.add("debugMode", false);
+
+ edm::ParameterSetDescription fit_par;
+ fit_par.add>("mean_par",
+ {std::numeric_limits::max(),
+ std::numeric_limits::max(),
+ std::numeric_limits::max()}); // par = mean
+
+ fit_par.add>("width_par",
+ {std::numeric_limits::max(),
+ std::numeric_limits::max(),
+ std::numeric_limits::max()}); // par = width
+
+ fit_par.add>("sigma_par",
+ {std::numeric_limits::max(),
+ std::numeric_limits::max(),
+ std::numeric_limits::max()}); // par = sigma
+
+ desc.add("fit_par", fit_par);
+
+ desc.add>("MEtoHarvest",
+ {"DiMuMassVsMuMuPhi",
+ "DiMuMassVsMuMuEta",
+ "DiMuMassVsMuPlusPhi",
+ "DiMuMassVsMuPlusEta",
+ "DiMuMassVsMuMinusPhi",
+ "DiMuMassVsMuMinusEta",
+ "DiMuMassVsMuMuDeltaEta",
+ "DiMuMassVsCosThetaCS"});
+ descriptions.addWithDefaultLabel(desc);
+}
+
+DEFINE_FWK_MODULE(DiMuonMassBiasClient);
diff --git a/DQMOffline/Alignment/src/DiMuonMassBiasMonitor.cc b/DQMOffline/Alignment/src/DiMuonMassBiasMonitor.cc
index ee6c7a70aa706..16befc138614d 100644
--- a/DQMOffline/Alignment/src/DiMuonMassBiasMonitor.cc
+++ b/DQMOffline/Alignment/src/DiMuonMassBiasMonitor.cc
@@ -6,6 +6,7 @@
#include "CommonTools/Statistics/interface/ChiSquaredProbability.h"
#include "DQMOffline/Alignment/interface/DiMuonMassBiasMonitor.h"
#include "DQMServices/Core/interface/DQMStore.h"
+#include "DataFormats/Histograms/interface/DQMToken.h"
#include "DataFormats/Math/interface/deltaR.h"
#include "DataFormats/TrackReco/interface/Track.h"
#include "DataFormats/TrackReco/interface/TrackBase.h"
@@ -33,7 +34,10 @@ DiMuonMassBiasMonitor::DiMuonMassBiasMonitor(const edm::ParameterSet& iConfig)
MEFolderName_(iConfig.getParameter("FolderName")),
decayMotherName_(iConfig.getParameter("decayMotherName")),
distanceScaleFactor_(iConfig.getParameter("distanceScaleFactor")),
- DiMuMassConfiguration_(iConfig.getParameter("DiMuMassConfig")) {}
+ DiMuMassConfiguration_(iConfig.getParameter("DiMuMassConfig")) {
+ produces("DQMGenerationDiMuonMassBiasMonitorRun");
+ produces("DQMGenerationDiMuonMassBiasMonitorLumi");
+}
void DiMuonMassBiasMonitor::bookHistograms(DQMStore::IBooker& iBooker, edm::Run const&, edm::EventSetup const&) {
iBooker.setCurrentFolder(MEFolderName_ + "/DiMuonMassBiasMonitor/MassBias");
diff --git a/DQMOffline/Alignment/src/DiMuonVertexMonitor.cc b/DQMOffline/Alignment/src/DiMuonVertexMonitor.cc
index cc8b691e16cc0..1a3efaf73fc33 100644
--- a/DQMOffline/Alignment/src/DiMuonVertexMonitor.cc
+++ b/DQMOffline/Alignment/src/DiMuonVertexMonitor.cc
@@ -171,7 +171,13 @@ void DiMuonVertexMonitor::analyze(const edm::Event& iEvent, const edm::EventSetu
VertexDistanceXY vertTool;
double distance = vertTool.distance(mumuTransientVtx, theMainVtx).value();
double dist_err = vertTool.distance(mumuTransientVtx, theMainVtx).error();
- float compatibility = vertTool.compatibility(mumuTransientVtx, theMainVtx);
+ float compatibility = 0.;
+
+ try {
+ compatibility = vertTool.compatibility(mumuTransientVtx, theMainVtx);
+ } catch (cms::Exception& er) {
+ LogTrace("DiMuonVertexMonitor") << "caught std::exception " << er.what() << std::endl;
+ }
hSVCompatibility_->Fill(compatibility);
hSVDist_->Fill(distance * cmToum);
@@ -182,7 +188,13 @@ void DiMuonVertexMonitor::analyze(const edm::Event& iEvent, const edm::EventSetu
VertexDistance3D vertTool3D;
double distance3D = vertTool3D.distance(mumuTransientVtx, theMainVtx).value();
double dist3D_err = vertTool3D.distance(mumuTransientVtx, theMainVtx).error();
- float compatibility3D = vertTool3D.compatibility(mumuTransientVtx, theMainVtx);
+ float compatibility3D = 0.;
+
+ try {
+ compatibility3D = vertTool3D.compatibility(mumuTransientVtx, theMainVtx);
+ } catch (cms::Exception& er) {
+ LogTrace("DiMuonVertexMonitor") << "caught std::exception " << er.what() << std::endl;
+ }
hSVCompatibility3D_->Fill(compatibility3D);
hSVDist3D_->Fill(distance3D * cmToum);
diff --git a/DQMOffline/Alignment/test/DiMuonVertexValidator_cfg.py b/DQMOffline/Alignment/test/DiMuonVertexValidator_cfg.py
index 3c2df50d86769..0c987e1600367 100644
--- a/DQMOffline/Alignment/test/DiMuonVertexValidator_cfg.py
+++ b/DQMOffline/Alignment/test/DiMuonVertexValidator_cfg.py
@@ -88,7 +88,8 @@
process.GlobalTag = GlobalTag(process.GlobalTag, options.globalTag, '')
process.load("DQMOffline.Configuration.AlCaRecoDQM_cff")
-process.seqALCARECOTkAlDiMuonAndVertex = cms.Sequence(process.ALCARECOTkAlDiMuonAndVertexVtxDQM + process.ALCARECOTkAlDiMuonMassBiasDQM)
+
+process.seqALCARECOTkAlDiMuonAndVertex = cms.Sequence(process.ALCARECOTkAlDiMuonAndVertexVtxDQM + process.ALCARECOTkAlDiMuonMassBiasDQM + process.ALCARECOTkAlDiMuonMassBiasClient)
process.dqmoffline_step = cms.EndPath(process.seqALCARECOTkAlDiMuonAndVertex)
process.DQMoutput_step = cms.EndPath(process.DQMoutput)
diff --git a/DQMOffline/Alignment/test/DiMuonVertex_HARVESTING.py b/DQMOffline/Alignment/test/DiMuonVertex_HARVESTING.py
index fd33f531b28e1..5ef58f4e10de4 100644
--- a/DQMOffline/Alignment/test/DiMuonVertex_HARVESTING.py
+++ b/DQMOffline/Alignment/test/DiMuonVertex_HARVESTING.py
@@ -93,6 +93,32 @@
process.dqmsave_step = cms.Path(process.DQMSaver)
+# the module to harvest
+process.DiMuonMassBiasClient = cms.EDProducer("DiMuonMassBiasClient",
+ FolderName = cms.string('AlCaReco/TkAlDiMuonAndVertex'),
+ fitBackground = cms.bool(False),
+ debugMode = cms.bool(True),
+ fit_par = cms.PSet(
+ mean_par = cms.vdouble(90.,60.,120.),
+ width_par = cms.vdouble(5.0,0.0,120.0),
+ sigma_par = cms.vdouble(5.0,0.0,120.0)
+ ),
+ MEtoHarvest = cms.vstring(
+ 'DiMuMassVsMuMuPhi',
+ 'DiMuMassVsMuMuEta',
+ 'DiMuMassVsMuPlusPhi',
+ 'DiMuMassVsMuPlusEta',
+ 'DiMuMassVsMuMinusPhi',
+ 'DiMuMassVsMuMinusEta',
+ 'DiMuMassVsMuMuDeltaEta',
+ 'DiMuMassVsCosThetaCS'
+ )
+ )
+
+process.diMuonBiasClient = cms.Sequence(process.DiMuonMassBiasClient)
+# trick to run the harvester module
+process.alcaHarvesting.insert(1,process.diMuonBiasClient)
+
# Schedule definition
process.schedule = cms.Schedule(process.alcaHarvesting,process.dqmsave_step)
from PhysicsTools.PatAlgos.tools.helpers import associatePatAlgosToolsTask