/* 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/API/PyWrapMapBase.hh" #include "src/map/MapCppTrackerMCNoise/MapCppTrackerMCNoise.hh" namespace MAUS { PyMODINIT_FUNC init_MapCppTrackerMCNoise(void) { PyWrapMapBase::PyWrapMapBaseModInit ("MapCppTrackerMCNoise", "", "", "", ""); } /***** Initialization *****/ MapCppTrackerMCNoise::MapCppTrackerMCNoise() : MapBase("MapCppTrackerMCNoise") { } /***** Destructor *****/ MapCppTrackerMCNoise::~MapCppTrackerMCNoise() { } /***** Birth *****/ void MapCppTrackerMCNoise::_birth(const std::string& argJsonConfigDocument) { if (!Globals::HasInstance()) { GlobalsManager::InitialiseGlobals(argJsonConfigDocument); } static MiceModule* _mice_modules = Globals::GetMonteCarloMiceModules(); SF_modules = _mice_modules->findModulesByPropertyString("SensitiveDetector", "SciFi"); _configJSON = Globals::GetConfigurationCards(); _vlpc_sim_on = (*_configJSON)["SciFi_BG_VLPCOn"].asInt(); _rf_sim_on = (*_configJSON)["SciFi_BG_RFOn"].asInt(); if (_vlpc_sim_on == 1) { _vlpc_rate = (*_configJSON)["SciFi_BG_VLPCRate"].asDouble(); vlpc_mean_npe = -log(1-_vlpc_rate); } if (_rf_sim_on == 1) { _rf_ave_act = (*_configJSON)["SciFi_BG_RFAct"].asDouble(); _rf_mag = (*_configJSON)["SciFi_BG_RFMag"].asDouble(); _rf_sdev = (*_configJSON)["SciFi_BG_RFSDev"].asDouble(); /***** Total number of events we would expect at the source *****/ flux = _rf_ave_act / (1/pow(1.95, 2.0)+1/pow(2.15, 2.0)+1/pow(2.4, 2.0) +1/pow(2.7, 2.0)+1/pow(3.05, 2.0))*(5.0); } } /***** Death *****/ void MapCppTrackerMCNoise::_death() { } /***** Process *****/ void MapCppTrackerMCNoise::_process(Data* data) const { Spill& spill = *(data->GetSpill()); if ( spill.GetMCEvents() ) { } else { throw MAUS::Exceptions::Exception(Exceptions::recoverable, "MC event array not initialised, aborting noise", "MapCppTrackerMCNoise::_process"); } /***** Examine each particle event in a spill individually *****/ for ( unsigned int event_i = 0; event_i < spill.GetMCEvents()->size(); event_i++ ) { int spill_n = spill.GetSpillNumber(); SciFiNoiseHitArray* noise = new SciFiNoiseHitArray(); // ===== Noise Implementation =============================== /***** Simulates noise from thermal activation of VLPCs ****/ if (_vlpc_sim_on == 1) { VLPC_Thermal(spill, noise, event_i, spill_n); } /************************************************************ * Crude attempt to simulate effects of RF generated * x-rays on tracker background noise ************************************************************/ if (_rf_sim_on == 1) { RF_X_Ray(spill, noise, event_i, spill_n); } // ========================================================== spill.GetMCEvents()->at(event_i)->SetSciFiNoiseHits(noise); } } void MapCppTrackerMCNoise::VLPC_Thermal(Spill& spill, SciFiNoiseHitArray* noise, unsigned int& event_i, int& spill_n) const { std::vector chanArray; /************************************************************************************** * Ideally time should be a flat distribution in the spill time, however without a * trigger simulation this isn't possible. Some investigation into MC spill time * might provide useful, but isn't really a pressing issue **************************************************************************************/ double time1 = 0.; // Fix: Need to assign a value to this! /************************************************************************************* * Description: * Determines the number of channels activated by background noise in the VLPCs * according to a Poisson distribution, where the mean activated channels can be set * at run time by command line/configuration file (--SciFiDarkCountChance=x). * Individual channels are then selected and assigned a randomized PE value. * Likewise, the NPE is determined then from a Poisson calculation. **************************************************************************************/ /***** Examine each tracker plane individually *****/ for ( unsigned int mod_i = 0; mod_i < SF_modules.size(); mod_i++ ) { int nChannels = static_cast (2*((SF_modules[mod_i]->propertyDouble("CentralFibre"))+0.5)); double mean_channels = static_cast(nChannels*_vlpc_rate); int active_channels = CLHEP::RandPoisson::shoot(mean_channels); /***** Fills array with all channels *****/ chanArray.resize(0); for (int ich = 0; ich < nChannels; ich++) { chanArray.push_back(ich+1); } if (active_channels == 0) { continue; } for (int fch = 0; fch < active_channels; fch++) { /****************************************************** * Determines and records activated channel then removes * the channel from the list of a possible choices ******************************************************/ int chan_ran = std::rand() % (nChannels - fch); int chan_i = chanArray[chan_ran]; chanArray.erase(chanArray.begin()+chan_ran); /***** Setting PE value *****/ int D_NPE = 0; Poisson_Hits(D_NPE, vlpc_mean_npe); /***** Writing out result *****/ int tracker = SF_modules[mod_i]->propertyInt("Tracker"); int station = SF_modules[mod_i]->propertyInt("Station"); int plane = SF_modules[mod_i]->propertyInt("Plane"); SciFiNoiseHit a_noise_hit(spill_n, event_i, tracker, station, plane, chan_i, D_NPE, time1); noise->push_back(a_noise_hit); } } } /****************************************************************************** * Uses the chance of an event happening to determine the likelihood that the * event will happen 1, 2, 3, or 4 times as described by a Poisson distribution. * Then uses a random number generator to choose the correct number of events. ******************************************************************************/ void MapCppTrackerMCNoise::Poisson_Hits(int& hits, const double& mean) const { double p_one = mean*exp(-mean); double p_two = pow(mean, 2.0)*exp(-mean)/2; double p_three = pow(mean, 3.0)*exp(-mean)/6; double p_four = pow(mean, 4.0)*exp(-mean)/24; double p_sum = p_one + p_two + p_three + p_four; double rand_pick = static_cast(std::rand()) / static_cast(RAND_MAX) * p_sum; hits = 0; if (rand_pick < p_one) { hits = 1; } else if (rand_pick < p_one+p_two) { hits = 2; } else if (rand_pick < p_one+p_two+p_three) { hits = 3; } else { hits = 4; } } void MapCppTrackerMCNoise::RF_X_Ray(Spill& spill, SciFiNoiseHitArray* noise, unsigned int& event_i, int& spill_n) const { std::vector chanArray; double time1 = 0.; // Fix: Need to assign a value to this! /************************************************************************************* * Description: * Written specificity to test a mean X-ray background rate of 10 hits per plane. * The per station hit rate varies as 1/r^2, where r comes from the distance from * the station (not plane, effect would be minimal) to the center of the RF cavity * as determined from a simplistic model of the MICE Demonstration geometry (r1 = 1.95) **************************************************************************************/ /***** Examine each tracker plane individually *****/ for ( unsigned int mod_i = 0; mod_i < SF_modules.size(); mod_i++ ) { int nChannels = static_cast (2*((SF_modules[mod_i]->propertyDouble("CentralFibre"))+0.5)); /***** Mean channels activated determined by distance from RF *****/ double mean_channels = 0.0; if (SF_modules[mod_i]->propertyInt("Station") == 1) { mean_channels = flux/pow(1.95, 2.0); } else if (SF_modules[mod_i]->propertyInt("Station") == 2) { mean_channels = flux/pow(2.15, 2.0); } else if (SF_modules[mod_i]->propertyInt("Station") == 3) { mean_channels = flux/pow(2.4, 2.0); } else if (SF_modules[mod_i]->propertyInt("Station") == 4) { mean_channels = flux/pow(2.7, 2.0); } else if (SF_modules[mod_i]->propertyInt("Station") == 5) { mean_channels = flux/pow(3.05, 2.0); } int active_channels = CLHEP::RandPoisson::shoot(mean_channels); /***** Fills array with all channels *****/ chanArray.resize(0); for (int ich = 0; ich < nChannels; ich++) { chanArray.push_back(ich+1); } if (active_channels == 0) { continue; } for (int fch = 0; fch < active_channels; fch++) { /*********************************************************************** * Determines and records activated channel then removes the channel from * the list of a possible choices in chanArray ***********************************************************************/ int chan_ran = std::rand() % (nChannels - fch); int chan_i = chanArray[chan_ran]; chanArray.erase(chanArray.begin()+chan_ran); /***** Setting PE value, toy values! *****/ double D_NPE = floor(CLHEP::RandGauss::shoot(_rf_mag, _rf_sdev)); /***** Creating the noise hit for writing to spill *****/ int tracker = SF_modules[mod_i]->propertyInt("Tracker"); int station = SF_modules[mod_i]->propertyInt("Station"); int plane = SF_modules[mod_i]->propertyInt("Plane"); SciFiNoiseHit a_noise_hit(spill_n, event_i, tracker, station, plane, chan_i, D_NPE, time1); noise->push_back(a_noise_hit); } } } } // ~namespace MAUS