File indexing completed on 2025-07-11 08:30:03
0001 #ifndef DDREC_DCH_INFO_H
0002 #define DDREC_DCH_INFO_H
0003
0004 #include "TMath.h"
0005
0006 #include "DDRec/DetectorData.h"
0007 #include <map>
0008 #include "TVector3.h"
0009
0010 namespace dd4hep { namespace rec {
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032 struct DCH_info_struct
0033 {
0034 public:
0035
0036
0037
0038 using DCH_layer = int;
0039
0040 using DCH_length_t = double;
0041
0042 using DCH_angle_t = double;
0043
0044 DCH_length_t Lhalf = {0};
0045
0046 DCH_length_t rin = {0};
0047
0048 DCH_length_t rout = {0};
0049
0050
0051 DCH_length_t guard_inner_r_at_z0 = {0};
0052
0053 DCH_length_t guard_outer_r_at_zL2 = {0};
0054
0055
0056 int ncell0 = {0};
0057
0058
0059
0060 int ncell_increment = {0};
0061
0062
0063 int ncell_per_sector = {0};
0064
0065
0066 DCH_layer nlayersPerSuperlayer = {0};
0067
0068
0069
0070 DCH_layer nsuperlayers = {0};
0071
0072 DCH_layer nlayers = {0};
0073
0074
0075
0076 DCH_angle_t twist_angle = {0};
0077
0078
0079 double first_width = {0};
0080
0081 DCH_length_t first_sense_r = {0};
0082
0083 void Set_lhalf(DCH_length_t _dch_Lhalf){Lhalf=_dch_Lhalf;}
0084 void Set_rin (DCH_length_t _dch_rin ){rin = _dch_rin; }
0085 void Set_rout (DCH_length_t _dch_rout ){rout = _dch_rout;}
0086
0087 void Set_guard_rin_at_z0 (DCH_length_t _dch_rin_z0_guard ){guard_inner_r_at_z0 = _dch_rin_z0_guard; }
0088 void Set_guard_rout_at_zL2(DCH_length_t _dch_rout_zL2_guard){guard_outer_r_at_zL2 = _dch_rout_zL2_guard; }
0089
0090 void Set_ncell0 (int _ncell0 ){ncell0 = _ncell0; }
0091 void Set_ncell_increment (int _ncell_increment ){ncell_increment = _ncell_increment; }
0092
0093 void Set_nlayersPerSuperlayer(int _nlayersPerSuperlayer){nlayersPerSuperlayer = _nlayersPerSuperlayer;}
0094 void Set_nsuperlayers (int _nsuperlayers ){nsuperlayers = _nsuperlayers; }
0095
0096 void Set_ncell_per_sector(int _ncell_per_sector){ncell_per_sector = _ncell_per_sector;}
0097
0098 void Set_twist_angle (DCH_length_t _dch_twist_angle ){twist_angle = _dch_twist_angle;}
0099
0100 void Set_first_width (double _first_width ){first_width = _first_width; }
0101 void Set_first_sense_r(double _first_sense_r){first_sense_r = _first_sense_r; }
0102
0103
0104
0105
0106 int Get_ncells(int ilayer){return database.at(ilayer).nwires/2;}
0107
0108
0109 DCH_angle_t Get_phi_width(int ilayer){return (TMath::TwoPi()/Get_ncells(ilayer))*dd4hep::rad;}
0110
0111
0112
0113 DCH_angle_t Get_cell_phi_angle(int ilayer, int nphi){ return (Get_phi_width(ilayer) * (nphi + 0.25*(ilayer%2)));}
0114
0115
0116
0117 int Get_nsuperlayer_minus_1(int ilayer){ return int((ilayer-1)/nlayersPerSuperlayer);}
0118
0119
0120 DCH_length_t Radius_zLhalf(DCH_length_t r_z0) const {
0121 return r_z0/cos(twist_angle/2/dd4hep::rad);
0122 }
0123
0124
0125 DCH_angle_t stereoangle_z0(DCH_length_t r_z0) const {
0126 return atan( r_z0/Lhalf*tan(twist_angle/2/dd4hep::rad));
0127 }
0128
0129
0130 DCH_angle_t stereoangle_zLhalf(DCH_length_t r_zLhalf) const {
0131 return atan( r_zLhalf/Lhalf*sin(twist_angle/2/dd4hep::rad));
0132 }
0133
0134
0135 DCH_length_t WireLength(int nlayer, DCH_length_t r_z0) const {
0136 auto Pitch_z0 = database.at(nlayer).Pitch_z0(r_z0);
0137 return 2*Lhalf/cos(atan(Pitch_z0/(2*Lhalf)))/cos(stereoangle_z0(r_z0)/dd4hep::rad) ;
0138 };
0139
0140
0141 struct DCH_info_layer
0142 {
0143
0144 DCH_layer layer = {0};
0145
0146 int nwires = {0};
0147
0148 double height_z0 = {0.};
0149
0150 double width_z0 = {0.};
0151
0152
0153 DCH_length_t radius_sw_z0 = {0.};
0154
0155
0156 DCH_length_t radius_fdw_z0 = {0.};
0157
0158
0159 DCH_length_t radius_fuw_z0 = {0.};
0160
0161
0162
0163 bool IsStereoPositive() const {
0164 return (1 == layer%2);
0165 }
0166
0167 int StereoSign() const {
0168 return (IsStereoPositive()*2 - 1);
0169 }
0170
0171
0172 DCH_length_t Pitch_z0(DCH_length_t r_z0) const {
0173 return TMath::TwoPi()*r_z0/nwires;
0174 };
0175
0176 };
0177
0178 std::map<DCH_layer, DCH_info_layer> database;
0179 bool IsDatabaseEmpty() const { return database.empty(); }
0180
0181 inline void BuildLayerDatabase();
0182 inline void Show_DCH_info_database(std::ostream& io) const;
0183
0184
0185 inline bool IsValid() const {return ((0 < Lhalf*rout) && (not IsDatabaseEmpty() ) ); }
0186
0187
0188
0189 inline DCH_layer CalculateILayerFromCellIDFields(int layer, int superlayer) const { DCH_layer ilayer = layer + (this->nlayersPerSuperlayer)*superlayer + 1; return ilayer;}
0190 inline TVector3 Calculate_hitpos_to_wire_vector(int ilayer, int nphi, const TVector3& hit_position ) const;
0191 inline TVector3 Calculate_wire_vector_ez (int ilayer, int nphi) const;
0192 inline TVector3 Calculate_wire_z0_point (int ilayer, int nphi) const;
0193 inline double Calculate_wire_phi_z0 (int ilayer, int nphi) const;
0194
0195 };
0196 typedef StructExtension<DCH_info_struct> DCH_info ;
0197 inline std::ostream& operator<<( std::ostream& io , const DCH_info& d ){d.Show_DCH_info_database(io); return io;}
0198
0199 inline void DCH_info_struct::BuildLayerDatabase()
0200 {
0201
0202 if( not this->IsDatabaseEmpty() ) return;
0203
0204 auto ff_check_positive_parameter = [](double p, std::string pname) -> void {
0205 if(p<=0)throw std::runtime_error(Form("DCH: %s must be positive",pname.c_str()));
0206 return;
0207 };
0208 ff_check_positive_parameter(this->rin ,"inner radius");
0209 ff_check_positive_parameter(this->rout ,"outer radius");
0210 ff_check_positive_parameter(this->Lhalf,"half length" );
0211
0212 ff_check_positive_parameter(this->guard_inner_r_at_z0 ,"inner radius of guard wires" );
0213 ff_check_positive_parameter(this->guard_outer_r_at_zL2,"outer radius of guard wires" );
0214
0215
0216 ff_check_positive_parameter(this->ncell0,"ncells in the first layer" );
0217 ff_check_positive_parameter(this->ncell_increment,"ncells increment per superlayer" );
0218 ff_check_positive_parameter(this->ncell_per_sector,"ncells per sector" );
0219
0220
0221
0222 if( 0 != (ncell0 % ncell_per_sector) || 0 != (ncell_increment % ncell_per_sector) )
0223 throw std::runtime_error("dch_ncell_per_sector is not divisor of dch_ncell0 or dch_ncell_increment");
0224
0225 ff_check_positive_parameter(this->nsuperlayers,"number of superlayers" );
0226 ff_check_positive_parameter(this->nlayersPerSuperlayer,"number of layers per superlayer" );
0227
0228
0229
0230 this->nlayers = this->nsuperlayers * this->nlayersPerSuperlayer;
0231
0232 ff_check_positive_parameter(this->first_width,"width of first layer cells" );
0233 ff_check_positive_parameter(this->first_sense_r,"radius of first layer cells" );
0234
0235
0236
0237 {
0238 DCH_info_layer layer1_info;
0239 layer1_info.layer = 1;
0240 layer1_info.nwires = 2*this->ncell0;
0241 layer1_info.height_z0 = first_width;
0242 layer1_info.radius_sw_z0 = first_sense_r;
0243 layer1_info.radius_fdw_z0 = first_sense_r - 0.5*first_width;
0244 layer1_info.radius_fuw_z0 = first_sense_r + 0.5*first_width;
0245 layer1_info.width_z0 = TMath::TwoPi()*first_sense_r/this->ncell0;
0246
0247 this->database.emplace(layer1_info.layer, layer1_info);
0248 }
0249
0250
0251
0252
0253 for(int ilayer = 2; ilayer<= this->nlayers; ++ilayer)
0254 {
0255
0256 DCH_info_layer layer_info;
0257
0258
0259 layer_info.layer = ilayer;
0260
0261 layer_info.nwires = 2*(this->ncell0 + this->ncell_increment*Get_nsuperlayer_minus_1(ilayer) );
0262
0263
0264 const auto& previousLayer = this->database.at(ilayer-1);
0265
0266
0267 {
0268 double h = previousLayer.height_z0;
0269 double ru = previousLayer.radius_fuw_z0;
0270 double rd = previousLayer.radius_fdw_z0;
0271
0272 if(0 == Get_nsuperlayer_minus_1(ilayer))
0273 layer_info.height_z0 = h*ru/rd;
0274 else
0275 layer_info.height_z0 = TMath::TwoPi()*ru/(0.5*layer_info.nwires - TMath::Pi());
0276
0277 layer_info.radius_sw_z0 = 0.5*layer_info.height_z0 + ru;
0278 }
0279
0280
0281 layer_info.radius_fdw_z0 = previousLayer.radius_fuw_z0;
0282 layer_info.radius_fuw_z0 = previousLayer.radius_fuw_z0 + layer_info.height_z0;
0283 layer_info.width_z0 = TMath::TwoPi()*layer_info.radius_sw_z0/(0.5*layer_info.nwires);
0284
0285
0286 if(fabs(layer_info.width_z0 - layer_info.height_z0)>1e-4)
0287 throw std::runtime_error("fabs(l.width_z0 - l.height_z0)>1e-4");
0288
0289
0290
0291 this->database.emplace(ilayer, layer_info);
0292 }
0293
0294 std::cout << "\t+ Total size of DCH database = " << database.size() << std::endl;
0295 return;
0296 }
0297
0298 inline void DCH_info_struct::Show_DCH_info_database(std::ostream & oss) const
0299 {
0300 oss << "\n";
0301 oss << "Global parameters of DCH:\n";
0302 oss << "\tGas, half length/mm = " << Lhalf/dd4hep::mm << '\n';
0303 oss << "\tGas, radius in/mm = " << rin/dd4hep::mm << '\n';
0304 oss << "\tGas, radius out/mm = " << rout/dd4hep::mm<< '\n';
0305 oss << "\tGuard, radius in(z=0)/mm = " << guard_inner_r_at_z0/dd4hep::mm << '\n';
0306 oss << "\tGuard, radius out(z=L/2)/mm = " << guard_outer_r_at_zL2/dd4hep::mm << '\n';
0307 oss << "\n";
0308 oss << "\tTwist angle (2*alpha) / deg = " << twist_angle/dd4hep::deg << '\n';
0309 oss << "\n";
0310 oss << "\tN superlayers = " << nsuperlayers << '\n';
0311 oss << "\tN layers per superlayer = " << nlayersPerSuperlayer << '\n';
0312 oss << "\tN layers = " << nlayers << '\n';
0313 oss << "\n";
0314 oss << "\tN cells layer1 = " << ncell0 << '\n';
0315 oss << "\tN cells increment per superlayer = " << ncell_increment << '\n';
0316 oss << "\tN cells per sector = " << ncell_per_sector << '\n';
0317 oss << "\n";
0318 oss << "Layer parameters of DCH:\n";
0319 oss
0320 << "\t" << "layer"
0321 << "\t" << "nwires"
0322 << "\t" << "height_z0/mm"
0323 << "\t" << "width_z0/mm"
0324 << "\t" << "radius_fdw_z0/mm"
0325 << "\t" << "radius_sw_z0/mm"
0326 << "\t" << "radius_fuw_z0/mm"
0327 << "\t" << "stereoangle_z0/deg"
0328 << "\t" << "Pitch_z0/mm"
0329 << "\t" << "radius_sw_zLhalf/mm"
0330 << "\t" << "WireLength/mm"
0331 << "\n" << std::endl;
0332
0333 if( this->IsDatabaseEmpty() )
0334 {
0335 oss << "\nDatabase empty\n";
0336 return;
0337 }
0338
0339 for(const auto& [nlayer, l] : database )
0340 {
0341 oss
0342 << "\t" << l.layer
0343 << "\t" << l.nwires
0344 << "\t" << l.height_z0/dd4hep::mm
0345 << "\t" << l.width_z0/dd4hep::mm
0346 << "\t" << l.radius_fdw_z0/dd4hep::mm
0347 << "\t" << l.radius_sw_z0/dd4hep::mm
0348 << "\t" << l.radius_fuw_z0/dd4hep::mm
0349 << "\t" << l.StereoSign()*this->stereoangle_z0(l.radius_sw_z0)/dd4hep::deg
0350 << "\t" << l.Pitch_z0(l.radius_sw_z0)/dd4hep::mm
0351 << "\t" << this->Radius_zLhalf(l.radius_sw_z0)/dd4hep::mm
0352 << "\t" << this->WireLength(l.layer,l.radius_sw_z0)/dd4hep::mm
0353 << "\n" << std::endl;
0354 }
0355 return;
0356 }
0357
0358
0359
0360
0361
0362
0363 inline TVector3 DCH_info_struct::Calculate_wire_vector_ez(int ilayer, int nphi) const {
0364 auto& l = this->database.at(ilayer);
0365
0366
0367
0368
0369
0370 int stereosign = l.StereoSign();
0371 double rz0 = l.radius_sw_z0;
0372 double dphi = this->twist_angle;
0373
0374 double kappa = (1. / this->Lhalf) * tan(dphi / 2);
0375
0376
0377
0378
0379
0380 double x1 = rz0;
0381 double y1 = -stereosign * rz0 * kappa * this->Lhalf;
0382 double z1 = -this->Lhalf;
0383
0384 TVector3 p1(x1, y1, z1);
0385
0386
0387 double x2 = rz0;
0388 double y2 = stereosign * rz0 * kappa * this->Lhalf;
0389 double z2 = this->Lhalf;
0390
0391 TVector3 p2(x2, y2, z2);
0392
0393
0394 double phi_z0 = Calculate_wire_phi_z0(ilayer, nphi);
0395 p1.RotateZ(phi_z0);
0396 p2.RotateZ(phi_z0);
0397
0398
0399
0400 return (p2 - p1).Unit();
0401 }
0402
0403 inline TVector3 DCH_info_struct::Calculate_wire_z0_point(int ilayer, int nphi) const {
0404 auto& l = this->database.at(ilayer);
0405 double rz0 = l.radius_sw_z0;
0406 TVector3 p1(rz0, 0, 0);
0407 double phi_z0 = Calculate_wire_phi_z0(ilayer, nphi);
0408 p1.RotateZ(phi_z0);
0409 return p1;
0410 }
0411
0412
0413 inline double DCH_info_struct::Calculate_wire_phi_z0(int ilayer, int nphi) const {
0414 auto& l = this->database.at(ilayer);
0415 int ncells = l.nwires / 2;
0416 double phistep = TMath::TwoPi() / ncells;
0417 double phi_z0 = (nphi + 0.25 * (l.layer % 2)) * phistep;
0418 return phi_z0;
0419 }
0420
0421
0422
0423
0424 inline TVector3 DCH_info_struct::Calculate_hitpos_to_wire_vector(int ilayer, int nphi, const TVector3& hit_position ) const {
0425
0426
0427 TVector3 n = this->Calculate_wire_vector_ez(ilayer, nphi);
0428 TVector3 a = this->Calculate_wire_z0_point(ilayer, nphi);
0429
0430
0431
0432 TVector3 a_minus_p = a - hit_position;
0433 double a_minus_p_dot_n = a_minus_p.Dot(n);
0434 TVector3 scaled_n = a_minus_p_dot_n * n;
0435
0436 return (a_minus_p - scaled_n);
0437 }
0438
0439 }}
0440
0441 #endif