00001 #include "GeSpectrum.h"
00002 #include "RegisterModule.inc"
00003 #include "TPulseIsland.h"
00004 #include "TGlobalData.h"
00005 #include "TSetupData.h"
00006 #include "ModulesOptions.h"
00007 #include "definitions.h"
00008 #include "SetupNavigator.h"
00009 #include "ExportPulse.h"
00010 #include "PulseCandidateFinder.h"
00011
00012 #include "TH1I.h"
00013 #include "TH2D.h"
00014 #include "TF1.h"
00015 #include "TDirectory.h"
00016
00017 #include <stdexcept>
00018 #include <iostream>
00019 #include <algorithm>
00020 #include <numeric>
00021 #include <cmath>
00022 #include <climits>
00023 #include <string>
00024 #include <sstream>
00025
00026 const IDs::channel GeSpectrum::fGeS(IDs::kGe, IDs::kSlow);
00027 const IDs::channel GeSpectrum::fGeF(IDs::kGe, IDs::kFast);
00028 const IDs::channel GeSpectrum::fMuSc(IDs::kMuSc, IDs::kNotApplicable);
00029
00030 GeSpectrum::GeSpectrum(modules::options* opts) :
00031 BaseModule("GeSpectrum",opts),
00032 fHist_Energy(NULL), fHist_Time(NULL), fHist_MoreTime(NULL),
00033 fHist_EnergyOOT(NULL), fHist_EnergyFarOOT(NULL), fHist_TimeEnergy(NULL), fHist_MeanTOffset(NULL),
00034 fMBAmpGe(SetupNavigator::Instance()->GetPedestal(fGeS), TSetupData::Instance()->GetTriggerPolarity(TSetupData::Instance()->GetBankName(fGeS.str()))),
00035 fMBAmpMuSc(SetupNavigator::Instance()->GetPedestal(fMuSc), TSetupData::Instance()->GetTriggerPolarity(TSetupData::Instance()->GetBankName(fMuSc.str()))),
00036 fCFTimeGe(SetupNavigator::Instance()->GetPedestal(fGeF),
00037 TSetupData::Instance()->GetTriggerPolarity(TSetupData::Instance()->GetBankName(fGeF.str())),
00038 TSetupData::Instance()->GetClockTick(TSetupData::Instance()->GetBankName(fGeF.str())),
00039 SetupNavigator::Instance()->GetCoarseTimeOffset(IDs::source(fGeF, IDs::generator(opts->GetString("gef_gen"), opts->GetString("gef_cfg")))),
00040 opts->GetDouble("gef_cf")),
00041 fCFTimeMuSc(SetupNavigator::Instance()->GetPedestal(fMuSc),
00042 TSetupData::Instance()->GetTriggerPolarity(TSetupData::Instance()->GetBankName(fMuSc.str())),
00043 TSetupData::Instance()->GetClockTick(TSetupData::Instance()->GetBankName(fMuSc.str())),
00044 0.,
00045 opts->GetDouble("musc_cf")),
00046 fADC2Energy(new TF1("adc2energy","[0]*x+[1]")),
00047 fTimeWindow_Small(1000.), fTimeWindow_Big(5000.), fPileupProtectionWindow(15000.) {
00048 const static int nbins = std::pow(2.,14);
00049 const std::pair<double,double> adc2energy_par = SetupNavigator::Instance()->GetEnergyCalibrationConstants(IDs::channel("Ge-S"));
00050 fADC2Energy->SetParameters(adc2energy_par.first, adc2energy_par.second);
00051 TDirectory* cwd = TDirectory::CurrentDirectory();
00052 dir->cd();
00053 fHist_ADC = new TH1D("hADC", "Energy of Gammas;Energy (ADC);Counts", nbins, 0., nbins);
00054
00055 double energy_bin_width = 0.1;
00056 double min_energy = 0;
00057 double max_energy = 2000;
00058 int n_energy_bins = (max_energy - min_energy) / energy_bin_width;
00059 fHist_Energy = new TH1D("hEnergy", "Energy of Gammas;Energy (keV);Counts", n_energy_bins, min_energy, max_energy);
00060 fHist_Time = new TH1D("hTime", "Time of Gammas within Energy Window", 1000, -10000., 10000.);
00061 fHist_MoreTime = new TH1D("hMoreTime", "Time of Gammas within Energy Window (Wide)", 1000, -100000., 100000.);
00062 fHist_ADCOOT = new TH1D("hADCOOT", "Energy of Gammas outside of Time Window;Energy (ADC);Counts", nbins, 0., nbins);
00063 fHist_EnergyOOT = new TH1D("hEnergyOOT", "Energy of Gammas outside of Time Window;Energy (keV);Counts", n_energy_bins, min_energy, max_energy);
00064 fHist_ADCFarOOT = new TH1D("hADCFarOOT", "Energy of Gammas far from Muons;Energy (ADC);Counts", nbins, 0., nbins);
00065 fHist_EnergyFarOOT = new TH1D("hEnergyFarOOT", "Energy of Gammas far from Muons;Energy (keV);Counts", n_energy_bins, min_energy, max_energy);
00066 fHist_TimeOOT = new TH1D("hTimeOOT", "Time of Gammas outside of Time Window", 1000., -2.*fTimeWindow_Small, 2.*fTimeWindow_Small);
00067 fHist_TimeFarOOT = new TH1D("hTimeFarOOT", "Time of Gammas far from Muons", 1000., -100.*fTimeWindow_Big, 100.*fTimeWindow_Big);
00068 fHist_TimeADC = new TH2D("hTimeADC", "Energy of Gammas within Time Window;Energy (ADC);Time (ns);Counts", 100, -fTimeWindow_Small, fTimeWindow_Small, nbins, 0., nbins);
00069 fHist_TimeEnergy = new TH2D("hTimeEnergy", "Energy of Gammas within Time Window;Energy (keV);Time (ns);Counts", 100, -fTimeWindow_Small, fTimeWindow_Small, n_energy_bins, min_energy, max_energy);
00070 fHist_MeanTOffset = new TH1D("hMeanTOffset", "Mean offset from nearest muon taken over MIDAS event", 4000, -4.*fTimeWindow_Big, 4.*fTimeWindow_Big);
00071 cwd->cd();
00072 ThrowIfInputsInsane(opts);
00073 }
00074
00075 GeSpectrum::~GeSpectrum(){
00076 }
00077
00078
00079
00080
00081 int GeSpectrum::BeforeFirstEntry(TGlobalData* gData, const TSetupData *setup){
00082 return 0;
00083 }
00084
00085
00086
00087 int GeSpectrum::ProcessEntry(TGlobalData* gData, const TSetupData *setup){
00088
00089 static const std::string bank_musc = TSetupData::Instance()->GetBankName(fMuSc.str());
00090 static const std::string bank_ges = TSetupData::Instance()->GetBankName(fGeS.str());
00091 static const std::string bank_gef = TSetupData::Instance()->GetBankName(fGeF.str());
00092
00093 const std::map< std::string, std::vector<TPulseIsland*> >& TPIMap = gData->fPulseIslandToChannelMap;
00094 ThrowIfGeInsane(TPIMap.at(bank_ges), TPIMap.at(bank_gef));
00095 if (!(TPIMap.count(bank_musc) && TPIMap.count(bank_ges) && TPIMap.count(bank_gef)))
00096 return 0;
00097 else if (TPIMap.at(bank_musc).size() == 0 || TPIMap.at(bank_ges).size() == 0 || TPIMap.at(bank_gef).size() == 0)
00098 return 0;
00099
00100 const std::vector<double> muScTimes = CalculateTimes(fMuSc, TPIMap.at(bank_musc));
00101 const std::vector<double> muScEnergies = CalculateEnergies(fMuSc, TPIMap.at(bank_musc));
00102 const std::vector<double> geTimes = CalculateTimes(fGeF, TPIMap.at(bank_gef));
00103 const std::vector<double> geEnergies = CalculateEnergies(fGeS, TPIMap.at(bank_ges));
00104
00105 std::vector<double> muScTimesPP(muScTimes), muScEnergiesPP(muScEnergies);
00106 RemovePileupMuScPulses(muScTimesPP, muScEnergiesPP);
00107
00108
00109
00110
00111 TH1I hTOff("hTOff", "Time Offset", 4000, -20000., 20000.);
00112 for (std::vector<double>::const_iterator geT = geTimes.begin(), prev = muScTimesPP.begin(), next;
00113 geT != geTimes.end();
00114 ++geT) {
00115 static const double unfound = 1e9;
00116 double dt[2] = {unfound, unfound}, &dt_prev = dt[0], &dt_next = dt[1];
00117 std::vector<double>::const_iterator end = muScTimesPP.end();
00118 next = std::upper_bound(prev, end, *geT);
00119 prev = next - 1;
00120 if (next == muScTimesPP.end())
00121 dt_prev = *geT - *prev;
00122 else if (next == muScTimesPP.begin()) {
00123 dt_next = *geT - *next;
00124 prev = next;
00125 } else {
00126 dt_prev = *geT - *prev;
00127 dt_next = *geT - *next;
00128 }
00129
00130 for (unsigned int it = 0; it < 2; ++it)
00131 if (std::abs(dt[it]) < 20000.)
00132 hTOff.Fill(dt[it]);
00133
00134 }
00135 double tOff = 0.;
00136 if (hTOff.Integral() > 1) {
00137 tOff = hTOff.GetMean();
00138 fHist_MeanTOffset->Fill(tOff);
00139 }
00140
00141
00142
00143
00144
00145 for (std::vector<double>::const_iterator geT = geTimes.begin(), geE = geEnergies.begin(), prev = muScTimesPP.begin(), next;
00146 geT != geTimes.end() && geE != geEnergies.end();
00147 ++geT, ++geE) {
00148 bool prev_found = false, next_found = false;
00149 double dt_prev, dt_next;
00150
00151
00152
00153 std::vector<double>::const_iterator end = muScTimesPP.end();
00154 next = std::upper_bound(prev, end, *geT);
00155 prev = next - 1;
00156 if (next == muScTimesPP.end()) {
00157 dt_prev = *geT - *prev;
00158 prev_found = true;
00159 } else if (next == muScTimesPP.begin()) {
00160 dt_next = *geT - *next;
00161 next_found = true;
00162 } else {
00163
00164 dt_prev = *geT - *prev;
00165 dt_next = *geT - *next;
00166 prev_found = next_found = true;
00167 }
00168
00169
00170 if (( !prev_found || dt_prev > fTimeWindow_Big) && ( !next_found || dt_next < -fTimeWindow_Big) ) {
00171 fHist_ADCFarOOT->Fill(*geE);
00172 fHist_EnergyFarOOT->Fill(fADC2Energy->Eval(*geE));
00173 } else if ( (!prev_found || dt_prev > fTimeWindow_Small) && (!next_found || dt_next < -fTimeWindow_Small) ) {
00174 fHist_ADCOOT->Fill(*geE);
00175 fHist_EnergyOOT->Fill(fADC2Energy->Eval(*geE));
00176 } else {
00177 if (prev_found && dt_prev <= fTimeWindow_Small) {
00178 fHist_TimeADC->Fill(dt_prev, *geE);
00179 fHist_TimeEnergy->Fill(dt_prev, fADC2Energy->Eval(*geE));
00180 } else if (next_found && dt_next >= -fTimeWindow_Small) {
00181 fHist_TimeADC->Fill(dt_next, *geE);
00182 fHist_TimeEnergy->Fill(dt_next, fADC2Energy->Eval(*geE));
00183 } else {
00184 std::cout << "WARNING: Unexpected branch! Prev: (" << prev_found << ", " << dt_prev << "), Next: (" << next_found << ", " << dt_next << ")" << std::endl;
00185 }
00186 }
00187 fHist_ADC->Fill(*geE);
00188 fHist_Energy->Fill(fADC2Energy->Eval(*geE));
00189
00190 if (prev_found) {
00191 if (dt_prev > fTimeWindow_Big)
00192 fHist_TimeFarOOT->Fill(dt_prev);
00193 else if (dt_prev > fTimeWindow_Small)
00194 fHist_TimeOOT->Fill(dt_prev);
00195 }
00196 if (next_found) {
00197 if (dt_next < -fTimeWindow_Big)
00198 fHist_TimeFarOOT->Fill(dt_next);
00199 else if (dt_next < -fTimeWindow_Small)
00200 fHist_TimeOOT->Fill(dt_next);
00201 }
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 }
00219 return 0;
00220 }
00221
00222
00223
00224
00225 int GeSpectrum::AfterLastEntry(TGlobalData* gData, const TSetupData *setup){
00226 return 0;
00227 }
00228
00229
00230 std::vector<double> GeSpectrum::CalculateTimes(const IDs::channel& ch, const std::vector<TPulseIsland*>& tpis) {
00231 std::vector<double> t;
00232 if (ch == fMuSc)
00233 for (unsigned int i = 0; i < tpis.size(); ++i)
00234 t.push_back(fCFTimeMuSc(tpis[i]));
00235 else if (ch == fGeF)
00236 for (unsigned int i = 0; i < tpis.size(); ++i)
00237 t.push_back(fCFTimeGe(tpis[i]));
00238 else
00239 throw std::logic_error("GeSpectrum: Invalid channel to calculate times for.");
00240 return t;
00241 }
00242
00243
00244 std::vector<double> GeSpectrum::CalculateEnergies(const IDs::channel& ch, const std::vector<TPulseIsland*>& tpis) {
00245 std::vector<double> e;
00246 if (ch == fGeS)
00247 for (unsigned int i = 0; i < tpis.size(); ++i)
00248 e.push_back(fMBAmpGe(tpis[i]));
00249 else if (ch == fMuSc)
00250 for (unsigned int i = 0; i < tpis.size(); ++i)
00251 e.push_back(fMBAmpMuSc(tpis[i]));
00252 else
00253 throw std::logic_error("GeSpectrum: Invalid channel to calculate energies for.");
00254 return e;
00255 }
00256
00257
00258 void GeSpectrum::ThrowIfGeInsane(const std::vector<TPulseIsland*>& ge1s, const std::vector<TPulseIsland*>& ge2s) {
00259 if (ge1s.size() != ge2s.size())
00260 throw std::logic_error("Fast and slow vectors are not same size!");
00261 for (std::vector<TPulseIsland*>::const_iterator ge1 = ge1s.begin(), ge2 = ge2s.begin(); ge1 != ge1s.end(); ++ge1, ++ge2)
00262 if ((*ge1)->GetTimeStamp() != (*ge2)->GetTimeStamp())
00263 throw std::logic_error("Fast and slow timestamps don't match up when getting time");
00264 }
00265
00266 void GeSpectrum::ThrowIfInputsInsane(const modules::options* opts) {
00267 const std::string& gef_cfg = opts->GetString("gef_cfg");
00268 const double gef_cf = opts->GetDouble("gef_cf");
00269 const double musc_cf = opts->GetDouble("musc_cf");
00270 const std::string cf_str("constant_fraction=");
00271 std::stringstream ss(gef_cfg.substr(gef_cfg.find(cf_str) + cf_str.size()));
00272 double cf;
00273 ss >> cf;
00274 if (cf != gef_cf)
00275 throw std::logic_error("GeSpectrum: GeF CF in options don't match.");
00276 if (gef_cf <= 0. || gef_cf > 1. || musc_cf <= 0. || musc_cf > 1.)
00277 throw std::logic_error("GeSpectrum: CF are out of reasonable bounds (0. to 1.).");
00278 }
00279
00280 void GeSpectrum::RemovePileupMuScPulses(std::vector<double>& t, std::vector<double>& e) {
00281 if (t.empty()) return;
00282 std::vector<bool> rm(t.size(), false);
00283 if (t.front() < fPileupProtectionWindow) rm.front() = true;
00284 for (unsigned int i = 1; i < t.size(); ++i)
00285 if (t[i] - t[i-1] < fPileupProtectionWindow)
00286 rm[i] = rm[i-1] = true;
00287 rm.back() = true;
00288 for (unsigned int i = 0; i < t.size(); ++i) {
00289 if (rm[i]) {
00290 t.erase(t.begin()+i);
00291 e.erase(e.begin()+i);
00292 rm.erase(rm.begin()+i);
00293 --i;
00294 }
00295 }
00296 }
00297
00298 ALCAP_REGISTER_MODULE(GeSpectrum, musc_cf, gef_gen, gef_cfg, gef_cf);