44//
55#include " Offline/GeometryService/inc/KinKalGeomMaker.hh"
66#include " Offline/TrackerGeom/inc/Tracker.hh"
7+ #include " Offline/CosmicRayShieldGeom/inc/CosmicRayShield.hh"
78#include " Offline/GeometryService/inc/GeomHandle.hh"
89#include " Offline/KinKalGeom/inc/KinKalGeom.hh"
910#include " Offline/KinKalGeom/inc/Tracker.hh"
1011#include " Offline/KinKalGeom/inc/DetectorSolenoid.hh"
1112#include " Offline/KinKalGeom/inc/StoppingTarget.hh"
12- #include " Offline/KinKalGeom/inc/TestCRV .hh"
13+ #include " Offline/KinKalGeom/inc/CRV .hh"
1314#include " Offline/BeamlineGeom/inc/Beamline.hh"
1415#include " Offline/GeometryService/inc/DetectorSystem.hh"
1516#include " Offline/DetectorSolenoidGeom/inc/DetectorSolenoid.hh"
17+ #include " cetlib_except/exception.h"
18+ #include < cmath>
19+ #include < algorithm>
1620
1721namespace mu2e {
1822 using KinKal::VEC3 ;
@@ -29,37 +33,45 @@ namespace mu2e {
2933 using FruPtr = std::shared_ptr<KinKal::Frustrum>;
3034 using SurfacePtr = std::shared_ptr<KinKal::Surface>;
3135 using KKGMap = std::multimap<SurfaceId,SurfacePtr>;
36+ using mu2e::KKGeom::KKCRVSector;
37+
3238
3339 std::unique_ptr<KinKalGeom>& KinKalGeomMaker::makeKKG () {
3440 kkg_ = std::make_unique<KinKalGeom>();
3541 makeTracker ();
3642 makeDS ();
3743 makeTarget ();
38- makeTCRV ();
44+ makeCRV ();
3945 return kkg_;
4046 }
4147
48+ // sort by transverse distance
49+ struct sortCRVSectors {
50+ bool operator () (KKCRVSector const & sect1, KKCRVSector const & sect2) {
51+ return sect1.sector_ ->center ().Rho () > sect2.sector_ ->center ().Rho (); // put largest distance first as cosmic rays (generally) go outside-in (downwards)
52+ }
53+ }crvsectorsort;
54+
4255 void KinKalGeomMaker::makeTracker () {
4356 // surfaces need to match with virtual detectors. The following is extracted from VirtualDetectorMaker and needs to be updated if that changes.
4457 // Note that these are placed at the center of the VDs, which have half-thickness of 0.01mm. Since the VD hits are recorded where the SimParticle
4558 // enters the volume, the reco track will be sampled at a different position depending on the track direction by that amount. This is a fundamental
4659 // discrepancy between reco and sim data
4760 auto const & tracker = *(GeomHandle<mu2e::Tracker>());
48- GeomHandle<Beamline> bg;
49- GeomHandle<DetectorSystem> det;
50- GeomHandle<DetectorSolenoid> ds;
61+ auto const & g4tmom = tracker.g4Tracker ()->mother ();
62+ auto const & ds = *(GeomHandle<DetectorSolenoid>());
5163 double vdHL (0.01 ); // hardcoded in VirtualDetectorMaker line 56
5264 // below are from VirtualDetectorMaker lnes 241-244
53- double zFrontGlobal = tracker. g4Tracker ()-> mother (). position ().z ()-tracker. g4Tracker ()-> mother () .tubsParams ().zHalfLength ()-vdHL;
54- double zBackGlobal = tracker. g4Tracker ()-> mother (). position ().z ()+tracker. g4Tracker ()-> mother () .tubsParams ().zHalfLength ()+vdHL;
65+ double zFrontGlobal = g4tmom. position ().z ()-g4tmom .tubsParams ().zHalfLength ()-vdHL;
66+ double zBackGlobal = g4tmom. position ().z ()+g4tmom .tubsParams ().zHalfLength ()+vdHL;
5567 // the 0.4 below comes from offsets in the mother volume nesting.
5668 double zFrontLocal = zFrontGlobal - tracker.g4Tracker ()->z0 () + 0.4 ;
5769 double zBackLocal = zBackGlobal - tracker.g4Tracker ()->z0 () - 0.4 ;
5870 double zMidLocal = 10.1 ; // 10.1 is hard-coded in VirtualDetectorMaker line 224
5971 double halfLen = 0.5 *(zBackLocal-zFrontLocal);
60- double orvd = tracker. g4Tracker ()-> mother () .tubsParams ().outerRadius ();
72+ double orvd = g4tmom .tubsParams ().outerRadius ();
6173 double irvd = tracker.g4Tracker ()->getInnerTrackerEnvelopeParams ().innerRadius ();
62- double irds = ds-> rIn1 ();
74+ double irds = ds. rIn1 ();
6375 // cylinders are defined by TT_outer (_inner) virtual detectors
6476 // Disks are defined to match TT_front (mid, back) virtual detectors
6577 auto outer = std::make_shared<Cylinder>(VEC3 (0.0 ,0.0 ,1.0 ),VEC3 (0.0 ,0.0 ,zMidLocal),orvd,halfLen);
@@ -160,16 +172,113 @@ namespace mu2e {
160172 kkg_->st_ = std::make_unique<KKGeom::StoppingTarget>(outer,inner,front,back,foils);
161173 }
162174
163- void KinKalGeomMaker::makeTCRV () {
164- // currently use hard-coded geometry
165- auto ex1= std::make_shared<Rectangle>(VEC3 (0.0 ,1.0 ,0.0 ),VEC3 (1.0 ,0.0 ,0.0 ), VEC3 (0.0 ,4775 ,-438 ),3000 ,1675 ); // layer widths are approximate FIXME
166- auto t1= std::make_shared<Rectangle>(VEC3 (0.0 ,1.0 ,0.0 ),VEC3 (0.0 ,0.0 ,1.0 ), VEC3 (0.0 ,4625 ,-438 ),1185 ,850 );
167- auto t2= std::make_shared<Rectangle>(VEC3 (0.0 ,1.0 ,0.0 ),VEC3 (1.0 ,0.0 ,0.0 ), VEC3 (0.0 ,4925 ,-438 ),1600 ,850 );
168-
169- kkg_->map_ .emplace (std::make_pair (SurfaceId (SurfaceIdEnum::TCRV ,0 ),std::static_pointer_cast<Surface>(t1)));
170- kkg_->map_ .emplace (std::make_pair (SurfaceId (SurfaceIdEnum::TCRV ,1 ),std::static_pointer_cast<Surface>(ex1)));
171- kkg_->map_ .emplace (std::make_pair (SurfaceId (SurfaceIdEnum::TCRV ,2 ),std::static_pointer_cast<Surface>(t2)));
175+ void KinKalGeomMaker::makeCRV () {
176+ GeomHandle<CosmicRayShield> CRS ;
177+ GeomHandle<DetectorSystem> det;
178+ auto const & shields = CRS ->getCRSScintillatorShields ();
179+ std::vector<KKCRVSector> sectors;
180+ // loop over the shields (= sectors)
181+ for (auto const & shield : shields) {
182+ //
183+ // First find this shield's orientation; the first bar is enough for that
184+ //
185+ auto const & firstbar = shield.getFirstBar ();
186+ auto fbarpos = VEC3 (det->toDetector (firstbar.getPosition ())); // convert to detector (tracker) coordinates and root vectors
187+ auto bardet = firstbar.getBarDetail ();
188+ // normal (w) direction is the thickness direction. Make sure it points away from the tracker
189+ VEC3 wdir;
190+ switch (bardet.getThicknessDirection ()) {
191+ case 0 :
192+ wdir = VEC3 (copysign (1.0 ,fbarpos.X ()),0.0 ,0.0 );
193+ break ;
194+ case 1 :
195+ wdir = VEC3 (0.0 ,copysign (1.0 ,fbarpos.Y ()),0.0 );
196+ break ;
197+ case 2 :
198+ wdir = VEC3 (0.0 ,0.0 ,copysign (1.0 ,fbarpos.Z ()));
199+ break ;
200+ default :
201+ throw cet::exception (" Service" )<<" invalid direction " << bardet.getThicknessDirection () << std::endl;
202+ break ;
203+ }
204+ // u direction points along the bars (length direction). Sign is unimportant.
205+ VEC3 udir;
206+ switch (bardet.getLengthDirection ()) {
207+ case 0 :
208+ udir = VEC3 (1.0 ,0.0 ,0.0 );
209+ break ;
210+ case 1 :
211+ udir = VEC3 (0.0 ,1.0 ,0.0 );
212+ break ;
213+ case 2 :
214+ udir = VEC3 (0.0 ,0.0 ,1.0 );
215+ break ;
216+ default :
217+ throw cet::exception (" Service" )<<" invalid direction " << bardet.getLengthDirection () << std::endl;
218+ break ;
219+ }
220+ // v points along bar width
221+ VEC3 vdir;
222+ switch (bardet.getWidthDirection ()) {
223+ case 0 :
224+ vdir = VEC3 (1.0 ,0.0 ,0.0 );
225+ break ;
226+ case 1 :
227+ vdir = VEC3 (0.0 ,1.0 ,0.0 );
228+ break ;
229+ case 2 :
230+ vdir = VEC3 (0.0 ,0.0 ,1.0 );
231+ break ;
232+ default :
233+ throw cet::exception (" Service" )<<" invalid direction " << firstbar.getBarDetail ().getWidthDirection () << std::endl;
234+ break ;
235+ }
236+ // next compute the average position. All the bars have the same position along their length
237+ double upos = fbarpos.Dot (udir);
238+ double uhw = firstbar.getHalfLength ();
239+ // average first and last layers to get the w position and half-width
240+ auto const & firstmod = shield.getModule (0 );
241+ auto flaypos = VEC3 (det->toDetector (firstmod.getLayer (0 ).getPosition ()));
242+ auto llaypos = VEC3 (det->toDetector (firstmod.getLayer (firstmod.nLayers ()-1 ).getPosition ()));
243+ double wpos = 0.5 *(flaypos+llaypos).Dot (wdir);
244+ double whw = 0.5 *(llaypos-flaypos).Dot (wdir) + firstbar.getHalfThickness ();
245+ // include the layer stagger when computing the position and width perp to the bars
246+ auto nlay = firstmod.nLayers ();
247+ auto nbar = firstmod.getLayer (0 ).nBars ();
248+ auto const & lastmod = shield.getModule (shield.nModules ()-1 );
249+ auto vf0 = VEC3 (det->toDetector (firstmod.getLayer (0 ).getBar (0 ).getPosition ())).Dot (vdir);
250+ auto vf3 = VEC3 (det->toDetector (firstmod.getLayer (nlay-1 ).getBar (0 ).getPosition ())).Dot (vdir);
251+ auto vl0 = VEC3 (det->toDetector (lastmod.getLayer (0 ).getBar (nbar-1 ).getPosition ())).Dot (vdir);
252+ auto vl3 = VEC3 (det->toDetector (lastmod.getLayer (nlay-1 ).getBar (nbar-1 ).getPosition ())).Dot (vdir);
253+ double vpos = 0.25 *(vf0+vf3+vl0+vl3);
254+ double vmin = std::min ({vf0,vf3,vl0,vl3});
255+ double vmax = std::max ({vf0,vf3,vl0,vl3});
256+ double vhw = 0.5 *(vmax-vmin)+ firstbar.getHalfWidth ();
257+ VEC3 midpoint = upos*udir + vpos*vdir + wpos*wdir;
258+ // create the rectangle
259+ KKCRVSector sector;
260+ sector.sname_ = shield.getName ();
261+ sector.sector_ = std::make_shared<KinKal::Rectangle>(wdir,udir,midpoint,uhw,vhw);
262+ sector.whw_ = whw;
263+ sectors.push_back (sector);
264+ }
265+ // sort the sectors according to their transverse distance (largest first), to optimize searching for downward going tracks.
266+ std::sort (sectors.begin (),sectors.end (),crvsectorsort);
267+ if (debug_ > 0 ){
268+ for (auto const & sector : sectors){
269+ std::cout << " CRV sector " << sector.sname_ ;
270+ auto const & sectptr = sector.sector_ ;
271+ std::cout << " midpoint " << sectptr->center () << " wdir " << sectptr->normal () << " udir " << sectptr->uDirection () << " vdir " << sectptr->vDirection ()
272+ << " uhw " << sectptr->uHalfLength () << " vhw " << sectptr->vHalfLength () << " whw " << sector.whw_ << std::endl;
273+ }
274+ }
172275
173- kkg_->tcrv_ = std::make_unique<KKGeom::TestCRV>(ex1,t1,t2);
276+ kkg_->crv_ = std::make_unique<KKGeom::CRV >(sectors);
277+ // fill map
278+ unsigned isect (0 );
279+ for (auto const & sector : kkg_->crv_ ->sectors ()){
280+ kkg_->map_ .emplace (std::make_pair (SurfaceId (sector.sname_ ),std::static_pointer_cast<Surface>(sector.sector_ )));
281+ isect++;
282+ }
174283 }
175284}
0 commit comments