2 #include <sevt/SEvent.h>
4 #include <sevt/PMTSimData.h>
5 #include <utl/ErrorLogger.h>
6 #include <utl/RandomEngine.h>
7 #include <fwk/CentralConfig.h>
8 #include <fwk/RandomEngineRegistry.h>
9 #include <utl/Reader.h>
10 #include <utl/config.h>
18 using namespace SdPMTSimulatorASCII;
24 using CLHEP::RandGeneral;
29 fLimitStationsPerCycle(false),
30 fNStationsPerCycle(numeric_limits<unsigned int>::
max()),
31 fAveragePulseShape(0),
32 fWantRootHistos(false),
35 fSaturationFunction(0),
54 vector<int> components;
57 if (topB.
GetChild(
"fundamentalComponents"))
59 for (
unsigned int i = 0; i != components.size(); ++i)
64 if (topB.
GetChild(
"fundamentalComponents_ASCII"))
66 for (
unsigned int i = 0; i != components.size(); ++i)
75 vector<double> anodeTimeBins;
77 vector<double> anodePulseHeight;
80 if (anodeTimeBins.empty() || anodeTimeBins.size() != anodePulseHeight.size()) {
81 ERROR(
"Malformed <anodePulseShape> configuration.");
86 const unsigned int naph = anodePulseHeight.size();
89 for (
unsigned int i = 0; i < naph; ++i)
90 anodePulseHeight[i] = (anodePulseHeight[i] >= 0) ? 0 : -anodePulseHeight[i];
92 double anodeIntegral = 0;
93 for (
unsigned int i1 = 0, i2 = 1; i2 < naph; ++i1, ++i2) {
94 const double dt = anodeTimeBins[i2] - anodeTimeBins[i1];
95 anodeIntegral += 0.5*(anodePulseHeight[i1] + anodePulseHeight[i2])*dt;
99 for (
unsigned int i1 = 0, i2 = 1; i2 < naph; ++i1, ++i2) {
101 anodePulseHeight[i1] *= dt / anodeIntegral;
105 const double offset = anodeTimeBins[0];
106 for (
unsigned int i = 0; i < naph; ++i)
107 anodeTimeBins[i] -= offset;
114 double currentMax = 0;
117 if (fIt->Y() >= currentMax) {
118 currentMax = fIt->Y();
128 vector<double> chargeProbability;
131 const unsigned int chargeProbabilityN = chargeProbability.size();
133 fRandomEngine = &RandomEngineRegistry::GetInstance().Get(RandomEngineRegistry::eDetector);
144 INFO(
"Will write diagnostic histograms for this module");
147 fChargeHisto =
new TH1D(
"chargeDist",
"charge distribution", 20,0,4);
148 for (
int itest = 0; itest < 100000; ++itest) {
168 useAtt[
"use"] = string(
"yes");
177 if (vIn.size() != vOut.size()) {
178 ERROR(
"Lists of input/output voltages for saturation curve must have same size");
182 info <<
"saturation curve [V]: ";
183 for (
unsigned int i = 0; i < vIn.size(); ++i)
184 info << vIn[i]/
volt <<
" -> " << vOut[i]/
volt <<
" ";
188 for (
unsigned int i = 0; i < vIn.size(); ++i) {
195 INFO(
"No PMT saturation simulation");
197 Branch limitStations = topB.
GetChild(
"LimitStationsPerCycle", useAtt);
213 double avgPulseShapeNorm = 0;
214 vector<double> avgPulseShape;
215 avgPulseShape.reserve(
int(pulseStopTime / dt) + 1);
216 for (
double time = 0; time < pulseStopTime; time += dt) {
218 avgPulseShapeNorm += pulse;
219 avgPulseShape.push_back(pulse);
223 const double scaleFactorMin = PMTGain *
fMinCharge / avgPulseShapeNorm;
224 const double scaleFactorMax = PMTGain *
fMaxCharge / avgPulseShapeNorm;
227 peIt != end; ++peIt) {
231 for (
int i = 0, n = peIt->get<1>(); i < n; ++i)
234 const double realCharge = scaleFactorMin + scaleFactorMax*charge;
236 const double offset = peIt->get<0>() - pulseMaxTime;
240 for (
double time = 0; time <= pulseStopTime; time += dt)
242 base.
AddTime(time + offset, realCharge * avgPulseShape[++i]);
252 for (
int i = baseSignal.
GetStart(), n = baseSignal.
GetStop(); i <= n; ++i) {
253 double& sig = baseSignal[i];
254 const double tot = totalBaseSignal[i];
255 const double maxDist =
max(sig, tot);
256 const double scaling =
267 ERROR(
"Event does not have an SEvent");
271 SEvent& sEvent =
event.GetSEvent();
275 info <<
"all stations processed.";
290 unsigned int fStationsProcessed = 0;
302 if (!pIt->HasSimData())
319 for (
unsigned int i = 0; i != nFundComponents; ++i) {
329 if ( nFundComponents == 0) {
333 for (
unsigned int i = 0; i != nFundComponents; ++i) {
338 peIt != end; ++peIt) {
339 totalBaseSignal[peIt->get<0>()] += peIt->get<1>();
348 ++fStationsProcessed;
unsigned int fNStationsPerCycle
std::vector< sevt::StationConstants::SignalComponent > fFundamentalComponents
Branch GetTopBranch() const
int GetStart() const
First slot with data.
unsigned int GetNPoints() const
StationIterator StationsEnd()
End of all stations.
Report success to RunController.
RandomEngineType & GetEngine()
bool HasBaseSignal(const StationConstants::SignalComponent source=StationConstants::eTotal) const
Check if signal at PMT base already exists (optionally for a given source)
CLHEP::RandGeneral * fChargeDist
Interface class to access to the SD part of an event.
fwk::VModule::ResultFlag Run(evt::Event &event)
Run: invoked once per event.
Class to hold collection (x,y) points and provide interpolation between them.
utl::RandomEngine * fRandomEngine
std::map< std::string, std::string > AttributeMap
Histogram class for time distributions with suppressed empty bins.
#define INFO(message)
Macro for logging informational messages.
std::string fRootHistoFilename
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
void SimulateSaturation(utl::TimeDistributionD &baseSignal, const utl::TimeDistributionD &totalBaseSignal)
bool HasPETimeDistribution(const StationConstants::SignalComponent source=StationConstants::eTotal) const
Check if a PE release time distribution exists (optionally for a given source)
fwk::VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
Class representing a document branch.
Break current loop. It works for nested loops too!
double GetBinning() const
Size of one slot.
virtual ~SdPMTSimulator()
void MakeBaseSignal(const StationConstants::SignalComponent source=StationConstants::eTotal)
Create a TimeDistributionD representing signal at PMT base (optionally for a give source) ...
sevt::SEvent::StationIterator fStationIterator
constexpr double nanosecond
int GetStop() const
Last slot with data (1 less than First slot if no data)
std::vector< sevt::StationConstants::SignalComponent > fFundamentalComponents_ASCII
utl::TabulatedFunction::Iterator fMaxPulseHeight
fwk::VModule::ResultFlag Finish()
Finish: invoked at end of the run (NOT end of the event)
void GetData(bool &b) const
Overloads of the GetData member template function.
SparseIterator SparseEnd() const
void ConvertPEToBaseSignal(const utl::TimeDistributionI &pe, utl::TimeDistributionD &baseSignal, double PMTGain)
ResultFlag
Flag returned by module methods to the RunController.
utl::TabulatedFunction * fAveragePulseShape
utl::TabulatedFunction * fSaturationFunction
StationIterator StationsBegin()
Beginning of all stations.
double fCurrent2VoltageMultiplier
Class to hold simulated data at PMT level.
total (shower and background)
Report failure to RunController, causing RunController to terminate execution.
SparseIterator SparseBegin() const
Iterator over time slots with data in them (skips empty slots).
utl::TimeDistributionI & GetPETimeDistribution(const StationConstants::SignalComponent source=StationConstants::eTotal)
Simulated photoelectron time distribution.
utl::TimeDistributionD & GetBaseSignal(const StationConstants::SignalComponent source=StationConstants::eTotal)
Get simulated signal at the PMT base, optionally for a given source.
double Y(const double x) const
Get or interpolate the Y value that corresponds to parameter x.
bool fLimitStationsPerCycle
#define ERROR(message)
Macro for logging error messages.
void AddTime(const double time, const T weight=T(1))
Add an entry (optionally weighted) for the given time. Slot will be computed.
boost::transform_iterator< InternalMapFunctor, InternalConstIterator, Tuple > SparseIterator