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