All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SimDepoSetSource.cxx
Go to the documentation of this file.
1 /** The WC/LS sim depo set source adapts larsoft SimEnergyDeposit to WCT's IDepoSets.
2  Modified from the SimDepoSource for IDepoSet for better efficiency
3 */
4 
5 #include "SimDepoSetSource.h"
6 
7 #include "art/Framework/Principal/Handle.h"
8 #include "art/Framework/Principal/Event.h"
9 
11 
12 #include "WireCellUtil/Units.h"
13 #include "WireCellUtil/String.h"
14 #include "WireCellUtil/NamedFactory.h"
15 #include "WireCellAux/SimpleDepo.h"
16 #include "WireCellAux/SimpleDepoSet.h"
17 #include "WireCellIface/IRecombinationModel.h"
18 
20  WireCell::IDepoSetSource, WireCell::IConfigurable)
21 
22 using WireCell::Aux::SimpleDepo;
23 using WireCell::Aux::SimpleDepoSet;
24 
25 namespace units = WireCell::units;
26 
27 namespace wcls {
28 
29  // There is more than one way to make ionization electrons.
30  // These adapters erase these differences.
32  public:
33  virtual ~DepoAdapter() {}
34  virtual double operator()(const sim::SimEnergyDeposit& sed) const = 0;
35  };
36 
37  namespace bits {
38 
39  // This takes number of electrons directly, and applies a
40  // multiplicative scale.
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).
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.
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 
87  : m_count(0), m_adapter(nullptr)
88 {
89 }
90 
92 {
93  if (m_adapter) {
94  delete m_adapter;
95  m_adapter = nullptr;
96  }
97 }
98 
99 WireCell::Configuration SimDepoSetSource::default_configuration() const
100 {
101  WireCell::Configuration cfg;
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 }
117 void SimDepoSetSource::configure(const WireCell::Configuration& cfg)
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::SimDepoSetSource: unknown recombination model: \"" << model_tn << "\"\n";
138  return; // I should throw something here!
139  }
140  if (model_type == "MipRecombination") {
141  m_adapter = new wcls::bits::PointAdapter(model, scale);
142  }
143  if (model_type == "BirksRecombination" || model_type == "BoxRecombination") {
144  m_adapter = new wcls::bits::StepAdapter(model, scale);
145  }
146  }
147 
148  m_inputTag = cfg["art_tag"].asString();
149  m_assnTag = cfg["assn_art_tag"].asString();
150 }
151 
152 
153 void SimDepoSetSource::visit(art::Event & event)
154 {
155  art::Handle< std::vector<sim::SimEnergyDeposit> > sedvh;
156 
157  bool okay = event.getByLabel(m_inputTag, sedvh);
158  if (!okay) {
159  std::string msg = "SimDepoSetSource 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 << "SimDepoSetSource 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 << "SimDepoSetSource 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!="") {
180  art::Handle< std::vector<sim::SimEnergyDeposit> > assn_sedvh;
181  okay = event.getByLabel(m_assnTag, assn_sedvh);
182  if (!okay) {
183  std::string msg = "SimDepoSetSource 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::SimDepoSetSource 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::SimDepoSetSource Inconsistent size of SimDepoSetSources";
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<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<SimpleDepo>(wt1, wpt1, wq1, nullptr, 0.0, 0.0, wid1, pdg1, we1);
231 
232  WireCell::IDepo::pointer depo
233  = std::make_shared<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<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 << "SimDepoSetSource: ready with " << m_depos.size() << " depos spanning: ["
253  << m_depos.front()->time()/units::us << ", "
254  << m_depos.back()->time()/units::us << "]us\n";
255 }
256 
257 bool SimDepoSetSource::operator()(WireCell::IDepoSet::pointer& out)
258 {
259  if (m_depos.empty()) {
260  return false;
261  }
262 
263  out = std::make_shared<SimpleDepoSet>(m_count, m_depos);
264  m_depos.clear();
265  ++m_count;
266 
267  return true;
268 }
geo::Length_t StepLength() const
WireCell::IDepo::vector m_depos
var pdg
Definition: selectors.fcl:14
ElectronsAdapter(double scale=1.0)
BEGIN_PROLOG could also be cerr
virtual double operator()(const sim::SimEnergyDeposit &sed) const
PointAdapter(WireCell::IRecombinationModel::pointer model, double scale=1.0)
util::quantities::megaelectronvolt MeV
WireCell::IRecombinationModel::pointer m_model
virtual void configure(const WireCell::Configuration &config)
virtual bool operator()(WireCell::IDepoSet::pointer &out)
IDepoSetSource.
BEGIN_PROLOG units
std::tuple< double, double, const reco::ClusterHit3D * > Point
Definitions used by the VoronoiDiagram algorithm.
Definition: DCEL.h:44
virtual double operator()(const sim::SimEnergyDeposit &sed) const
WIRECELL_FACTORY(wclsChannelNoiseDB, wcls::ChannelNoiseDB, wcls::IArtEventVisitor, WireCell::IChannelNoiseDatabase) using namespace WireCell
StepAdapter(WireCell::IRecombinationModel::pointer model, double scale=1.0)
virtual WireCell::Configuration default_configuration() const
IConfigurable.
contains information for a single step in the detector simulation
Energy deposition in the active material.
virtual void visit(art::Event &event)
IArtEventVisitor.
virtual double operator()(const sim::SimEnergyDeposit &sed) const
double Energy() const
WireCell::IRecombinationModel::pointer m_model
BEGIN_PROLOG could also be cout