Functions
test_impactzipper.cxx File Reference
#include "WireCellGen/ImpactZipper.h"
#include "WireCellGen/TrackDepos.h"
#include "WireCellGen/BinnedDiffusion.h"
#include "WireCellGen/TransportedDepo.h"
#include "WireCellGen/PlaneImpactResponse.h"
#include "WireCellUtil/ExecMon.h"
#include "WireCellUtil/Point.h"
#include "WireCellUtil/Binning.h"
#include "WireCellUtil/Testing.h"
#include "WireCellUtil/Response.h"
#include "WireCellUtil/PluginManager.h"
#include "WireCellUtil/NamedFactory.h"
#include "WireCellIface/IRandom.h"
#include "WireCellIface/IConfigurable.h"
#include "WireCellIface/IFieldResponse.h"
#include "WireCellIface/IPlaneImpactResponse.h"
#include "TCanvas.h"
#include "TFile.h"
#include "TLine.h"
#include "TStyle.h"
#include "TH2F.h"
#include <iostream>
#include <string>

Go to the source code of this file.

Functions

int main (const int argc, char *argv[])
 

Function Documentation

int main ( const int  argc,
char *  argv[] 
)

Definition at line 32 of file test_impactzipper.cxx.

33 {
34  string track_types = "point";
35  if (argc > 1) {
36  track_types = argv[1];
37  }
38  cerr << "Using tracks type: \"" << track_types << "\"\n";
39 
40  string response_file = "ub-10-half.json.bz2";
41  if (argc > 2) {
42  response_file = argv[2];
43  cerr << "Using Wire Cell field response file:\n"
44  << response_file << endl;
45  }
46  else {
47  cerr << "No Wire Cell field response input file given, will try to use:\n"
48  << response_file << endl;
49  }
50 
51  string out_basename = argv[0];
52  if (argc > 3) {
53  out_basename = argv[3];
54  }
55 
56 
57  // here we do hard-wired configuration. User code should NEVER do
58  // this.
59 
61  pm.add("WireCellGen");
62  pm.add("WireCellSigProc");
63  {
64  auto rngcfg = Factory::lookup<IConfigurable>("Random");
65  auto cfg = rngcfg->default_configuration();
66  rngcfg->configure(cfg);
67  }
68 
69  const int nticks = 9595;
70  const double tick = 0.5*units::us;
71  const double gain = 14.0*units::mV/units::fC;
72  const double shaping = 2.0*units::us;
73 
74  const double t0 = 0.0*units::s;
75  const double readout_time = nticks*tick;
76  const double drift_speed = 1.0*units::mm/units::us; // close, but not real
77 
78  const std::string er_tn = "ElecResponse", rc_tn = "RCResponse";
79 
80  { // configure elecresponse
81  auto icfg = Factory::lookup_tn<IConfigurable>(er_tn);
82  auto cfg = icfg->default_configuration();
83  cfg["gain"] = gain;
84  cfg["shaping"] = shaping;
85  cfg["nticks"] = nticks;
86  cerr << "Setting: " << cfg["nticks"].asInt() << " ticks\n";
87  cfg["tick"] = tick;
88  cfg["start"] = t0;
89  icfg->configure(cfg);
90  }
91  { // configure rc response
92  auto icfg = Factory::lookup_tn<IConfigurable>(rc_tn);
93  auto cfg = icfg->default_configuration();
94  cfg["nticks"] = nticks;
95  cfg["tick"] = tick;
96  cfg["start"] = t0;
97  icfg->configure(cfg);
98  }
99  {
100  auto icfg = Factory::lookup<IConfigurable>("FieldResponse");
101  auto cfg = icfg->default_configuration();
102  cfg["filename"] = response_file;
103  icfg->configure(cfg);
104  }
105 
106  std::vector<std::string> pir_tns{ "PlaneImpactResponse:U",
107  "PlaneImpactResponse:V", "PlaneImpactResponse:W"};
108  { // configure pirs
109  for (int iplane=0; iplane<3; ++iplane) {
110  auto icfg = Factory::lookup_tn<IConfigurable>(pir_tns[iplane]);
111  auto cfg = icfg->default_configuration();
112  cfg["plane"] = iplane;
113  cfg["nticks"] = nticks;
114  cfg["tick"] = tick;
115  cfg["other_responses"][0] = er_tn;
116  cfg["other_responses"][1] = rc_tn; // double it so
117  cfg["other_responses"][2] = rc_tn; // we get RC^2
118  icfg->configure(cfg);
119  }
120  }
121 
122 
123 
124  WireCell::ExecMon em(out_basename);
125  auto ifr = Factory::find_tn<IFieldResponse>("FieldResponse");
126  auto fr = ifr->field_response();
127 
128 
129  em("loaded response");
130 
131  const char* uvw = "UVW";
132 
133  // 1D garfield wires are all parallel
134  const double angle = 60*units::degree;
135  const Vector upitch(0, -sin(angle), cos(angle));
136  const Vector uwire (0, cos(angle), sin(angle));
137  const Vector vpitch(0, sin(angle), cos(angle));
138  const Vector vwire (0, cos(angle), -sin(angle));
139  const Vector wpitch(0, 0, 1);
140  const Vector wwire (0, 1, 0);
141 
142  // FIXME: need to apply electronics response!
143 
144 
145  // Origin where drift and diffusion meets field response.
146  Point field_origin(fr.origin, 0, 0);
147  cerr << "Field response origin: " << field_origin/units::mm << "mm\n";
148 
149  // Describe the W collection plane
150  const int nwires = 2001;
151  const double wire_pitch = 3*units::mm;
152  const int nregion_bins = 10; // fixme: this should come from the Response::Schema.
153  const double halfwireextent = wire_pitch * 0.5 * (nwires - 1);
154  cerr << "Max wire at pitch=" << halfwireextent << endl;
155 
156  std::vector<Pimpos> uvw_pimpos{
157  Pimpos(nwires, -halfwireextent, halfwireextent,
158  uwire, upitch, field_origin, nregion_bins),
159  Pimpos(nwires, -halfwireextent, halfwireextent,
160  vwire, vpitch, field_origin, nregion_bins),
161  Pimpos(nwires, -halfwireextent, halfwireextent,
162  wwire, wpitch, field_origin, nregion_bins)};
163 
164  // Digitization and time
165  Binning tbins(nticks, t0, t0+readout_time);
166 
167  // Diffusion
168  const int ndiffision_sigma = 3.0;
169  bool fluctuate = false; // note, "point" negates this below
170 
171  // Generate some trivial tracks
172  const double stepsize = 0.003*units::mm;
173  Gen::TrackDepos tracks(stepsize);
174 
175  // This is the number of ionized electrons for a MIP assumed by MB noise paper.
176  // note: with option "point" this is overridden below.
177  const double dqdx = 16000*units::eplus/(3*units::mm);
178  const double charge_per_depo = -(dqdx)*stepsize;
179 
180  const double event_time = t0 + 1*units::ms;
181  const Point event_vertex(1.0*units::m, 0*units::m, 0*units::mm);
182 
183  // mostly "prolonged" track in X direction
184  if (track_types.find("prolong") < track_types.size()) {
185  tracks.add_track(event_time,
186  Ray(event_vertex,
187  event_vertex + Vector(1*units::m, 0*units::m, +10*units::cm)),
188  charge_per_depo);
189  tracks.add_track(event_time,
190  Ray(event_vertex,
191  event_vertex + Vector(1*units::m, 0*units::m, -10*units::cm)),
192  charge_per_depo);
193  }
194 
195  // mostly "isochronous" track in Z direction, give spelling errors a break. :)
196  if (track_types.find("isoch") < track_types.size()) {
197  tracks.add_track(event_time,
198  Ray(event_vertex,
199  event_vertex+Vector(0, 0, 50*units::mm)),
200  charge_per_depo);
201  }
202  // "driftlike" track diagonal in space and drift time
203  if (track_types.find("driftlike") < track_types.size()) {
204  tracks.add_track(event_time,
205  Ray(event_vertex,
206  event_vertex + Vector(60*units::cm, 0*units::m, 10.0*units::mm)),
207  charge_per_depo);
208  }
209 
210  // make a +
211  if (track_types.find("plus") < track_types.size()) {
212  tracks.add_track(event_time,
213  Ray(event_vertex,
214  event_vertex+Vector(0,0,+1*units::m)),
215  charge_per_depo);
216  tracks.add_track(event_time,
217  Ray(event_vertex,
218  event_vertex+Vector(0,0,-1*units::m)),
219  charge_per_depo);
220  tracks.add_track(event_time,
221  Ray(event_vertex,
222  event_vertex+Vector(0,+1*units::m, 0)),
223  charge_per_depo);
224  tracks.add_track(event_time,
225  Ray(event_vertex,
226  event_vertex+Vector(0,-1*units::m, 0)),
227  charge_per_depo);
228  }
229 
230  // // make a .
231  if (track_types.find("point") < track_types.size()) {
232  fluctuate = false;
233  for(int i=0; i<6; i++)
234  {
235  auto vt = event_vertex + Vector(0, 0, i*0.06*units::mm);
236  auto tt = event_time + i*10.0*units::us;
237  tracks.add_track(tt,
238  Ray(vt,
239  vt + Vector(0, 0, 0.1*stepsize)), // force 1 point
240  -1.0*units::eplus);
241  }
242 
243  /* tracks.add_track(event_time, */
244  /* Ray(event_vertex, */
245  /* event_vertex + Vector(0, 0, 0.1*stepsize)), // force 1 point */
246  /* -1.0*units::eplus); */
247  }
248 
249  em("made tracks");
250 
251  // Get depos
252  auto depos = tracks.depos();
253 
254  std::cerr << "got " << depos.size() << " depos from tracks\n";
255  em("made depos");
256 
257  TFile* rootfile = TFile::Open(Form("%s-uvw.root", out_basename.c_str()), "recreate");
258  TCanvas* canvas = new TCanvas("c","canvas",1000,1000);
259  gStyle->SetOptStat(0);
260 
261  std::string pdfname = argv[0];
262  pdfname += ".pdf";
263  canvas->Print((pdfname+"[").c_str(),"pdf");
264 
265 
266  IRandom::pointer rng = nullptr;
267  if (fluctuate) {
268  rng = Factory::lookup<IRandom>("Random");
269  }
270 
271  for (int plane_id = 0; plane_id < 3; ++plane_id) {
272  em("start loop over planes");
273  Pimpos& pimpos = uvw_pimpos[plane_id];
274 
275  // add deposition to binned diffusion
276  Gen::BinnedDiffusion bindiff(pimpos, tbins, ndiffision_sigma, rng, Gen::BinnedDiffusion::ImpactDataCalculationStrategy::constant); // default is constant interpolation
277  em("made BinnedDiffusion");
278  for (auto depo : depos) {
279  auto drifted = std::make_shared<Gen::TransportedDepo>(depo, field_origin.x(), drift_speed);
280 
281  // In the real simulation these sigma are a function of
282  // drift time. Hard coded here with small values the
283  // resulting voltage peak due to "point" source should
284  // correspond to what is also shown on a per-impact
285  // "Detector Response" from util's test_impactresponse.
286  // Peak response of a delta function of current
287  // integrating over time to one electron charge would give
288  // 1eplus * 14mV/fC = 2.24 microvolt.
289  const double sigma_time = 1*units::us;
290  const double sigma_pitch = 1.5*units::mm;
291 
292  bool ok = bindiff.add(drifted, sigma_time, sigma_pitch);
293  if (!ok) {
294  std::cerr << "failed to add: t=" << drifted->time()/units::us << ", pt=" << drifted->pos()/units::mm << std::endl;
295  }
296  Assert(ok);
297 
298  std::cerr << "depo:"
299  << " q=" << drifted->charge()/units::eplus << "ele"
300  << " time-T0=" << (drifted->time()-t0)/units::us<< "us +/- " << sigma_time/units::us << " us "
301  << " pt=" << drifted->pos() / units::mm << " mm\n";
302 
303  }
304  em("added track depositions");
305 
306  auto ipir = Factory::find_tn<IPlaneImpactResponse>(pir_tns[plane_id]);
307 
308  em("looked up " + pir_tns[plane_id]);
309  {
310  const Response::Schema::PlaneResponse* pr = fr.plane(plane_id);
311  const double pmax = 0.5*ipir->pitch_range();
312  const double pstep = std::abs(pr->paths[1].pitchpos - pr->paths[0].pitchpos);
313  const int npbins = 2.0*pmax/pstep;
314  const int ntbins = pr->paths[0].current.size();
315 
316  const double tmin = fr.tstart;
317  const double tmax = fr.tstart + fr.period*ntbins;
318  TH2F* hpir = new TH2F(Form("hfr%d", plane_id), Form("Field Response %c-plane", uvw[plane_id]),
319  ntbins, tmin, tmax,
320  npbins, -pmax, pmax);
321  for (auto& path : pr->paths) {
322  const double cpitch = path.pitchpos;
323  for (size_t ic=0; ic<path.current.size(); ++ic) {
324  const double ctime = fr.tstart + ic*fr.period;
325  const double charge = path.current[ic]*fr.period;
326  hpir->Fill(ctime, cpitch, -1*charge/units::eplus);
327  }
328  }
329  hpir->SetZTitle("Induced charge [eles]");
330  hpir->Write();
331 
332  hpir->Draw("colz");
333  if (track_types.find("point") < track_types.size()) {
334  hpir->GetXaxis()->SetRangeUser(70.*units::us,100.*units::us);
335  hpir->GetYaxis()->SetRangeUser(-10.*units::mm,10.*units::mm);
336  }
337  canvas->Update();
338  //canvas->Print(Form("%s_%c_resp.png", out_basename.c_str(), uvw[plane_id]));
339  canvas->Print(pdfname.c_str(), "pdf");
340  }
341  em("wrote and leaked response hist");
342 
343  Gen::ImpactZipper zipper(ipir, bindiff);
344  em("made ImpactZipper");
345 
346  // Set pitch range for plot y-axis
347  auto rbins = pimpos.region_binning();
348  auto pmm = bindiff.pitch_range(ndiffision_sigma);
349  const int wbin0 = max(0, rbins.bin(pmm.first) - 40);
350  const int wbinf = min(rbins.nbins()-1, rbins.bin(pmm.second) + 40);
351  const int nwbins = 1+wbinf-wbin0;
352 
353  // Dead reckon
354  const int tbin0 = 3500, tbinf=5500;
355  const int ntbins = tbinf-tbin0;
356 
357  std::map<int, Waveform::realseq_t> frame;
358  double tottot=0.0;
359  for (int iwire=wbin0; iwire <= wbinf; ++iwire) {
360  auto wave = zipper.waveform(iwire);
361  auto tot = Waveform::sum(wave);
362  if (tot != 0.0) {
363  auto mm = std::minmax_element(wave.begin(), wave.end());
364  cerr << "^ Wire " << iwire << " tot=" << tot/units::uV << " uV"
365  << " mm=[" << (*mm.first)/units::uV << "," << (*mm.second)/units::uV << "] uV "
366  << endl;
367  }
368 
369  tottot += tot;
370  if (std::abs(iwire-1000) <=1) { // central wires for "point"
371  auto mm = std::minmax_element(wave.begin(), wave.end());
372  std::cerr << "central wire: " << iwire
373  << " mm=["
374  << (*mm.first)/units::microvolt << ","
375  << (*mm.second)/units::microvolt
376  << "] uV\n";
377  }
378  frame[iwire] = wave;
379  }
380  em("zipped through wires");
381  cerr << "Tottot = " << tottot << endl;
382  Assert(tottot != 0.0);
383 
384  TH2F *hist = new TH2F(Form("h%d", plane_id),
385  Form("Wire vs Tick %c-plane", uvw[plane_id]),
386  ntbins, tbin0, tbin0+ntbins,
387  nwbins, wbin0, wbin0+nwbins);
388  hist->SetXTitle("tick");
389  hist->SetYTitle("wire");
390  hist->SetZTitle("Voltage [-#muV]");
391 
392  std::cerr << nwbins << " wires: [" << wbin0 << "," << wbinf << "], "
393  << ntbins << " ticks: [" << tbin0 << "," << tbinf << "]\n";
394 
395  em("created TH2F");
396  for (auto wire : frame) {
397  const int iwire = wire.first;
398  Assert(rbins.inbounds(iwire));
399  const Waveform::realseq_t& wave = wire.second;
400  //auto tot = Waveform::sum(wave);
401  //std::cerr << iwire << " tot=" << tot << std::endl;
402  for (int itick=tbin0; itick <= tbinf; ++itick) {
403  hist->Fill(itick+0.1, iwire+0.1, -1.0*wave[itick]/units::microvolt);
404  }
405  }
406 
407  if (track_types.find("point") < track_types.size()) {
408  hist->GetXaxis()->SetRangeUser(3950,4100);
409  hist->GetYaxis()->SetRangeUser(996, 1004);
410  }
411  if (track_types.find("isoch") < track_types.size()) {
412  hist->GetXaxis()->SetRangeUser(3900,4000);
413  hist->GetYaxis()->SetRangeUser(995, 1020);
414  }
415  em("filled TH2F");
416  hist->Write();
417  em("wrote TH2F");
418  hist->Draw("colz");
419  canvas->SetRightMargin(0.15);
420  em("drew TH2F");
421  std::vector<TLine*> lines;
422  auto trqs = tracks.tracks();
423  for (size_t iline=0; iline<trqs.size(); ++iline) {
424  auto trq = trqs[iline];
425  const double time = get<0>(trq);
426  const Ray ray = get<1>(trq);
427 
428  // this need to subtract off the fr.origin is I think a bug,
429  // or at least a bookkeeping detail to ensconce somewhere. I
430  // think FR is taking the start of the path as the time
431  // origin. Something to check...
432  const int tick1 = tbins.bin(time + (ray.first.x()-fr.origin)/drift_speed);
433  const int tick2 = tbins.bin(time + (ray.second.x()-fr.origin)/drift_speed);
434 
435  const int wire1 = rbins.bin(pimpos.distance(ray.first));
436  const int wire2 = rbins.bin(pimpos.distance(ray.second));
437 
438  cerr << "digitrack: t=" << time << " ticks=["<<tick1<<","<<tick2<<"] wires=["<<wire1<<","<<wire2<<"]\n";
439 
440  const int fudge = 0;
441  TLine* line = new TLine(tick1-fudge, wire1, tick2-fudge, wire2);
442  line->Write(Form("l%c%d", uvw[plane_id], (int)iline));
443  line->Draw();
444  //canvas->Print(Form("%s_%c.png", out_basename.c_str(), uvw[plane_id]));
445  canvas->Print(pdfname.c_str(), "pdf");
446  }
447  em("printed PNG canvases");
448  em("end of PIR scope");
449 
450  //canvas->Print("test_impactzipper.pdf","pdf");
451  }
452  rootfile->Close();
453  canvas->Print((pdfname+"]").c_str(), "pdf");
454  em("done");
455 
456  //cerr << em.summary() << endl;
457  return 0;
458 }
code to link reconstructed objects back to the MC truth information
std::pair< Point, Point > Ray
A line segment running from a first (tail) to a second (head) point.
Definition: Point.h:21
const int nwires
static const double m
Definition: Units.h:79
static const double uV
Definition: Units.h:181
Sequence< real_t > realseq_t
Definition: Waveform.h:31
std::string string
Definition: nybbler.cc:12
const Binning & region_binning() const
Definition: Pimpos.h:109
static const double degree
Definition: Units.h:162
const std::string instance
double distance(const Point &pt, int axis=2) const
Definition: Pimpos.cxx:71
cfg
Definition: dbjson.py:29
const double tick
const int nticks
Binning tbins(nticks, t0, t0+readout_time)
A producer of depositions created from some number of simple, linear tracks.
Definition: TrackDepos.h:17
#define Assert
Definition: Testing.h:7
Definition: type_traits.h:56
T abs(T value)
const double t0
int bin(double val) const
Definition: Binning.h:80
std::tuple< double, double, const reco::ClusterHit3D * > Point
Definitions used by the VoronoiDiagram algorithm.
Definition: DCEL.h:34
float fC
Definition: units.py:113
static int max(int a, int b)
const double drift_speed
IFrame::pointer sum(std::vector< IFrame::pointer > frames, int ident)
Definition: FrameUtil.cxx:15
static const double mm
Definition: Units.h:73
std::vector< float > Vector
static const double us
Definition: Units.h:101
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
Pimpos pimpos(nwires, min_wire_pitch, max_wire_pitch)
static const double ms
Definition: Units.h:100
Pitch-Impact-Position.
Definition: Pimpos.h:36
static const double cm
Definition: Units.h:76
Plugin * add(const std::string &plugin_name, const std::string &libname="")
Add a plugin. If libname is not given, try to derive it.
const GenericPointer< typename T::ValueType > & pointer
Definition: pointer.h:1124
std::vector< PathResponse > paths
List of PathResponse objects.
Definition: Response.h:54
const double wire_pitch
microvolt_as<> microvolt
Type of time stored in microvolt, in double precision.
static QCString * s
Definition: config.cpp:1042
QTextStream & endl(QTextStream &s)
const double readout_time