/* This file is part of MAUS: http://micewww.pp.rl.ac.uk:8080/projects/maus * * MAUS is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MAUS is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MAUS. If not, see . * */ #include #include "src/common_cpp/DataStructure/MCEvent.hh" #include "src/common_cpp/DataStructure/ReconEvent.hh" #include "src/common_cpp/JsonCppProcessors/SpillProcessor.hh" #include "src/map/MapCppTrackerMCDigitization/MapCppTrackerMCDigitization.hh" #include "src/common_cpp/Recon/SciFi/SciFiLookup.hh" #include "src/common_cpp/API/PyWrapMapBase.hh" #include "Utils/Squeak.hh" namespace MAUS { PyMODINIT_FUNC init_MapCppTrackerMCDigitization(void) { PyWrapMapBase::PyWrapMapBaseModInit ("MapCppTrackerMCDigitization", "", "", "", ""); } MapCppTrackerMCDigitization::MapCppTrackerMCDigitization() : MapBase("MapCppTrackerMCDigitization"), _chan_map(_n_entries) { } MapCppTrackerMCDigitization::~MapCppTrackerMCDigitization() { } void MapCppTrackerMCDigitization::_birth(const std::string& argJsonConfigDocument) { if (!Globals::HasInstance()) { GlobalsManager::InitialiseGlobals(argJsonConfigDocument); } static MiceModule* mice_modules = Globals::GetMonteCarloMiceModules(); modules = mice_modules->findModulesByPropertyString("SensitiveDetector", "SciFi"); Json::Value *json = Globals::GetConfigurationCards(); // Load constants. // _disc_sim_on = (*json)["SciFi_DiscOn"].asInt(); // _SciFiDisCut = (*json)["SciFiDisCut"].asDouble(); _SciFiCalibrateMC = (*json)["SciFiCalibrateMC"].asBool(); _SciFiadcBits = (*json)["SciFiadcBits"].asDouble(); _SciFivlpcRes = (*json)["SciFivlpcRes"].asDouble(); _SciFiNPECut = (*json)["SciFiNoiseNPECut"].asDouble(); _SciFitdcBits = (*json)["SciFitdcBits"].asDouble(); _SciFivlpcTimeRes = (*json)["SciFivlpcTimeRes"].asDouble(); _SciFitdcFactor = (*json)["SciFitdcFactor"].asDouble(); _SciFiFiberConvFactor = (*json)["SciFiFiberConvFactor"].asDouble(); _SciFiFiberTrappingEff = (*json)["SciFiFiberTrappingEff"].asDouble(); _SciFiFiberMirrorEff = (*json)["SciFiFiberMirrorEff"].asDouble(); _SciFivlpcQE = (*json)["SciFivlpcQE"].asDouble(); _SciFiFiberTransmissionEff = (*json)["SciFiFiberTransmissionEff"].asDouble(); _SciFiMUXTransmissionEff = (*json)["SciFiMUXTransmissionEff"].asDouble(); _eV_to_phe = _SciFiFiberConvFactor * _SciFiFiberTrappingEff * ( 1.0 + _SciFiFiberMirrorEff ) * _SciFiFiberTransmissionEff * _SciFiMUXTransmissionEff * _SciFivlpcQE; _config_dir = (*json)["SciFiConfigDir"].asString(); _mapping_file = (*json)["SciFiMappingFileName"].asString(); _calibration_file = (*json)["SciFiCalibrationFileName"].asString(); _bad_chan_file = (*json)["SciFiBadChannelsFileName"].asString(); std::cout << "INFO: MapCppTrackerDigits: Map file: " << _mapping_file << ". Calib file: " << _calibration_file << ". Bad Chan file: " << _bad_chan_file << " from " << _config_dir << "\n"; bool map = load_mapping(_mapping_file); bool calib = load_calibration(_calibration_file); bool bad_channels = load_bad_channels(_bad_chan_file); if ( !calib || !map || !bad_channels ) { throw(Exceptions::Exception(Exceptions::recoverable, "Could not load Tracker calibration, mapping or bad channel list.", "RealDataDigitization::process")); } } void MapCppTrackerMCDigitization::_death() { } void MapCppTrackerMCDigitization::_process(MAUS::Data* data) const { Spill& spill = *(data->GetSpill()); if (!spill.GetMCEvents()) { throw MAUS::Exceptions::Exception(Exceptions::recoverable, "MC event array not initialised.", "MapCppTrackerMCDigitization::process"); } // ================= Reconstruction ========================= // Check the Recon event array is initialised, and if not make it so if ( !spill.GetReconEvents() ) { ReconEventPArray* revts = new ReconEventPArray(); spill.SetReconEvents(revts); } // Construct digits from hits for each MC event for ( size_t event_i = 0; event_i < spill.GetMCEventSize(); event_i++ ) { MCEvent *mc_evt = spill.GetMCEvents()->at(event_i); SciFiDigitPArray digits; if ( mc_evt->GetSciFiHits() ) { construct_digits(mc_evt->GetSciFiHits(), spill.GetSpillNumber(), event_i, digits); } // Adding in effects from noise in VLPC if ( mc_evt->GetSciFiNoiseHits() ) { add_noise(mc_evt->GetSciFiNoiseHits(), digits); } // Smearing NPE results from ADC resolution if ( _SciFiCalibrateMC ) { for (size_t digit_j = 0; digit_j < digits.size(); digit_j++) { // std::cerr << "get: " << digits.at(digit_j)->get_npe() << std::endl; double ret_npe = compute_adc_counts(digits.at(digit_j)); // std::cerr << "returned: " << ret_npe << std::endl; digits.at(digit_j)->set_npe(ret_npe); } } // For running with discriminators only // if (_disc_sim_on == 1) { // discriminator(digits); // } // Make a SciFiEvent to hold the digits produced SciFiEvent *sf_evt = new SciFiEvent(); sf_evt->set_digits(digits); // If there is already a Recon event associated with this MC event, add the SciFiEvent to it, // otherwise make a new Recon event to hold the SciFiEvent if ( spill.GetReconEvents()->size() > event_i ) { spill.GetReconEvents()->at(event_i)->SetSciFiEvent(sf_evt); } else { ReconEvent *revt = new ReconEvent(); revt->SetPartEventNumber(event_i); revt->SetSciFiEvent(sf_evt); spill.GetReconEvents()->push_back(revt); } } } // void MapCppTrackerMCDigitization::discriminator(SciFiDigitPArray &digits) const { // std::vector cut_pos; // for (unsigned int i = 0; i < digits.size(); i++) { // if (_SciFiDisCut < digits.at(i)->get_npe()) { // // std::cerr << "Good Point: " << digits.at(i)->get_npe() << "\n"; // digits.at(i)->set_npe(10.0); // } else { // // std::cerr << "Bad Point: " << digits.at(i)->get_npe() << "\n"; // std::cerr << "This shouldn't run.\n"; // digits.at(i)->set_npe(-10.0); // cut_pos.push_back(i); // } // } // for (unsigned int j = 0; j < cut_pos.size(); j++) { // int pos_j = cut_pos.size() - j - 1; // // std::cerr<< pos_j << " of " << cut_pos.size() << "\n"; // int k = cut_pos.at(pos_j); // digits.erase(digits.begin()+k); // } // } void MapCppTrackerMCDigitization::construct_digits(SciFiHitArray *hits, int spill_num, int event_num, SciFiDigitPArray &digits) const { SciFiLookup lookup; for ( unsigned int hit_i = 0; hit_i < hits->size(); hit_i++ ) { if ( !hits->at(hit_i).GetChannelId()->GetUsed() ) { SciFiHit *a_hit = &hits->at(hit_i); a_hit->GetChannelId()->SetUsed(true); int chanNo = compute_chan_no(a_hit); // Get nPE from this hit. double edep = a_hit->GetEnergyDeposited(); double nPE = edep*_eV_to_phe; // Compute tdc count. double time1 = a_hit->GetTime(); // int tdcCounts = compute_tdc_counts(time1); // Pull tracker/station/plane information from geometry int tracker = a_hit->GetChannelId()->GetTrackerNumber(); int station = a_hit->GetChannelId()->GetStationNumber(); int plane = a_hit->GetChannelId()->GetPlaneNumber(); // Create Digit for use with MC lookup, will update NPE later SciFiDigit *a_digit = new SciFiDigit(spill_num, event_num, tracker, station, plane, chanNo, nPE, time1); a_hit->GetChannelId()->SetID(lookup.get_digit_id(a_digit)); // Loop over all the other hits. for ( unsigned int hit_j = hit_i+1; hit_j < hits->size(); hit_j++ ) { if ( check_param(&(*hits)[hit_i], &(*hits)[hit_j]) ) { MAUS::SciFiHit *same_digit = &(*hits)[hit_j]; double edep_j = same_digit->GetEnergyDeposited(); nPE += edep_j*_eV_to_phe; same_digit->GetChannelId()->SetUsed(true); same_digit->GetChannelId()->SetID(lookup.get_digit_id(a_digit)); } } // ends loop over all the array nPE = floor(nPE+0.5); a_digit->set_npe(nPE); a_digit->set_adc(150); // Just to test it digits.push_back(a_digit); } } // ends 'for' loop over hits } void MapCppTrackerMCDigitization::add_noise(SciFiNoiseHitArray *noises, SciFiDigitPArray &digits) const { /************************************************************************** * Function checks which channel has noise against which channel has a * digit. If noise is in the same channel as a digit then the noise is * added to the digit, else noise is added as a new digit. **************************************************************************/ std::map digit_map; for (size_t digit_i = 0; digit_i < digits.size(); digit_i++) { int track_id = digits.at(digit_i)->get_tracker(); int stat_id = digits.at(digit_i)->get_station(); int plane_id = digits.at(digit_i)->get_plane(); int chan_id = digits.at(digit_i)->get_channel(); int key = chan_id + 1000*plane_id + 10000*stat_id + 100000*track_id; digit_map[key] = digit_i; } for (size_t noise_j = 0; noise_j < noises->size(); noise_j++) { int track_id = noises->at(noise_j).GetTracker(); int stat_id = noises->at(noise_j).GetStation(); int plane_id = noises->at(noise_j).GetPlane(); int chan_id = noises->at(noise_j).GetChannel(); int key = chan_id + 1000*plane_id + 10000*stat_id + 100000*track_id; if (digit_map.find(key) != digit_map.end()) { double digit_npe = digits.at(digit_map[key])->get_npe(); double noise_npe = noises->at(noise_j).GetNPE(); digits.at(digit_map[key])->set_npe(digit_npe + noise_npe); } else { SciFiDigit* a_digit = new SciFiDigit(noises->at(noise_j).GetSpill(), noises->at(noise_j).GetEvent(), noises->at(noise_j).GetTracker(), noises->at(noise_j).GetStation(), noises->at(noise_j).GetPlane(), noises->at(noise_j).GetChannel(), noises->at(noise_j).GetNPE(), noises->at(noise_j).GetTime()); a_digit->set_adc(57); digits.push_back(a_digit); } } } int MapCppTrackerMCDigitization::compute_tdc_counts(double time1) const { double tmpcounts; tmpcounts = CLHEP::RandGauss::shoot(time1, _SciFivlpcTimeRes)*_SciFitdcFactor; // Check for saturation of TDCs if ( tmpcounts > pow(2.0, _SciFitdcBits) - 1.0 ) { tmpcounts = pow(2.0, _SciFitdcBits) - 1.0; } int tdcCounts = static_cast (floor(tmpcounts)); return tdcCounts; } int MapCppTrackerMCDigitization::compute_chan_no(MAUS::SciFiHit *ahit) const { // This is the channel number computed from the fibre number. int fiberNumber = ahit->GetChannelId()->GetFibreNumber(); int chanNo = static_cast (floor(fiberNumber/7.0)); return chanNo; } double MapCppTrackerMCDigitization::compute_adc_counts(MAUS::SciFiDigit *digit) const { double numb_pe = digit->get_npe(); if ( numb_pe == 0 ) return 0; // Throw the dice and generate VLPC output numb_pe = CLHEP::RandGauss::shoot(numb_pe, _SciFivlpcRes); if (numb_pe <= 0.0) { return 0; } // Gathering calibration information double _SciFiadcGain = 0; double _SciFiadcPed = 0; // encode the tracker,station,plane,channel into a string for lookup std::stringstream ss; ss << digit->get_tracker() << digit->get_station() << digit->get_plane() << digit->get_channel(); std::map::const_iterator _UIdit = _uidlookup.find(ss.str()); // get the unique ID (board, bank, channel) for this tracker,station,plane,channel int this_uid = _UIdit->second; // catch errors in lookup if (static_cast(this_uid) > (_chan_map.size() - 1)) { std::cerr << "WARNING:: MapCppTrackerMCDigitization: Channel ID outside bounds of map\n"; std::cerr << "UId: " << this_uid << ", size: " << _chan_map.size() << std::endl; return -10.0; } // get the board, bank, channel from the ID int this_board = this_uid/(_number_channels*_banks_per_board); int rem = this_uid%(_number_channels*_banks_per_board); int this_bank = rem/(_number_channels); int this_chan = rem%(_number_channels); // the f.e. bank for calibration lookup int cali_bank = this_board*_banks_per_board + this_bank; _SciFiadcGain = _calibration[cali_bank][this_chan]["adc_gain"].asDouble(); _SciFiadcPed = _calibration[cali_bank][this_chan]["adc_pedestal"].asDouble(); if (_SciFiadcGain == 0 || _SciFiadcPed == 0) { // std::cerr << "Zero Gain|Pedestal: t:stn:pln:chn: " << digit->get_tracker() // << " " << digit->get_station() // << " " << digit->get_plane() << " " << digit->get_channel() // << " gain:ped: " << _SciFiadcGain << " " << _SciFiadcPed // << " board:bank:chan: " << this_board << " " << this_bank << " " << this_chan // << " corr: bnk:g:p " << cali_bank << " " << _SciFiadcGain << " " << _SciFiadcPed // << std::endl; return numb_pe = -10.0; } if (!_good_chan[cali_bank][this_chan]) { // std::cerr << "...bad chan: " << cali_bank << " " << this_chan << std::endl; return numb_pe = -10.0; } // Check for saturation of ADCs double tmpcounts = (numb_pe * _SciFiadcGain) + _SciFiadcPed; if ( tmpcounts > pow(2.0, _SciFiadcBits) - 1.0 ) tmpcounts = pow(2.0, _SciFiadcBits) - 1.0; tmpcounts = (floor(tmpcounts)); numb_pe = (tmpcounts - _SciFiadcPed)/_SciFiadcGain; return numb_pe; } bool MapCppTrackerMCDigitization::check_param(MAUS::SciFiHit *hit1, MAUS::SciFiHit *hit2) const { if ( hit2->GetChannelId()->GetUsed() ) { return false; } else { // two hits passed to the check_param function int tracker1 = hit1->GetChannelId()->GetTrackerNumber(); int tracker2 = hit2->GetChannelId()->GetTrackerNumber(); int station1 = hit1->GetChannelId()->GetStationNumber(); int station2 = hit2->GetChannelId()->GetStationNumber(); int plane1 = hit1->GetChannelId()->GetPlaneNumber(); int plane2 = hit2->GetChannelId()->GetPlaneNumber(); double chan1 = compute_chan_no(hit1); double chan2 = compute_chan_no(hit2); // check whether the hits belong to the same tracker, station, plane and channel if ( tracker1 == tracker2 && station1 == station2 && plane1 == plane2 && chan1 == chan2 ) { return true; } else { return false; } } } bool MapCppTrackerMCDigitization::load_calibration(std::string file) { std::string fname = _config_dir+"/files/calibration/"+file; std::ifstream inf(fname.c_str()); if (!inf) { throw(Exceptions::Exception(Exceptions::recoverable, "Could not load Tracker Calibration.", "MapCppTrackerMCDigitization::load_calibration")); } std::string calib((std::istreambuf_iterator(inf)), std::istreambuf_iterator()); Json::Reader reader; Json::Value calibration_data; if (!reader.parse(calib, calibration_data)) return false; size_t n_channels = calibration_data.size(); for ( Json::Value::ArrayIndex i = 0; i < n_channels; ++i ) { int bank = calibration_data[i]["bank"].asInt(); int channel_n = calibration_data[i]["channel"].asInt(); double adc_pedestal = calibration_data[i]["adc_pedestal"].asDouble(); double adc_gain = calibration_data[i]["adc_gain"].asDouble(); double tdc_pedestal = calibration_data[i]["tdc_pedestal"].asDouble(); double tdc_gain = calibration_data[i]["tdc_gain"].asDouble(); Json::Value channel; channel["adc_pedestal"] = adc_pedestal; channel["adc_gain"] = adc_gain; channel["tdc_pedestal"] = tdc_pedestal; channel["tdc_gain"] = tdc_gain; _calibration[bank][channel_n] = channel; } return true; } bool MapCppTrackerMCDigitization::load_mapping(std::string file) { std::string fname = _config_dir+"/files/cabling/"+file; std::ifstream inf(fname.c_str()); if (!inf) { throw(Exceptions::Exception(Exceptions::recoverable, "Could not load Tracker Mapping.", "MapCppTrackerMCDigitization::load_mapping")); } std::string line; int line_count = 0; while ( getline(inf, line) ) { ++line_count; std::istringstream ist1(line.c_str()); ChanMap cmap; ist1 >> cmap.board >> cmap.bank >> cmap.chan_ro >> cmap.tracker >> cmap.station >> cmap.view >> cmap.fibre >> cmap.extWG >> cmap.inWG >> cmap.WGfib; int UId = calc_uid(cmap.chan_ro, cmap.bank, cmap.board); if (static_cast(UId) > (_chan_map.size() - 1)) { std::cerr << "WARNING:: MapCppTrackerMCDigitization: Channel ID outside bounds of map\n"; std::cerr << "line number: " << line_count << ", UId: " << UId << ", size: " << _chan_map.size() << ", chan_ro: " << cmap.chan_ro << ", bank: " << cmap.bank << ", board: " << cmap.board << "\n"; continue; } // Check the channel map entry for this UId is not uninitialised if (_chan_map[UId].tracker != -1) { std::cerr << "WARNING: UId " << UId << " not unique! "; std::cerr << "chan_ro: " << cmap.chan_ro << ", bank: " << cmap.bank << ", board: " << cmap.board << "\n"; } _chan_map[UId] = cmap; // encode the tracker, sttion, plane, channel as a string for lookup std::stringstream ss; ss << cmap.tracker << cmap.station << cmap.view << cmap.fibre; _uidlookup[ss.str()] = UId; // std::cerr << "UID: " << UId << " tk:st:pl:ch:: " << cmap.tracker << " " << cmap.station // << " " << cmap.view << " " << cmap.fibre << " brd:bnk:chan " << cmap.board // << " " << cmap.bank << " " << cmap.chan_ro << std::endl; } return true; } int MapCppTrackerMCDigitization::calc_uid(int chan_ro, int bank, int board) const { return chan_ro + (bank*_number_channels) + (board*_banks_per_board*_number_channels); } bool MapCppTrackerMCDigitization::load_bad_channels(std::string file) { for ( int bank = 0; bank < _number_banks; ++bank ) { for ( int chan_ro = 0; chan_ro < _number_channels; ++chan_ro ) { _good_chan[bank][chan_ro] = true; } } if ( file.size() == 0 ) { // No file specified - assume no bad channels. std::cerr << "No SciFi Bad Channels File. Assuming no bad channels"; return true; } std::string fname = _config_dir+"/files/calibration/"+file; std::ifstream inf(fname.c_str()); if (!inf) { throw(Exceptions::Exception(Exceptions::recoverable, "Could not load Tracker bad channel list.", "MapCppTrackerMCDigitization::load_bad_channels")); } int bad_bank, bad_chan_ro; while ( !inf.eof() ) { inf >> bad_bank >> bad_chan_ro; _good_chan[bad_bank][bad_chan_ro] = false; } return true; } } // ~namespace MAUS