3 #include "art/Framework/Principal/Event.h"
4 #include "art/Framework/Core/EDProducer.h"
6 #include "WireCellIface/IDepo.h"
7 #include "WireCellGen/GaussianDiffusion.h"
8 #include "WireCellUtil/NamedFactory.h"
9 #include "WireCellUtil/Units.h"
15 using namespace WireCell;
23 WireCell::Configuration SimChannelSink::default_configuration()
const
26 cfg[
"anodes_tn"] = Json::arrayValue;
27 cfg[
"anode"] =
"AnodePlane";
28 cfg[
"rng"] =
"Random";
29 cfg[
"artlabel"] =
"simpleSC";
30 cfg[
"start_time"] = -1.6*units::ms;
31 cfg[
"readout_time"] = 4.8*units::ms;
32 cfg[
"tick"] = 0.5*units::us;
34 cfg[
"drift_speed"] = 1.098*units::mm/units::us;
35 cfg[
"uboone_u_to_rp"] = 94*units::mm;
36 cfg[
"uboone_v_to_rp"] = 97*units::mm;
37 cfg[
"uboone_y_to_rp"] = 100*units::mm;
38 cfg[
"u_time_offset"] = 0.0*units::us;
39 cfg[
"v_time_offset"] = 0.0*units::us;
40 cfg[
"y_time_offset"] = 0.0*units::us;
41 cfg[
"g4_ref_time"] = -4050*units::us;
42 cfg[
"use_energy"] =
false;
43 cfg[
"use_extra_sigma"] =
false;
47 void SimChannelSink::configure(
const WireCell::Configuration& cfg)
50 auto anodes_tn = cfg[
"anodes_tn"];
51 for (
auto anode_tn: anodes_tn) {
52 auto anode = Factory::find_tn<IAnodePlane>(anode_tn.asString());
53 m_anodes.push_back(anode);
62 for (
auto& anode: m_anodes){
63 for (
auto& channel: anode->channels()){
70 if (m_anodes.empty()) {
71 const std::string anode_tn = cfg[
"anode"].asString();
72 if (anode_tn.empty()) {
73 THROW(ValueError() << errmsg{
"SimChannelSink requires an anode plane"});
75 auto anode = Factory::find_tn<IAnodePlane>(anode_tn);
76 m_anodes.push_back(anode);
79 const std::string rng_tn = cfg[
"rng"].asString();
81 THROW(ValueError() << errmsg{
"SimChannelSink requires a noise source"});
83 m_rng = Factory::find_tn<IRandom>(rng_tn);
85 m_artlabel = cfg[
"artlabel"].asString();
86 m_artlabel =
get(cfg,
"artlabel",m_artlabel);
87 m_start_time =
get(cfg,
"start_time",-1.6*units::ms);
88 m_readout_time =
get(cfg,
"readout_time",4.8*units::ms);
89 m_tick =
get(cfg,
"tick",0.5*units::us);
90 m_nsigma =
get(cfg,
"nsigma",3.0);
91 m_drift_speed =
get(cfg,
"drift_speed",1.098*units::mm/units::us);
92 m_u_to_rp =
get(cfg,
"uboone_u_to_rp",94*units::mm);
93 m_v_to_rp =
get(cfg,
"uboone_v_to_rp",97*units::mm);
94 m_y_to_rp =
get(cfg,
"uboone_y_to_rp",100*units::mm);
96 if (cfg.isMember(
"u_to_rp")) m_u_to_rp =
get(cfg,
"u_to_rp",90.58*units::mm);
97 if (cfg.isMember(
"v_to_rp")) m_v_to_rp =
get(cfg,
"v_to_rp",95.29*units::mm);
98 if (cfg.isMember(
"y_to_rp")) m_y_to_rp =
get(cfg,
"y_to_rp",100.0*units::mm);
100 m_u_time_offset =
get(cfg,
"u_time_offset",0.0*units::us);
101 m_v_time_offset =
get(cfg,
"v_time_offset",0.0*units::us);
102 m_y_time_offset =
get(cfg,
"y_time_offset",0.0*units::us);
103 m_g4_ref_time =
get(cfg,
"g4_ref_time",-4050*units::us);
104 m_use_energy =
get(cfg,
"use_energy",
false);
105 m_use_extra_sigma =
get(cfg,
"use_extra_sigma",
false);
109 void SimChannelSink::produces(art::ProducesCollector& collector)
111 collector.
produces< std::vector<sim::SimChannel> >(m_artlabel);
114 void SimChannelSink::save_as_simchannel(
const WireCell::IDepo::pointer& depo){
122 double response_plane = 10.0 * units::cm;
123 double response_time_offset = response_plane / m_drift_speed;
124 int response_nticks = (int)(response_time_offset / m_tick);
125 Binning tbins(m_readout_time/m_tick + response_nticks, m_start_time - response_time_offset, m_start_time+m_readout_time);
133 for (
auto anode: m_anodes) {
134 for(
auto face : anode->faces()){
135 auto boundbox = face->sensitive();
136 if(!boundbox.inside(depo->pos()))
continue;
140 for (
auto plane : face->planes()) {
142 int iplane = plane->planeid().index();
143 if (iplane<0)
continue;
144 const Pimpos* pimpos = plane->pimpos();
145 auto& wires = plane->wires();
147 const double center_time = depo->time();
148 const double center_pitch = pimpos->distance(depo->pos());
150 double sigma_L = depo->extent_long();
151 if (m_use_extra_sigma) {
153 double time_slice_width = nrebin * m_drift_speed * m_tick;
154 double add_sigma_L = 1.428249 * time_slice_width / nrebin / (m_tick/units::us);
155 sigma_L = sqrt( pow(depo->extent_long(),2) + pow(add_sigma_L,2) );
157 Gen::GausDesc time_desc(center_time, sigma_L / m_drift_speed);
160 double nmin_sigma = time_desc.distance(tbins.min());
161 double nmax_sigma = time_desc.distance(tbins.max());
163 double eff_nsigma = depo->extent_long() / m_drift_speed>0?m_nsigma:0;
164 if (nmin_sigma > eff_nsigma || nmax_sigma < -eff_nsigma) {
170 auto wbins = pimpos->region_binning();
172 double sigma_T = depo->extent_tran();
173 if (m_use_extra_sigma) {
174 double add_sigma_T = wbins.binsize();
175 if (iplane==0) add_sigma_T *= (0.402993*0.3);
176 else if (iplane==1) add_sigma_T *= (0.402993*0.5);
177 else if (iplane==2) add_sigma_T *= (0.188060*0.2);
178 sigma_T = sqrt( pow(depo->extent_tran(),2) + pow(add_sigma_T,2) );
180 Gen::GausDesc pitch_desc(center_pitch, sigma_T);
183 double nmin_sigma = pitch_desc.distance(wbins.min());
184 double nmax_sigma = pitch_desc.distance(wbins.max());
186 double eff_nsigma = depo->extent_tran()>0?m_nsigma:0;
187 if (nmin_sigma > eff_nsigma || nmax_sigma < -eff_nsigma) {
192 auto gd = std::make_shared<Gen::GaussianDiffusion>(depo, time_desc, pitch_desc);
193 gd->set_sampling(tbins, wbins, m_nsigma, 0, 1);
197 double energy = 100.0;
199 id = depo->prior()->id();
200 if(m_use_energy){ energy = depo->prior()->energy(); }
204 if(m_use_energy){ energy = depo->energy(); }
207 const auto patch = gd->patch();
208 const int poffset_bin = gd->poffset_bin();
209 const int toffset_bin = gd->toffset_bin();
210 const int np = patch.rows();
211 const int nt = patch.cols();
214 int max_imp = wbins.nbins();
216 for (
int pbin = 0; pbin != np; pbin++){
217 int abs_pbin = pbin + poffset_bin;
218 if (abs_pbin < min_imp || abs_pbin >= max_imp)
continue;
220 auto iwire = wires[abs_pbin];
221 int channel = iwire->channel();
226 auto channelData = m_mapSC.find(channel);
229 : channelData->second;
231 for (
int tbin = 0; tbin!= nt; tbin++){
232 int abs_tbin = tbin + toffset_bin;
233 double charge = patch(pbin, tbin);
234 double tdc = tbins.center(abs_tbin);
238 tdc = tdc + (m_u_to_rp/m_drift_speed) + m_u_time_offset;
242 tdc = tdc + (m_v_to_rp/m_drift_speed) + m_v_time_offset;
246 tdc = tdc + (m_y_to_rp/m_drift_speed) + m_y_time_offset;
250 WireCell::IDepo::pointer orig = depo_chain(depo).back();
251 xyz[0] = orig->pos().x()/units::cm;
252 xyz[1] = orig->pos().y()/units::cm;
253 xyz[2] = orig->pos().z()/units::cm;
255 unsigned int temp_time = (
unsigned int) ( (tdc - m_g4_ref_time) / m_tick );
256 charge =
abs(charge);
268 void SimChannelSink::visit(art::Event & event)
270 std::unique_ptr<std::vector<sim::SimChannel> > out(
new std::vector<sim::SimChannel>);
272 for(
auto&
m : m_mapSC){
273 out->emplace_back(
m.second);
276 event.put(std::move(out), m_artlabel);
278 for (
auto& elem: m_mapSC){
284 bool SimChannelSink::operator()(
const WireCell::IDepo::pointer& indepo,
285 WireCell::IDepo::pointer& outdepo)
290 save_as_simchannel(m_depo);
virtual void produces(art::ProducesCollector &collector)
IArtEventVisitor.
Energy deposited on a readout channel by simulated tracks.
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
for($it=0;$it< $RaceTrack_number;$it++)
WIRECELL_FACTORY(wclsChannelNoiseDB, wcls::ChannelNoiseDB, wcls::IArtEventVisitor, WireCell::IChannelNoiseDatabase) using namespace WireCell
void AddIonizationElectrons(TrackID_t trackID, TDC_t tdc, double numberElectrons, double const *xyz, double energy, TrackID_t origTrackID=util::kBogusI)
Add ionization electrons and energy to this channel.