File indexing completed on 2025-01-18 09:55:25
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
0009 namespace dd4hep { namespace rec {
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 struct DCH_info_struct
0032 {
0033 public:
0034
0035
0036
0037 using DCH_layer = int;
0038
0039 using DCH_length_t = double;
0040
0041 using DCH_angle_t = double;
0042
0043 DCH_length_t Lhalf = {0};
0044
0045 DCH_length_t rin = {0};
0046
0047 DCH_length_t rout = {0};
0048
0049
0050 DCH_length_t guard_inner_r_at_z0 = {0};
0051
0052 DCH_length_t guard_outer_r_at_zL2 = {0};
0053
0054
0055 int ncell0 = {0};
0056
0057
0058
0059 int ncell_increment = {0};
0060
0061
0062 int ncell_per_sector = {0};
0063
0064
0065 DCH_layer nlayersPerSuperlayer = {0};
0066
0067
0068
0069 DCH_layer nsuperlayers = {0};
0070
0071 DCH_layer nlayers = {0};
0072
0073
0074
0075 DCH_angle_t twist_angle = {0};
0076
0077
0078 double first_width = {0};
0079
0080 DCH_length_t first_sense_r = {0};
0081
0082 void Set_lhalf(DCH_length_t _dch_Lhalf){Lhalf=_dch_Lhalf;}
0083 void Set_rin (DCH_length_t _dch_rin ){rin = _dch_rin; }
0084 void Set_rout (DCH_length_t _dch_rout ){rout = _dch_rout;}
0085
0086 void Set_guard_rin_at_z0 (DCH_length_t _dch_rin_z0_guard ){guard_inner_r_at_z0 = _dch_rin_z0_guard; }
0087 void Set_guard_rout_at_zL2(DCH_length_t _dch_rout_zL2_guard){guard_outer_r_at_zL2 = _dch_rout_zL2_guard; }
0088
0089 void Set_ncell0 (int _ncell0 ){ncell0 = _ncell0; }
0090 void Set_ncell_increment (int _ncell_increment ){ncell_increment = _ncell_increment; }
0091
0092 void Set_nlayersPerSuperlayer(int _nlayersPerSuperlayer){nlayersPerSuperlayer = _nlayersPerSuperlayer;}
0093 void Set_nsuperlayers (int _nsuperlayers ){nsuperlayers = _nsuperlayers; }
0094
0095 void Set_ncell_per_sector(int _ncell_per_sector){ncell_per_sector = _ncell_per_sector;}
0096
0097 void Set_twist_angle (DCH_length_t _dch_twist_angle ){twist_angle = _dch_twist_angle;}
0098
0099 void Set_first_width (double _first_width ){first_width = _first_width; }
0100 void Set_first_sense_r(double _first_sense_r){first_sense_r = _first_sense_r; }
0101
0102
0103
0104
0105 int Get_ncells(int ilayer){return database.at(ilayer).nwires/2;}
0106
0107
0108 DCH_angle_t Get_phi_width(int ilayer){return (TMath::TwoPi()/Get_ncells(ilayer))*dd4hep::rad;}
0109
0110
0111
0112 DCH_angle_t Get_cell_phi_angle(int ilayer, int nphi){ return (Get_phi_width(ilayer) * (nphi + 0.25*(ilayer%2)));}
0113
0114
0115
0116 int Get_nsuperlayer_minus_1(int ilayer){ return int((ilayer-1)/nlayersPerSuperlayer);}
0117
0118
0119 DCH_length_t Radius_zLhalf(DCH_length_t r_z0) const {
0120 return r_z0/cos(twist_angle/2/dd4hep::rad);
0121 }
0122
0123
0124 DCH_angle_t stereoangle_z0(DCH_length_t r_z0) const {
0125 return atan( r_z0/Lhalf*tan(twist_angle/2/dd4hep::rad));
0126 }
0127
0128
0129 DCH_angle_t stereoangle_zLhalf(DCH_length_t r_zLhalf) const {
0130 return atan( r_zLhalf/Lhalf*sin(twist_angle/2/dd4hep::rad));
0131 }
0132
0133
0134 DCH_length_t WireLength(int nlayer, DCH_length_t r_z0) const {
0135 auto Pitch_z0 = database.at(nlayer).Pitch_z0(r_z0);
0136 return 2*Lhalf/cos(atan(Pitch_z0/(2*Lhalf)))/cos(stereoangle_z0(r_z0)/dd4hep::rad) ;
0137 };
0138
0139
0140 struct DCH_info_layer
0141 {
0142
0143 DCH_layer layer = {0};
0144
0145 int nwires = {0};
0146
0147 double height_z0 = {0.};
0148
0149 double width_z0 = {0.};
0150
0151
0152 DCH_length_t radius_sw_z0 = {0.};
0153
0154
0155 DCH_length_t radius_fdw_z0 = {0.};
0156
0157
0158 DCH_length_t radius_fuw_z0 = {0.};
0159
0160
0161
0162 bool IsStereoPositive() const {
0163 return (1 == layer%2);
0164 }
0165
0166 int StereoSign() const {
0167 return (IsStereoPositive()*2 - 1);
0168 }
0169
0170
0171 DCH_length_t Pitch_z0(DCH_length_t r_z0) const {
0172 return TMath::TwoPi()*r_z0/nwires;
0173 };
0174
0175 };
0176
0177 std::map<DCH_layer, DCH_info_layer> database;
0178 bool IsDatabaseEmpty() const { return database.empty(); }
0179
0180 inline void BuildLayerDatabase();
0181 inline void Show_DCH_info_database(std::ostream& io) const;
0182
0183
0184 };
0185 typedef StructExtension<DCH_info_struct> DCH_info ;
0186 std::ostream& operator<<( std::ostream& io , const DCH_info& d ){d.Show_DCH_info_database(io); return io;}
0187
0188 inline void DCH_info_struct::BuildLayerDatabase()
0189 {
0190
0191 if( not this->IsDatabaseEmpty() ) return;
0192
0193 auto ff_check_positive_parameter = [](double p, std::string pname) -> void {
0194 if(p<=0)throw std::runtime_error(Form("DCH: %s must be positive",pname.c_str()));
0195 return;
0196 };
0197 ff_check_positive_parameter(this->rin ,"inner radius");
0198 ff_check_positive_parameter(this->rout ,"outer radius");
0199 ff_check_positive_parameter(this->Lhalf,"half length" );
0200
0201 ff_check_positive_parameter(this->guard_inner_r_at_z0 ,"inner radius of guard wires" );
0202 ff_check_positive_parameter(this->guard_outer_r_at_zL2,"outer radius of guard wires" );
0203
0204
0205 ff_check_positive_parameter(this->ncell0,"ncells in the first layer" );
0206 ff_check_positive_parameter(this->ncell_increment,"ncells increment per superlayer" );
0207 ff_check_positive_parameter(this->ncell_per_sector,"ncells per sector" );
0208
0209
0210
0211 if( 0 != (ncell0 % ncell_per_sector) || 0 != (ncell_increment % ncell_per_sector) )
0212 throw std::runtime_error("dch_ncell_per_sector is not divisor of dch_ncell0 or dch_ncell_increment");
0213
0214 ff_check_positive_parameter(this->nsuperlayers,"number of superlayers" );
0215 ff_check_positive_parameter(this->nlayersPerSuperlayer,"number of layers per superlayer" );
0216
0217
0218
0219 this->nlayers = this->nsuperlayers * this->nlayersPerSuperlayer;
0220
0221 ff_check_positive_parameter(this->first_width,"width of first layer cells" );
0222 ff_check_positive_parameter(this->first_sense_r,"radius of first layer cells" );
0223
0224
0225
0226 {
0227 DCH_info_layer layer1_info;
0228 layer1_info.layer = 1;
0229 layer1_info.nwires = 2*this->ncell0;
0230 layer1_info.height_z0 = first_width;
0231 layer1_info.radius_sw_z0 = first_sense_r;
0232 layer1_info.radius_fdw_z0 = first_sense_r - 0.5*first_width;
0233 layer1_info.radius_fuw_z0 = first_sense_r + 0.5*first_width;
0234 layer1_info.width_z0 = TMath::TwoPi()*first_sense_r/this->ncell0;
0235
0236 this->database.emplace(layer1_info.layer, layer1_info);
0237 }
0238
0239
0240
0241
0242 for(int ilayer = 2; ilayer<= this->nlayers; ++ilayer)
0243 {
0244
0245 DCH_info_layer layer_info;
0246
0247
0248 layer_info.layer = ilayer;
0249
0250 layer_info.nwires = 2*(this->ncell0 + this->ncell_increment*Get_nsuperlayer_minus_1(ilayer) );
0251
0252
0253 const auto& previousLayer = this->database.at(ilayer-1);
0254
0255
0256 {
0257 double h = previousLayer.height_z0;
0258 double ru = previousLayer.radius_fuw_z0;
0259 double rd = previousLayer.radius_fdw_z0;
0260
0261 if(0 == Get_nsuperlayer_minus_1(ilayer))
0262 layer_info.height_z0 = h*ru/rd;
0263 else
0264 layer_info.height_z0 = TMath::TwoPi()*ru/(0.5*layer_info.nwires - TMath::Pi());
0265
0266 layer_info.radius_sw_z0 = 0.5*layer_info.height_z0 + ru;
0267 }
0268
0269
0270 layer_info.radius_fdw_z0 = previousLayer.radius_fuw_z0;
0271 layer_info.radius_fuw_z0 = previousLayer.radius_fuw_z0 + layer_info.height_z0;
0272 layer_info.width_z0 = TMath::TwoPi()*layer_info.radius_sw_z0/(0.5*layer_info.nwires);
0273
0274
0275 if(fabs(layer_info.width_z0 - layer_info.height_z0)>1e-4)
0276 throw std::runtime_error("fabs(l.width_z0 - l.height_z0)>1e-4");
0277
0278
0279
0280 this->database.emplace(ilayer, layer_info);
0281 }
0282
0283 std::cout << "\t+ Total size of DCH database = " << database.size() << std::endl;
0284 return;
0285 }
0286
0287 inline void DCH_info_struct::Show_DCH_info_database(std::ostream & oss) const
0288 {
0289 oss << "\n";
0290 oss << "Global parameters of DCH:\n";
0291 oss << "\tGas, half length/mm = " << Lhalf/dd4hep::mm << '\n';
0292 oss << "\tGas, radius in/mm = " << rin/dd4hep::mm << '\n';
0293 oss << "\tGas, radius out/mm = " << rout/dd4hep::mm<< '\n';
0294 oss << "\tGuard, radius in(z=0)/mm = " << guard_inner_r_at_z0/dd4hep::mm << '\n';
0295 oss << "\tGuard, radius out(z=L/2)/mm = " << guard_outer_r_at_zL2/dd4hep::mm << '\n';
0296 oss << "\n";
0297 oss << "\tTwist angle (2*alpha) / deg = " << twist_angle/dd4hep::deg << '\n';
0298 oss << "\n";
0299 oss << "\tN superlayers = " << nsuperlayers << '\n';
0300 oss << "\tN layers per superlayer = " << nlayersPerSuperlayer << '\n';
0301 oss << "\tN layers = " << nlayers << '\n';
0302 oss << "\n";
0303 oss << "\tN cells layer1 = " << ncell0 << '\n';
0304 oss << "\tN cells increment per superlayer = " << ncell_increment << '\n';
0305 oss << "\tN cells per sector = " << ncell_per_sector << '\n';
0306 oss << "\n";
0307 oss << "Layer parameters of DCH:\n";
0308 oss
0309 << "\t" << "layer"
0310 << "\t" << "nwires"
0311 << "\t" << "height_z0/mm"
0312 << "\t" << "width_z0/mm"
0313 << "\t" << "radius_fdw_z0/mm"
0314 << "\t" << "radius_sw_z0/mm"
0315 << "\t" << "radius_fuw_z0/mm"
0316 << "\t" << "stereoangle_z0/deg"
0317 << "\t" << "Pitch_z0/mm"
0318 << "\t" << "radius_sw_zLhalf/mm"
0319 << "\t" << "WireLength/mm"
0320 << "\n" << std::endl;
0321
0322 if( this->IsDatabaseEmpty() )
0323 {
0324 oss << "\nDatabase empty\n";
0325 return;
0326 }
0327
0328 for(const auto& [nlayer, l] : database )
0329 {
0330 oss
0331 << "\t" << l.layer
0332 << "\t" << l.nwires
0333 << "\t" << l.height_z0/dd4hep::mm
0334 << "\t" << l.width_z0/dd4hep::mm
0335 << "\t" << l.radius_fdw_z0/dd4hep::mm
0336 << "\t" << l.radius_sw_z0/dd4hep::mm
0337 << "\t" << l.radius_fuw_z0/dd4hep::mm
0338 << "\t" << l.StereoSign()*this->stereoangle_z0(l.radius_sw_z0)/dd4hep::deg
0339 << "\t" << l.Pitch_z0(l.radius_sw_z0)/dd4hep::mm
0340 << "\t" << this->Radius_zLhalf(l.radius_sw_z0)/dd4hep::mm
0341 << "\t" << this->WireLength(l.layer,l.radius_sw_z0)/dd4hep::mm
0342 << "\n" << std::endl;
0343 }
0344 return;
0345 }
0346 }}
0347
0348 #endif