LDMX Software
CDFSiSensorSim.cxx
1#include "Tracking/Digitization/CDFSiSensorSim.h"
2
3/*
4
5//TODO:: use ldmx logger instead
6std::map<ChargeCarrier,SiElectrodeDataCollection> computeElectrodeData() {
7
8 if (debug_) {
9
10 //std::cout<<__PRETTY_FUNCTION__<<" sensor " <<std::endl;
11 //std::cout<<" Sense Strips: "
12 }
13
14 depositChargeOneSense();
15 transferChargeToReadout();
16
17 return readout_data_;
18
19
20}
21
22
23//Clear readout data
24
25void clearReadout() {
26
27 for (auto pair : readout_data_) {
28
29 readout_data_[pair.first].clear();
30 }
31}
32
33//Clear sense data
34void clearSense() {
35
36 for (auto pair : sense_dat_) {
37 sense_data[pair.first].clear();
38 }
39
40}
41
42//TODO Implement
43void lorentzCorrect(const Acts::Vector3& position, const ChargeCarrier& carrier)
44{
45
46}
47
48//TODO:: Implement
49void depositChargeOnSense() {
50 //if (debug_)
51 // std::cout<<__PRETTY_FUNCTION__<<" depositChargeOnSense for sensor " <<
52std:endl;
53
54 //for (auto& carrier : tracking::digitization::ChargeCarriers) {
55
56
57 //if (sensor_.hasElectrodesOnSide(carrier)) {
58
59 //Use local origin to compute the drift direction
60 //drift_direction_[carrier] = driftDirection(carrier,
61Acts::Vector3(0.,0.,0.));
62 // }
63 //}
64
65 //Acts::Transform3 global_to_sensor =
66sensor_.getGeometry().getGlobalToLocal();
67 //std::vector<ldmx::SimTrackerHit> hits = sensor_.getReadout().getHits();
68
69 for (auto& hit : hits) {
70
71 Acts::Vector3
72hitPosition(hit.getPosition()[0],hit.getPosition()[1],hit.getPosition()[2]);
73
74
75 if (debug_) {
76 std::cout<<__PRETTY_FUNCTION__<<"Hit Point:
77["<<hitPosition(0)<<","<<hitPosition(1)<<","<<hitPosition(2)<<std::endl;
78
79 }
80
81 TrackSegment track_segment = new TrackSegment(hit);
82 track_segment.transform(global_to_sensor);
83
84 int nsegments = 0;
85
86 for (auto& carrier : tracking::digitization::carriers) {
87
88 if (sensor_.hasElectrodeOnSide(carrier))
89 nsegments = std::max(nsegments, nSegments(track_segment, carrier,
90deposition_granularity));
91
92 }
93
94 double segment_length = track_segment.getLength() / nsegments;
95 double segment_charge = (track_segment.getEloss() / nsegment ) /
96sensor_.getBulk().ENERGY_EHPAIR;
97
98 Acts::Vector3 segment_step = segment_length *
99track_segment.getDirection(); Acts::Vector3 segment_center =
100track_segment.getP1() + (0.5 * segment_step);
101
102 if (debug_) {
103 std::cout<<"segment length " << segment_length << std::endl;
104 std::cout<<"segment charge " << segment_charge << std::endl;
105 std::cout<<"segment step " << segment_step << std::endl;
106 }
107
108 for ( int iseg = 0 ; iseg < nsegments; iseg++) {
109 if (debug_)
110 std::cout<<"segment "<< iseg<<" segment center"<<std::endl;
111
112 for (auto& carrier : tracking::digitization::carriers) {
113
114 if (sensor_.hasElectrodesOnSide(carrier)) {
115
116 SiSensorElectrodes electrodes = sensor_.getSenseElectrodes(carrier);
117
118 //Apply collection inefficiency for charge trapping: require between 0
119and 1
120
121 double collection_efficiency = 1.0 - 10 * trapping_*
122 driftVector(segment_center,carrier).norm();
123
124 collection_efficiency = std::max(0.0,
125std::min(1.0,collection_efficiency));
126
127 segment_charge *= collection_efficiency;
128
129 ChargeDistribution charge_distribution =
130diffusionDistribution(segment_charge, segment_center, carrier);
131 charge_distribution.trasnform(electrodes.getParentToLocal());
132
133 std::map<int,int> sense_charge =
134electrodes.computeElectrodeData(charge_distribution);
135
136 sense_data[carrier].add(SiElectrodeDataCollection(sense_charge,hit));
137
138 } // has electrodes
139 }//loop on carriers
140 }// loop on segments
141 }//loop on hits
142}//deposit charge on sense
143
144
145//Calculate charge distribution for carrier
146ChargeDistribution diffusionDistribution(double segment_charge,
147 const Acts::Vector3& origin,
148 const ChargeCarrier& carrier) {
149
150 if (debug_)
151 std::cout<<__PRETTY_FUNCTION__<<" calculating charge distribution for
152carrier"<<std::endl;
153
154 double distance = sensor_.distanceFromSide(origin, carrier);
155 double thickness = sensor_.getThickness();
156
157 if (distance < -distance_error_threshold || distance >
158distance_error_threshold) { std::cout<<"ERROR::"<<__PRETTY_FUNCTION__<<"
159Distance is outside of sensor by more than
160"<<distance_error_threshold<<std::endl;
161 }
162
163 else if (distance < 0.)
164 distance = 0.;
165 else if (distance > thickness)
166 distance = thickness;
167
168
169 double bias_voltage = sensor_.getBiasVoltage();
170 double depletion_voltage = sensor_.getDepletionVoltage();
171
172 //Common factors
173
174 double deltaV = bias_voltage - depletionVoltage;
175 double sumV = bias_voltage + deplettionVoltage;
176 double common_factor = 2.0 * distance * depletion_voltage / thickness;
177
178
179 // Calculate charge spreading without magnetic field
180
181 double sigmaq = sensor_.getBulk().K_BOLTZMANN *
182sensor_.getBulk().getTemperature() * thickness*thickness / depletion_voltage;
183
184 // If the bulk is n-type and the carrier are holes, then evaluate to true
185 // if the bulk is p-type and the carrier are electrons, then evaluate to true
186 // false otherwise
187
188 if (sensor_.getBulk().isNtype() == (carrier.getCharge() == 1 ))
189 sigmasq *= std::log(sumV / (sumV - common_factor));
190 else
191 sigmasq *= std::log((deltaV + common_factor) / deltaV);
192
193 double sigma = std::sqrt(sigmasq);
194
195 if (debug_)
196 std::cout<<__PRETTY_FUNCTION__<<" sigma = " << sigma<<std::endl;
197
198 // Corrections for magnetic field -- this is an approximation, may have to be
199done better for high fields
200
201 // Special case if field is parallel to drift direction
202
203 Acts::Vector3 drift_direction = drift_direction[carrier];
204 Acts::Vector3 bias_surface_normal =
205sensor_.getBiasSurface(carrier).getNormal();
206
207 Acts::Vector3 major_axis, minor_axis;
208 double major_axis_length, minor_axis_length;
209
210 double angular_tolerance = 1.e-9;
211
212 if ( (drift_direction.cross(bias_surface_normal)).norm() < angular_tolerance)
213{
214
215
216 major_axis =
217bias_surface_normal.cross(sensor_.getBiasSurface(carrier).getEdges().get(0).getDirection());
218 minor_axis = bias_surface_normal.cross(major_axis);
219
220 major_axis_length = sigma;
221 minor_axis_length = major_axis_length;
222 }
223 else {
224
225 Acts::Vector3 tmp = drift_direction_[carrier].cross(bias_surface_normal);
226 major_axis = bias_surface_normal.cross(tmp);
227 major_axis = major_axis / major_axis.norm();
228
229 minor_axis = bias_surface_normal.cross(major_axis);
230
231 // Project-to-plane would definitely be convenient here!!!
232
233 double cos_theta_lorentz =
234drift_direction_[carrier].dot(bias_surface_normal);
235
236 //drift time correction
237 minor_axis_length = sigma * (1. / cos_theta_lorentz);
238
239 // + drift time correction
240 major_axis_length = minor_axis_length * (1. / cos_theta_lorentz);
241
242 }
243
244 major_axis = major_axis_length * major_axis;
245 minor_axis = minor_axis_length * minor_axis;
246
247 // FIXME: this has a Z component!!! (is that OK?? I think the whole thing
248transforms into the electrode coordinates before integrating charge.)
249
250 Acts::Vector3 drift_destination = driftDestination(origin,carrier);
251
252
253 GaussianDistribution2D distribution(segment_charge,
254drift_destination,major_axis,minor_axis);
255
256 return distribution;
257
258}
259
260*/