SimDepoSource.cxx
Go to the documentation of this file.
1 /** The WC/LS sim depo source adapts larsoft SimEnergyDeposit to WCT's IDepos.
2 
3  Note, this WC/LS file unusually verbose. Besides just data
4  conversion, additional WCT guts are exposed allow optional
5  application of WCT ionization/recombination models, or to rely on
6  the depo provider to already provide depo in units of #electrons.
7 */
8 
9 #include "SimDepoSource.h"
10 
13 
15 
16 #include "WireCellUtil/Units.h"
17 #include "WireCellUtil/String.h"
18 #include "WireCellUtil/NamedFactory.h"
19 #include "WireCellIface/SimpleDepo.h"
20 #include "WireCellIface/IRecombinationModel.h"
21 
23  WireCell::IDepoSource, WireCell::IConfigurable)
24 
25 
26 namespace units = WireCell::units;
27 
28 namespace wcls {
29  namespace bits {
30 
31  // There is more than one way to make ionization electrons.
32  // These adapters erase these differences.
33  class DepoAdapter {
34  public:
35  virtual ~DepoAdapter() {}
36  virtual double operator()(const sim::SimEnergyDeposit& sed) const = 0;
37  };
38 
39  // This takes number of electrons directly, and applies a
40  // multiplicative scale.
41  class ElectronsAdapter : public DepoAdapter {
42  double m_scale;
43  public:
44  ElectronsAdapter(double scale=1.0) : m_scale(scale) {}
45  virtual ~ElectronsAdapter() {};
46  virtual double operator()(const sim::SimEnergyDeposit& sed) const {
47  return m_scale * sed.NumElectrons();
48  }
49  };
50 
51  // This one takes a recombination model which only requires dE
52  // (ie, assumes MIP).
53  class PointAdapter : public DepoAdapter {
54  WireCell::IRecombinationModel::pointer m_model;
55  double m_scale;
56  public:
57  PointAdapter(WireCell::IRecombinationModel::pointer model, double scale=1.0)
58  : m_model(model), m_scale(scale) {}
59  virtual ~PointAdapter() {}
60  virtual double operator()(const sim::SimEnergyDeposit& sed) const {
61  const double dE = sed.Energy()*units::MeV;
62  return m_scale * (*m_model)(dE);
63  }
64  };
65 
66  // This one takes a recombination which is a function of both dE and dX.
67  class StepAdapter : public DepoAdapter {
68  WireCell::IRecombinationModel::pointer m_model;
69  double m_scale;
70  public:
71  StepAdapter(WireCell::IRecombinationModel::pointer model, double scale=1.0)
72  : m_model(model), m_scale(scale) {}
73  virtual ~StepAdapter() {}
74  virtual double operator()(const sim::SimEnergyDeposit& sed) const {
75  const double dE = sed.Energy()*units::MeV;
76  const double dX = sed.StepLength()*units::cm;
77  return m_scale * (*m_model)(dE, dX);
78  }
79  };
80  }
81 }
82 
83 
84 using namespace wcls;
85 
86 SimDepoSource::SimDepoSource()
87  : m_adapter(nullptr)
88 {
89 }
90 
92 {
93  if (m_adapter) {
94  delete m_adapter;
95  m_adapter = nullptr;
96  }
97 }
98 
100 {
102 
103  // An empty model or the special model "electrons" means to take
104  // precalcualted input NumElectrons. Anything else means some
105  // recombination model is used.
106  cfg["model"] = "";
107  // Multiply this number to the number of electrons before forming
108  // a WC depo.
109  cfg["scale"] = 1.0;
110 
111  // For locating input in the art::Event
112  cfg["art_tag"] = ""; // eg, "plopper:bogus"
113  cfg["assn_art_tag"] = ""; // eg, "largeant"
114 
115  return cfg;
116 }
118 {
119  if (m_adapter) {
120  delete m_adapter;
121  m_adapter = nullptr;
122  }
123  double scale = WireCell::get(cfg, "scale", 1.0);
124 
125  std::string model_tn = WireCell::get<std::string>(cfg, "model", "");
126  std::string model_type = "";
127  if (!model_tn.empty()) {
128  WireCell::String::split(model_tn)[0];
129  }
130 
131  if (model_type == "" or model_type == "electrons") {
133  }
134  else {
135  auto model = WireCell::Factory::lookup_tn<WireCell::IRecombinationModel>(model_tn);
136  if (!model) {
137  std::cerr << "wcls::SimDepoSource: unknown recombination model: \"" << model_tn << "\"\n";
138  return; // I should throw something here!
139  }
140  if (model_type == "MipRecombination") {
142  }
143  if (model_type == "BirksRecombination" || model_type == "BoxRecombination") {
145  }
146  }
147 
148  m_inputTag = cfg["art_tag"].asString();
149  m_assnTag = cfg["assn_art_tag"].asString();
150 }
151 
152 
154 {
156 
157  bool okay = event.getByLabel(m_inputTag, sedvh);
158  if (!okay) {
159  std::string msg = "SimDepoSource failed to get sim::SimEnergyDeposit from art tag: " + m_inputTag.encode();
160  std::cerr << msg << std::endl;
161  THROW(WireCell::RuntimeError() << WireCell::errmsg{msg});
162  }
163  //else if (sedvh->empty()) return;
164 
165  const size_t ndepos = sedvh->size();
166 
167  std::cerr << "SimDepoSource got " << ndepos
168  << " depos from art tag \"" << m_inputTag
169  << "\" returns: " << (okay ? "okay" : "fail") << std::endl;
170 
171  if (!m_depos.empty()) {
172  std::cerr << "SimDepoSource dropping " << m_depos.size()
173  << " unused, prior depos\n";
174  m_depos.clear();
175  }
176 
177  // associate the input SED with the other set of SED (eg, before SCE)
178  std::vector<sim::SimEnergyDeposit> assn_sedv;
179  if (m_assnTag!="") {
181  okay = event.getByLabel(m_assnTag, assn_sedvh);
182  if (!okay) {
183  std::string msg = "SimDepoSource failed to get sim::SimEnergyDeposit from art tag: " + m_assnTag.encode();
184  std::cerr << msg << std::endl;
185  THROW(WireCell::RuntimeError() << WireCell::errmsg{msg});
186  }
187  else {
188  std::cout << "Larwirecell::SimDepoSource got " << assn_sedvh->size()
189  << " associated depos from " << m_assnTag << std::endl;
190  assn_sedv.insert(assn_sedv.end(), assn_sedvh->begin(), assn_sedvh->end() );
191  }
192  // safty check for the associated SED
193  if (ndepos != assn_sedv.size()) {
194  std::string msg = "Larwirecell::SimDepoSource Inconsistent size of SimDepoSources";
195  std::cerr << msg << std::endl;
196  THROW(WireCell::RuntimeError() << WireCell::errmsg{msg});
197  }
198  }
199 
200  for (size_t ind=0; ind<ndepos; ++ind) {
201  auto const& sed = sedvh->at(ind);
202  auto pt = sed.MidPoint();
203  const WireCell::Point wpt(pt.x()*units::cm, pt.y()*units::cm, pt.z()*units::cm);
204  double wt = sed.Time()*units::ns;
205  double wq = (*m_adapter)(sed);
206  int wid = sed.TrackID();
207  int pdg = sed.PdgCode();
208  double we = sed.Energy()*units::MeV;
209 
210  if (assn_sedv.size() == 0) {
211  WireCell::IDepo::pointer depo
212  = std::make_shared<WireCell::SimpleDepo>(wt, wpt, wq, nullptr, 0.0, 0.0, wid, pdg, we);
213  m_depos.push_back(depo);
214  // std::cerr << ind << ": t=" << wt/units::us << "us,"
215  // << " r=" << wpt/units::cm << "cm, "
216  // << " q=" << wq
217  // << " e=" << we/units::MeV << "\n";
218  }
219  else {
220  auto const& sed1 = assn_sedv.at(ind);
221  auto pt1 = sed1.MidPoint();
222  const WireCell::Point wpt1(pt1.x()*units::cm, pt1.y()*units::cm, pt1.z()*units::cm);
223  double wt1 = sed1.Time()*units::ns;
224  double wq1 = (*m_adapter)(sed1);
225  int wid1 = sed1.TrackID();
226  int pdg1 = sed1.PdgCode();
227  double we1 = sed1.Energy()*units::MeV;
228 
229  WireCell::IDepo::pointer assn_depo
230  = std::make_shared<WireCell::SimpleDepo>(wt1, wpt1, wq1, nullptr, 0.0, 0.0, wid1, pdg1, we1);
231 
232  WireCell::IDepo::pointer depo
233  = std::make_shared<WireCell::SimpleDepo>(wt, wpt, wq, assn_depo, 0.0, 0.0, wid, pdg, we);
234  m_depos.push_back(depo);
235  // std::cerr << ind << ": t1=" << wt1/units::us << "us,"
236  // << " r1=" << wpt1/units::cm << "cm, "
237  // << " q1=" << wq1
238  // << " e1=" << we1/units::MeV << "\n";
239  }
240  }
241 
242  // empty "ionization": no TPC activity
243  if (ndepos == 0) {
244  WireCell::Point wpt(0, 0, 0);
245  WireCell::IDepo::pointer depo
246  = std::make_shared<WireCell::SimpleDepo>(0, wpt, 0, nullptr, 0.0, 0.0);
247  m_depos.push_back(depo);
248  }
249 
250  // don't trust user to honor time ordering.
251  std::sort(m_depos.begin(), m_depos.end(), WireCell::ascending_time);
252  std::cerr << "SimDepoSource: ready with " << m_depos.size() << " depos spanning: ["
253  << m_depos.front()->time()/units::us << ", "
254  << m_depos.back()->time()/units::us << "]us\n";
255  m_depos.push_back(nullptr); // EOS marker
256 }
257 
258 bool SimDepoSource::operator()(WireCell::IDepo::pointer& out)
259 {
260  if (m_depos.empty()) {
261  return false;
262  }
263 
264  out = m_depos.front();
265  m_depos.pop_front();
266 
267  // if (!out) {
268  // std::cerr << "SimDepoSource: reached EOS\n";
269  // }
270  // else {
271  // std::cerr << "SimDepoSource: t=" << out->time()/units::us << "us,"
272  // << " r=" << out->pos()/units::cm << "cm, " << " q=" << out->charge() << "\n";
273  // }
274  return true;
275 }
static constexpr double cm
Definition: Units.h:68
geo::Length_t StepLength() const
static constexpr double us
Definition: Units.h:97
virtual WireCell::Configuration default_configuration() const
IConfigurable.
void msg(const char *fmt,...)
Definition: message.cpp:107
ElectronsAdapter(double scale=1.0)
std::string string
Definition: nybbler.cc:12
virtual double operator()(const sim::SimEnergyDeposit &sed) const
std::deque< WireCell::IDepo::pointer > m_depos
Definition: SimDepoSource.h:60
PointAdapter(WireCell::IRecombinationModel::pointer model, double scale=1.0)
Definition: model.py:1
static constexpr double MeV
Definition: Units.h:129
std::string encode() const
Definition: InputTag.cc:97
art::InputTag m_assnTag
Definition: SimDepoSource.h:64
WireCell::IRecombinationModel::pointer m_model
WIRECELL_FACTORY(wclsSimDepoSource, wcls::SimDepoSource, wcls::IArtEventVisitor, WireCell::IDepoSource, WireCell::IConfigurable) namespace units
virtual void configure(const WireCell::Configuration &config)
art::InputTag m_inputTag
Definition: SimDepoSource.h:63
std::tuple< double, double, const reco::ClusterHit3D * > Point
Definitions used by the VoronoiDiagram algorithm.
Definition: DCEL.h:44
virtual bool operator()(WireCell::IDepo::pointer &out)
IDepoSource.
virtual double operator()(const sim::SimEnergyDeposit &sed) const
virtual void visit(art::Event &event)
IArtEventVisitor.
bits::DepoAdapter * m_adapter
Definition: SimDepoSource.h:61
StepAdapter(WireCell::IRecombinationModel::pointer model, double scale=1.0)
contains information for a single step in the detector simulation
Energy deposition in the active material.
virtual double operator()(const sim::SimEnergyDeposit &sed) const
void split(std::string const &s, char c, OutIter dest)
Definition: split.h:35
double Energy() const
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
QAsciiDict< Entry > ns
WireCell::IRecombinationModel::pointer m_model
QTextStream & endl(QTextStream &s)
Event finding and building.