Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:15:56

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2024 Alex Jentsch
0003 
0004 #include "DD4hep/DetFactoryHelper.h"
0005 #include "DD4hep/Printout.h"
0006 #include "TMath.h"
0007 #include <XML/Helper.h>
0008 
0009 using namespace std;
0010 using namespace dd4hep;
0011 
0012 static Ref_t create_detector(Detector& det, xml_h e, SensitiveDetector /* sens */) {
0013 
0014   using namespace ROOT::Math;
0015   xml_det_t x_det = e;
0016   string det_name = x_det.nameStr();
0017   DetElement sdet(det_name, x_det.id());
0018   Assembly assembly(det_name + "_assembly");
0019   Material m_Al    = det.material("Aluminum");
0020   Material m_Be    = det.material("Beryllium");
0021   Material m_SS    = det.material("StainlessSteel");
0022   Material m_vac   = det.material("Vacuum");
0023   string vis_name  = x_det.visStr();
0024   xml_comp_t x_pos = x_det.position();
0025 
0026   PlacedVolume pv_assembly;
0027 
0028   double b0_hadron_tube_inner_r = 2.9 * dd4hep::cm;
0029   double b0_hadron_tube_outer_r = 3.1 * dd4hep::cm;
0030   double b0_hadron_tube_length  = 120.0 * dd4hep::cm;
0031 
0032   double pipeThickness = 5.0 * dd4hep::mm;
0033 
0034   struct beampipe_dimensions_t {
0035     Double_t length        = 0.0;
0036     Double_t innerXRadius  = 0.0;
0037     Double_t innerYRadius  = 0.0;
0038     Double_t outerXRadius  = 0.0;
0039     Double_t outerYRadius  = 0.0;
0040     Double_t xCenter       = 0.0;
0041     Double_t yCenter       = 0.0;
0042     Double_t zCenter       = 0.0;
0043     Double_t rotationAngle = 0.0;
0044   };
0045 
0046   std::vector<beampipe_dimensions_t> beampipe_dimensions;
0047 
0048   double globRotationAngle =
0049       -0.0454486856; //This is the angle of the proton orbit from the end of B1APF to the beginning of B2PF
0050   double crossingAngle = -0.025; //relevant for the neutral cone
0051 
0052   double b0PFCenter_z =
0053       x_pos
0054           .z(); // location of the center of B0 magnet, used to define the hadron beampipe inside the magnet
0055 
0056   double b1APFEndPoint_z =
0057       22062.3828 * dd4hep::mm;                    //location of proton orbit at b1APF exit -- in mm
0058   double b1APFEndPoint_x = 654.3372 * dd4hep::mm; //location of proton orbit at b1APF exit -- in mm
0059 
0060   double tmp_endpoint_z = 0.0;
0061   double tmp_endpoint_x = 0.0;
0062 
0063   //forumula -> Z = b1APFEndPoint_z+((0.5*elementLengt)*Cos(globRotationAngle))
0064   //forumula -> X = b1APFEndPoint_z+((0.5*elementLengt)*Sin(globRotationAngle))
0065 
0066   //------------------------------------------------------------------------------------
0067   //Geometry extracted from version 0 VPC drawings shown at the FF preliminary
0068   //design review in February 2024 -- CAD model not available as of April 1st, 2024
0069   //------------------------------------------------------------------------------------
0070 
0071   //------------------------------------------------------------------------------------
0072   //primary pipe after B1APF, before neutral exit window + transition to smaller pipe
0073   //rectangular cross-section!!!!!
0074   //------------------------------------------------------------------------------------
0075 
0076   beampipe_dimensions.push_back({.length        = 7615.486 * dd4hep::mm, //from VPC drawings, in mm
0077                                  .innerXRadius  = 275.0 * dd4hep::mm,
0078                                  .innerYRadius  = 175.0 * dd4hep::mm,
0079                                  .rotationAngle = globRotationAngle});
0080 
0081   beampipe_dimensions[0].outerXRadius = beampipe_dimensions[0].innerXRadius + pipeThickness;
0082   beampipe_dimensions[0].outerYRadius = beampipe_dimensions[0].innerYRadius + pipeThickness;
0083   beampipe_dimensions[0].xCenter =
0084       -1 *
0085       (b1APFEndPoint_x + ((0.5 * beampipe_dimensions[0].length) * TMath::Sin(-globRotationAngle)));
0086   beampipe_dimensions[0].yCenter = 0.0;
0087   beampipe_dimensions[0].zCenter =
0088       (b1APFEndPoint_z + ((0.5 * beampipe_dimensions[0].length) * TMath::Cos(-globRotationAngle)));
0089 
0090   tmp_endpoint_z = beampipe_dimensions[0].zCenter +
0091                    ((0.5 * beampipe_dimensions[0].length) * TMath::Cos(-globRotationAngle));
0092   tmp_endpoint_x = -1 * beampipe_dimensions[0].xCenter +
0093                    ((0.5 * beampipe_dimensions[0].length) * TMath::Sin(-globRotationAngle));
0094 
0095   double windowRadius = 110.0 * dd4hep::mm;
0096 
0097   //------------------------------------------------------------------------------------
0098   //first small pipe section, between primary vessel and RP station 1
0099   //rectangular cross-section!!!!!
0100   //------------------------------------------------------------------------------------
0101 
0102   beampipe_dimensions.push_back({.length        = 2780.273 * dd4hep::mm, // from VPC drawings
0103                                  .innerXRadius  = 150.0 * dd4hep::mm,
0104                                  .innerYRadius  = 30.0 * dd4hep::mm,
0105                                  .rotationAngle = globRotationAngle});
0106 
0107   beampipe_dimensions[1].outerXRadius = beampipe_dimensions[1].innerXRadius + pipeThickness;
0108   beampipe_dimensions[1].outerYRadius = beampipe_dimensions[1].innerYRadius + pipeThickness;
0109   beampipe_dimensions[1].xCenter =
0110       -1 *
0111       (tmp_endpoint_x + ((0.5 * beampipe_dimensions[1].length) * TMath::Sin(-globRotationAngle)));
0112   beampipe_dimensions[1].yCenter = 0.0;
0113   beampipe_dimensions[1].zCenter =
0114       tmp_endpoint_z + ((0.5 * beampipe_dimensions[1].length) * TMath::Cos(-globRotationAngle));
0115 
0116   tmp_endpoint_z = beampipe_dimensions[1].zCenter +
0117                    ((0.5 * beampipe_dimensions[1].length) * TMath::Cos(-globRotationAngle));
0118   tmp_endpoint_x = -1 * beampipe_dimensions[1].xCenter +
0119                    ((0.5 * beampipe_dimensions[1].length) * TMath::Sin(-globRotationAngle));
0120 
0121   //------------------------------------------------------------------------------------
0122   //First roman pots scattering chamber
0123   //------------------------------------------------------------------------------------
0124 
0125   beampipe_dimensions.push_back({.length        = 200 * dd4hep::mm, // from VPC drawings
0126                                  .innerXRadius  = 200.0 * dd4hep::mm,
0127                                  .innerYRadius  = 125.0 * dd4hep::mm,
0128                                  .rotationAngle = globRotationAngle});
0129 
0130   beampipe_dimensions[2].outerXRadius = beampipe_dimensions[2].innerXRadius + pipeThickness;
0131   beampipe_dimensions[2].outerYRadius = beampipe_dimensions[2].innerYRadius + pipeThickness;
0132   beampipe_dimensions[2].xCenter =
0133       -1 *
0134       (tmp_endpoint_x + ((0.5 * beampipe_dimensions[2].length) * TMath::Sin(-globRotationAngle)));
0135   beampipe_dimensions[2].yCenter = 0.0;
0136   beampipe_dimensions[2].zCenter =
0137       tmp_endpoint_z + ((0.5 * beampipe_dimensions[2].length) * TMath::Cos(-globRotationAngle));
0138 
0139   tmp_endpoint_z = beampipe_dimensions[2].zCenter +
0140                    ((0.5 * beampipe_dimensions[2].length) * TMath::Cos(-globRotationAngle));
0141   tmp_endpoint_x = -1 * beampipe_dimensions[2].xCenter +
0142                    ((0.5 * beampipe_dimensions[2].length) * TMath::Sin(-globRotationAngle));
0143 
0144   //------------------------------------------------------------------------------------
0145   //pipe between RP 1 and RP 2 stations
0146   //rectangular cross-section!!!!!
0147   //------------------------------------------------------------------------------------
0148 
0149   beampipe_dimensions.push_back({.length        = 1500.0 * dd4hep::mm, // from VPC drawings
0150                                  .innerXRadius  = 150.0 * dd4hep::mm,
0151                                  .innerYRadius  = 30.0 * dd4hep::mm,
0152                                  .rotationAngle = globRotationAngle});
0153 
0154   beampipe_dimensions[3].outerXRadius = beampipe_dimensions[3].innerXRadius + pipeThickness;
0155   beampipe_dimensions[3].outerYRadius = beampipe_dimensions[3].innerYRadius + pipeThickness;
0156   beampipe_dimensions[3].xCenter =
0157       -1 *
0158       (tmp_endpoint_x + ((0.5 * beampipe_dimensions[3].length) * TMath::Sin(-globRotationAngle)));
0159   beampipe_dimensions[3].yCenter = 0.0;
0160   beampipe_dimensions[3].zCenter =
0161       tmp_endpoint_z + ((0.5 * beampipe_dimensions[3].length) * TMath::Cos(-globRotationAngle));
0162 
0163   tmp_endpoint_z = beampipe_dimensions[3].zCenter +
0164                    ((0.5 * beampipe_dimensions[3].length) * TMath::Cos(-globRotationAngle));
0165   tmp_endpoint_x = -1 * beampipe_dimensions[3].xCenter +
0166                    ((0.5 * beampipe_dimensions[3].length) * TMath::Sin(-globRotationAngle));
0167 
0168   //------------------------------------------------------------------------------------
0169   //second roman pots scattering chamber
0170   //------------------------------------------------------------------------------------
0171 
0172   beampipe_dimensions.push_back({.length        = 200 * dd4hep::mm, // from VPC drawings
0173                                  .innerXRadius  = 200.0 * dd4hep::mm,
0174                                  .innerYRadius  = 125.0 * dd4hep::mm,
0175                                  .rotationAngle = globRotationAngle});
0176 
0177   beampipe_dimensions[4].outerXRadius = beampipe_dimensions[4].innerXRadius + pipeThickness;
0178   beampipe_dimensions[4].outerYRadius = beampipe_dimensions[4].innerYRadius + pipeThickness;
0179   beampipe_dimensions[4].xCenter =
0180       -1 *
0181       (tmp_endpoint_x + ((0.5 * beampipe_dimensions[4].length) * TMath::Sin(-globRotationAngle)));
0182   beampipe_dimensions[4].yCenter = 0.0;
0183   beampipe_dimensions[4].zCenter =
0184       tmp_endpoint_z + ((0.5 * beampipe_dimensions[4].length) * TMath::Cos(-globRotationAngle));
0185 
0186   tmp_endpoint_z = beampipe_dimensions[4].zCenter +
0187                    ((0.5 * beampipe_dimensions[4].length) * TMath::Cos(-globRotationAngle));
0188   tmp_endpoint_x = -1 * beampipe_dimensions[4].xCenter +
0189                    ((0.5 * beampipe_dimensions[4].length) * TMath::Sin(-globRotationAngle));
0190 
0191   //------------------------------------------------------------------------------------
0192   // Pipe from second RP chamber to taper
0193   //------------------------------------------------------------------------------------
0194 
0195   beampipe_dimensions.push_back({.length        = 100.0 * dd4hep::mm, // from VPC drawings
0196                                  .innerXRadius  = 150.0 * dd4hep::mm,
0197                                  .innerYRadius  = 30.0 * dd4hep::mm,
0198                                  .rotationAngle = globRotationAngle});
0199 
0200   beampipe_dimensions[5].outerXRadius = beampipe_dimensions[5].innerXRadius + pipeThickness;
0201   beampipe_dimensions[5].outerYRadius = beampipe_dimensions[5].innerYRadius + pipeThickness;
0202   beampipe_dimensions[5].xCenter =
0203       -1 *
0204       (tmp_endpoint_x + ((0.5 * beampipe_dimensions[5].length) * TMath::Sin(-globRotationAngle)));
0205   beampipe_dimensions[5].yCenter = 0.0;
0206   beampipe_dimensions[5].zCenter =
0207       tmp_endpoint_z + ((0.5 * beampipe_dimensions[5].length) * TMath::Cos(-globRotationAngle));
0208 
0209   tmp_endpoint_z = beampipe_dimensions[5].zCenter +
0210                    ((0.5 * beampipe_dimensions[5].length) * TMath::Cos(-globRotationAngle));
0211   tmp_endpoint_x = -1 * beampipe_dimensions[5].xCenter +
0212                    ((0.5 * beampipe_dimensions[5].length) * TMath::Sin(-globRotationAngle));
0213 
0214   //------------------------------------------------------------------------------------
0215   // taper near ZDC
0216   //------------------------------------------------------------------------------------
0217 
0218   beampipe_dimensions.push_back({.length        = 599.692 * dd4hep::mm, // from VPC drawings
0219                                  .innerXRadius  = 150.0 * dd4hep::mm,
0220                                  .innerYRadius  = 30.0 * dd4hep::mm,
0221                                  .rotationAngle = globRotationAngle
0222 
0223   });
0224 
0225   beampipe_dimensions[6].outerXRadius = beampipe_dimensions[6].innerXRadius + pipeThickness;
0226   beampipe_dimensions[6].outerYRadius = beampipe_dimensions[6].innerYRadius + pipeThickness;
0227   beampipe_dimensions[6].xCenter =
0228       -1 *
0229       (tmp_endpoint_x + ((0.5 * beampipe_dimensions[6].length) * TMath::Sin(-globRotationAngle)));
0230   beampipe_dimensions[6].yCenter = 0.0;
0231   beampipe_dimensions[6].zCenter =
0232       tmp_endpoint_z + ((0.5 * beampipe_dimensions[6].length) * TMath::Cos(-globRotationAngle));
0233 
0234   tmp_endpoint_z = beampipe_dimensions[6].zCenter +
0235                    ((0.5 * beampipe_dimensions[6].length) * TMath::Cos(-globRotationAngle));
0236   tmp_endpoint_x = -1 * beampipe_dimensions[6].xCenter +
0237                    ((0.5 * beampipe_dimensions[6].length) * TMath::Sin(-globRotationAngle));
0238 
0239   //------------------------------------------------------------------------------------
0240   // pipe connecting taper to B2PF magnet, just past ZDC
0241   //------------------------------------------------------------------------------------
0242 
0243   //numbers here are not really correct for the full taper, just for the opening
0244 
0245   beampipe_dimensions.push_back({.length        = 3000.0 * dd4hep::mm, // from VPC drawings
0246                                  .innerXRadius  = 35.0 * dd4hep::mm,
0247                                  .innerYRadius  = 0.0,
0248                                  .rotationAngle = globRotationAngle});
0249 
0250   beampipe_dimensions[7].outerXRadius = beampipe_dimensions[7].innerXRadius + pipeThickness;
0251   beampipe_dimensions[7].outerYRadius =
0252       beampipe_dimensions[7].innerYRadius + pipeThickness; //NOT USED HERE
0253   beampipe_dimensions[7].xCenter =
0254       -1 *
0255       (tmp_endpoint_x + ((0.5 * beampipe_dimensions[7].length) * TMath::Sin(-globRotationAngle)));
0256   beampipe_dimensions[7].yCenter = 0.0;
0257   beampipe_dimensions[7].zCenter =
0258       tmp_endpoint_z + ((0.5 * beampipe_dimensions[7].length) * TMath::Cos(-globRotationAngle));
0259 
0260   //------------------------------------------
0261   //begin building main volumes here
0262   //------------------------------------------
0263 
0264   //-------------------------------------------------------------------
0265 
0266   int pieceIdx =
0267       0; //Larger, rectangular pipe transporting proton and neutral envelopes (neutral exit window and transfer to smaller proton line at the end)
0268 
0269   Box pipeAfterB1APF_outer(beampipe_dimensions[pieceIdx].outerXRadius,
0270                            beampipe_dimensions[pieceIdx].outerYRadius,
0271                            beampipe_dimensions[pieceIdx].length / 2);
0272   Box pipeAfterB1APF_inner(beampipe_dimensions[pieceIdx].innerXRadius,
0273                            beampipe_dimensions[pieceIdx].innerYRadius,
0274                            (beampipe_dimensions[pieceIdx].length) / 2);
0275   Box pipeAfterB1APF_firstEndCap(beampipe_dimensions[pieceIdx].outerXRadius,
0276                                  beampipe_dimensions[pieceIdx].outerYRadius, 5.0 / 2.0);
0277   Tube neutral_exit_window_cutout(0.0, windowRadius, 1.0); // 1.0cm thick
0278   //FIXME: proton transfer window is done by hand right now - not a nicer way to do it until we get the CAD drawing
0279   Box protonTransferWindow(155.0 * dd4hep::mm, beampipe_dimensions[1].outerYRadius, (5.0 / 2));
0280 
0281   SubtractionSolid tmpAfterB1APF(
0282       pipeAfterB1APF_outer,
0283       pipeAfterB1APF_inner); //This gets rid of the inner portion of the pipe, but leaves the endcaps
0284   tmpAfterB1APF = SubtractionSolid(tmpAfterB1APF, pipeAfterB1APF_firstEndCap,
0285                                    Position(0.0, 0.0, (-beampipe_dimensions[pieceIdx].length) / 2));
0286   tmpAfterB1APF = SubtractionSolid(
0287       tmpAfterB1APF, protonTransferWindow,
0288       Position((-120.0 * dd4hep::mm), 0.0, (beampipe_dimensions[pieceIdx].length) / 2));
0289   tmpAfterB1APF = SubtractionSolid(
0290       tmpAfterB1APF, neutral_exit_window_cutout,
0291       Position(160.0 * dd4hep::mm, 0.0, 0.5 * beampipe_dimensions[pieceIdx].length));
0292 
0293   Volume v_pipeAfterB1APF(Form("v_pipeAfterB1APF_%d", pieceIdx), tmpAfterB1APF, m_SS);
0294   sdet.setAttributes(det, v_pipeAfterB1APF, x_det.regionStr(), x_det.limitsStr(), vis_name);
0295 
0296   auto pv_pipe_0 = assembly.placeVolume(
0297       v_pipeAfterB1APF,
0298       Transform3D(RotationY(crossingAngle),
0299                   Position(beampipe_dimensions[pieceIdx].xCenter + 4.0,
0300                            beampipe_dimensions[pieceIdx].yCenter,
0301                            beampipe_dimensions[pieceIdx].zCenter))); // 2353.06094)));
0302   pv_pipe_0.addPhysVolID("sector", 1);
0303   DetElement pipe_de_0(sdet, Form("sector_pipe_%d_de", pieceIdx), 1);
0304   pipe_de_0.setPlacement(pv_pipe_0);
0305 
0306   //--------------------------------------------------------------------
0307 
0308   double lengthDelta = 0.0; //over-length value to remove end-pieces for hollow rectangular pipes
0309 
0310   // 1 -- small pipe connecting big pipe to RP station 1
0311   // 2 -- roman pots scattering chamber 1
0312   // 3 -- small pipe connecting RP1 and RP2
0313   // 4 -- roman pots scattering chamber 2
0314   // 5 -- small pipe connecting RP2 to ZDC taper
0315 
0316   lengthDelta = 5.0; //for small beam pipes to remove endcaps
0317 
0318   for (int idx = 1; idx < 6; idx++) { //loop for the easier pieces to simplify
0319 
0320     if (idx == 2 || idx == 4) {
0321       continue;
0322     }
0323 
0324     Box outer(beampipe_dimensions[idx].outerXRadius, beampipe_dimensions[idx].outerYRadius,
0325               beampipe_dimensions[idx].length / 2);
0326     Box inner(beampipe_dimensions[idx].innerXRadius, beampipe_dimensions[idx].innerYRadius,
0327               (beampipe_dimensions[idx].length + lengthDelta) / 2);
0328 
0329     SubtractionSolid hollow_pipe(outer, inner);
0330 
0331     Volume v_hollow_pipe(Form("v_pipe_%d", idx), hollow_pipe, m_SS);
0332     sdet.setAttributes(det, v_hollow_pipe, x_det.regionStr(), x_det.limitsStr(), vis_name);
0333 
0334     auto pv_final = assembly.placeVolume(
0335         v_hollow_pipe,
0336         Transform3D(RotationY(beampipe_dimensions[idx].rotationAngle),
0337                     Position(beampipe_dimensions[idx].xCenter, beampipe_dimensions[idx].yCenter,
0338                              beampipe_dimensions[idx].zCenter)));
0339     pv_final.addPhysVolID("sector", 1);
0340     DetElement final_de(sdet, Form("sector_pipe_%d_de", idx), 1);
0341     final_de.setPlacement(pv_final);
0342   }
0343 
0344   lengthDelta = 0.0; //not needed for scattering chambers
0345 
0346   for (int idx = 1; idx < 6; idx++) { //loop for the easier pieces to simplify
0347 
0348     if (idx == 1 || idx == 3 || idx == 5) {
0349       continue;
0350     }
0351 
0352     Box outer(beampipe_dimensions[idx].outerXRadius, beampipe_dimensions[idx].outerYRadius,
0353               beampipe_dimensions[idx].length / 2);
0354     Box inner(beampipe_dimensions[idx].innerXRadius, beampipe_dimensions[idx].innerYRadius,
0355               (beampipe_dimensions[idx].length + lengthDelta) / 2);
0356     Box RP_subtract_outer(beampipe_dimensions[1].outerXRadius, beampipe_dimensions[1].outerYRadius,
0357                           (beampipe_dimensions[2].length + 5.0) / 2);
0358 
0359     SubtractionSolid hollow_pipe(outer, inner);
0360     hollow_pipe = SubtractionSolid(hollow_pipe, RP_subtract_outer);
0361 
0362     Volume v_hollow_pipe(Form("v_pipe_%d", idx), hollow_pipe, m_SS);
0363     sdet.setAttributes(det, v_hollow_pipe, x_det.regionStr(), x_det.limitsStr(), vis_name);
0364 
0365     auto pv_final = assembly.placeVolume(
0366         v_hollow_pipe,
0367         Transform3D(RotationY(beampipe_dimensions[idx].rotationAngle),
0368                     Position(beampipe_dimensions[idx].xCenter, beampipe_dimensions[idx].yCenter,
0369                              beampipe_dimensions[idx].zCenter)));
0370     pv_final.addPhysVolID("sector", 1);
0371     DetElement final_de(sdet, Form("sector_pipe_%d_de", idx), 1);
0372     final_de.setPlacement(pv_final);
0373   }
0374 
0375   //----------------------------------------------------------------
0376 
0377   pieceIdx = 6;
0378 
0379   Double_t trpVertices[16];
0380   Double_t trpVerticesInner[16];
0381   //(x0, y0, x1, y1, ... , x7, y7)
0382   //opening side - larger size
0383   trpVertices[0] = -beampipe_dimensions[6].outerXRadius;
0384   trpVertices[1] = -beampipe_dimensions[6].outerYRadius;
0385 
0386   trpVertices[2] = -beampipe_dimensions[6].outerXRadius;
0387   trpVertices[3] = beampipe_dimensions[6].outerYRadius;
0388 
0389   trpVertices[4] = beampipe_dimensions[6].outerXRadius;
0390   trpVertices[5] = beampipe_dimensions[6].outerYRadius;
0391 
0392   trpVertices[6] = beampipe_dimensions[6].outerXRadius;
0393   trpVertices[7] = -beampipe_dimensions[6].outerYRadius;
0394 
0395   //exiting side - smaller size
0396 
0397   trpVertices[8] = -beampipe_dimensions[6].outerYRadius;
0398   trpVertices[9] = -beampipe_dimensions[6].outerYRadius;
0399 
0400   trpVertices[10] = -beampipe_dimensions[6].outerYRadius;
0401   trpVertices[11] = beampipe_dimensions[6].outerYRadius;
0402 
0403   trpVertices[12] = beampipe_dimensions[6].outerYRadius;
0404   trpVertices[13] = beampipe_dimensions[6].outerYRadius;
0405 
0406   trpVertices[14] = beampipe_dimensions[6].outerYRadius;
0407   trpVertices[15] = -beampipe_dimensions[6].outerYRadius;
0408 
0409   for (int i = 0; i < 16; i++) {
0410 
0411     if (trpVertices[i] > 0.0) {
0412       trpVerticesInner[i] = trpVertices[i] - (pipeThickness);
0413     }
0414     if (trpVertices[i] < 0.0) {
0415       trpVerticesInner[i] = trpVertices[i] + (pipeThickness);
0416     }
0417   }
0418 
0419   EightPointSolid taper_outer((0.5 * beampipe_dimensions[pieceIdx].length), trpVertices);
0420   EightPointSolid taper_inner((0.5 * beampipe_dimensions[pieceIdx].length), trpVerticesInner);
0421 
0422   Box taper_entrance(beampipe_dimensions[pieceIdx].innerXRadius,
0423                      beampipe_dimensions[pieceIdx].innerYRadius, (0.5 * (pipeThickness + 5.0)));
0424   Box taper_exit(beampipe_dimensions[pieceIdx].innerYRadius,
0425                  beampipe_dimensions[pieceIdx].innerYRadius, (0.5 * (pipeThickness + 5.0)));
0426   SubtractionSolid hollowTaper(taper_outer, taper_inner);
0427   hollowTaper = SubtractionSolid(hollowTaper, taper_entrance,
0428                                  Position(0.0, 0.0, (-0.5 * beampipe_dimensions[pieceIdx].length)));
0429   hollowTaper = SubtractionSolid(hollowTaper, taper_exit,
0430                                  Position(0.0, 0.0, (0.5 * beampipe_dimensions[pieceIdx].length)));
0431 
0432   Volume v_taper(Form("v_taper_%d", pieceIdx), hollowTaper, m_SS);
0433   sdet.setAttributes(det, v_taper, x_det.regionStr(), x_det.limitsStr(), vis_name);
0434 
0435   auto pv_pipe_6 = assembly.placeVolume(
0436       v_taper, Transform3D(RotationY(beampipe_dimensions[pieceIdx].rotationAngle),
0437                            Position(beampipe_dimensions[pieceIdx].xCenter,
0438                                     beampipe_dimensions[pieceIdx].yCenter,
0439                                     beampipe_dimensions[pieceIdx].zCenter)));
0440   pv_pipe_6.addPhysVolID("sector", 1);
0441   DetElement pipe_de_6(sdet, Form("sector_pipe_%d_de", pieceIdx), 1);
0442   pipe_de_6.setPlacement(pv_pipe_6);
0443 
0444   //---------------------------------------------------------------
0445 
0446   pieceIdx = 7; //pipe between taper and B2PF
0447 
0448   Tube pipe_after_taper(beampipe_dimensions[pieceIdx].innerXRadius,
0449                         beampipe_dimensions[pieceIdx].outerXRadius,
0450                         beampipe_dimensions[pieceIdx].length / 2);
0451 
0452   Volume v_pipe_7(Form("v_pipe_7_%d", pieceIdx), pipe_after_taper, m_SS);
0453   sdet.setAttributes(det, v_pipe_7, x_det.regionStr(), x_det.limitsStr(), vis_name);
0454 
0455   auto pv_pipe_7 = assembly.placeVolume(
0456       v_pipe_7, Transform3D(RotationY(beampipe_dimensions[pieceIdx].rotationAngle),
0457                             Position(beampipe_dimensions[pieceIdx].xCenter,
0458                                      beampipe_dimensions[pieceIdx].yCenter,
0459                                      beampipe_dimensions[pieceIdx].zCenter))); // 2353.06094)));
0460   pv_pipe_7.addPhysVolID("sector", 1);
0461   DetElement pipe_de_7(sdet, Form("sector_pipe_%d_de", pieceIdx), 1);
0462   pipe_de_7.setPlacement(pv_pipe_7);
0463 
0464   //--------------------------------------------------------------
0465   // This is the beam tube in the B0 magnet for the hadron beam
0466   // doesn't use the slope information calculated before - it stands alone
0467 
0468   pieceIdx = 8;
0469 
0470   Tube b0_hadron_tube(b0_hadron_tube_inner_r, b0_hadron_tube_outer_r, b0_hadron_tube_length / 2.0);
0471   Volume v_b0_hadron_tube("v_b0_hadron_tube", b0_hadron_tube, m_Be);
0472   sdet.setAttributes(det, v_b0_hadron_tube, x_det.regionStr(), x_det.limitsStr(), vis_name);
0473 
0474   auto pv_pipe_8 = assembly.placeVolume(
0475       v_b0_hadron_tube, Transform3D(RotationY(crossingAngle),
0476                                     Position(b0PFCenter_z * sin(crossingAngle), 0.0,
0477                                              b0PFCenter_z * cos(crossingAngle)))); // 2353.06094)));
0478   pv_pipe_8.addPhysVolID("sector", 1);
0479   DetElement pipe_de_8(sdet, Form("sector_pipe_%d_de", pieceIdx), 1);
0480   pipe_de_8.setPlacement(pv_pipe_6);
0481 
0482   //----------------------------------------------------------------
0483 
0484   pieceIdx = 9; //neutral exit window
0485 
0486   Box pipeAfterB1APF_LARGE((beampipe_dimensions[0].outerXRadius + 5.0),
0487                            (beampipe_dimensions[0].outerYRadius + 5.0),
0488                            (beampipe_dimensions[0].length + 5.0) / 2);
0489   Tube neutral_exit_window(0.0, windowRadius, 1.0); // 1.0cm thick
0490 
0491   IntersectionSolid finalWindow(
0492       pipeAfterB1APF_outer, neutral_exit_window,
0493       Position(160.0 * dd4hep::mm, 0.0, 0.5 * beampipe_dimensions[0].length));
0494 
0495   Volume v_neutral_exit_window("v_neutral_exit_window", finalWindow, m_Al);
0496   sdet.setAttributes(det, v_neutral_exit_window, x_det.regionStr(), x_det.limitsStr(), "AnlRed");
0497 
0498   auto pv_pipe_9 = assembly.placeVolume(
0499       v_neutral_exit_window,
0500       Transform3D(RotationY(crossingAngle), Position(beampipe_dimensions[0].xCenter + 4.0, 0.0,
0501                                                      beampipe_dimensions[0].zCenter)));
0502   pv_pipe_9.addPhysVolID("sector", 1);
0503   DetElement pipe_de_9(sdet, Form("sector_pipe_%d_de", pieceIdx), 1);
0504   pipe_de_9.setPlacement(pv_pipe_9);
0505 
0506   //-----------------------------------------------------------------
0507   // Build vacuum volumes here
0508   //-----------------------------------------------------------------
0509 
0510   pieceIdx = 0;
0511 
0512   Box vacuum_main_pipe(beampipe_dimensions[pieceIdx].innerXRadius,
0513                        beampipe_dimensions[pieceIdx].innerYRadius,
0514                        (beampipe_dimensions[pieceIdx].length - 2.0) / 2);
0515   Box cutout_for_OMD_station(beampipe_dimensions[pieceIdx].innerXRadius,
0516                              beampipe_dimensions[pieceIdx].innerYRadius, 2.0);
0517 
0518   SubtractionSolid final_vacuum_main_pipe(
0519       vacuum_main_pipe, cutout_for_OMD_station,
0520       Position(0.0, 0.0, (2251.0 - beampipe_dimensions[pieceIdx].zCenter)));
0521   final_vacuum_main_pipe =
0522       SubtractionSolid(final_vacuum_main_pipe, cutout_for_OMD_station,
0523                        Position(0.0, 0.0, (2451.0 - beampipe_dimensions[pieceIdx].zCenter)));
0524 
0525   Volume v_vacuum_main_pipe("v_vacuum_main_pipe", final_vacuum_main_pipe, m_vac);
0526   sdet.setAttributes(det, v_vacuum_main_pipe, x_det.regionStr(), x_det.limitsStr(), "AnlBlue");
0527 
0528   auto pv_vacuum_0 = assembly.placeVolume(
0529       v_vacuum_main_pipe,
0530       Transform3D(RotationY(crossingAngle), Position(beampipe_dimensions[pieceIdx].xCenter + 4.0,
0531                                                      0.0, beampipe_dimensions[pieceIdx].zCenter)));
0532   pv_vacuum_0.addPhysVolID("sector", 1);
0533   DetElement vacuum_de_0(sdet, Form("sector_FF_vacuum_%d_de", pieceIdx), 1);
0534   vacuum_de_0.setPlacement(pv_vacuum_0);
0535 
0536   //------------------------------------------------------------------
0537 
0538   for (int idx = 1; idx < 6; idx++) { //loop for the easier pieces to simplify
0539 
0540     if (idx == 2 || idx == 4) {
0541       continue;
0542     } //FIXME: don't fill RP chambers with vacuum yet - still an issue with RP geometry
0543 
0544     Box inner_vacuum(beampipe_dimensions[idx].innerXRadius, beampipe_dimensions[idx].innerYRadius,
0545                      (beampipe_dimensions[idx].length) / 2);
0546 
0547     Volume v_inner_vacuum(Form("v_vacuum_%d", idx), inner_vacuum, m_vac);
0548     sdet.setAttributes(det, v_inner_vacuum, x_det.regionStr(), x_det.limitsStr(), "AnlBlue");
0549 
0550     auto pv_final = assembly.placeVolume(
0551         v_inner_vacuum,
0552         Transform3D(RotationY(beampipe_dimensions[idx].rotationAngle),
0553                     Position(beampipe_dimensions[idx].xCenter, beampipe_dimensions[idx].yCenter,
0554                              beampipe_dimensions[idx].zCenter)));
0555     pv_final.addPhysVolID("sector", 1);
0556     DetElement final_de(sdet, Form("sector_FF_vacuum_%d_de", idx), 1);
0557     final_de.setPlacement(pv_final);
0558   }
0559 
0560   //------------------------------------------------------------------
0561 
0562   pieceIdx = 6;
0563 
0564   EightPointSolid vacuum_taper((0.5 * beampipe_dimensions[pieceIdx].length), trpVerticesInner);
0565 
0566   Volume v_vacuum_taper("v_vacuum_taper", vacuum_taper, m_vac);
0567   sdet.setAttributes(det, v_vacuum_taper, x_det.regionStr(), x_det.limitsStr(), "AnlBlue");
0568 
0569   auto pv_vacuum_6 = assembly.placeVolume(
0570       v_vacuum_taper, Transform3D(RotationY(beampipe_dimensions[pieceIdx].rotationAngle),
0571                                   Position(beampipe_dimensions[pieceIdx].xCenter, 0.0,
0572                                            beampipe_dimensions[pieceIdx].zCenter)));
0573   pv_vacuum_6.addPhysVolID("sector", 1);
0574   DetElement vacuum_de_6(sdet, Form("sector_FF_vacuum_%d_de", pieceIdx), 1);
0575   vacuum_de_6.setPlacement(pv_vacuum_6);
0576 
0577   //-------------------------------------------------------------------
0578 
0579   pieceIdx = 7; //vacuum between taper and B2PF
0580 
0581   Tube vacuum_pipe_after_taper(0.0, beampipe_dimensions[pieceIdx].innerXRadius,
0582                                beampipe_dimensions[pieceIdx].length / 2);
0583 
0584   Volume v_vacuum_pipe_after_taper("v_vacuum_pipe_after_taper", vacuum_pipe_after_taper, m_vac);
0585   sdet.setAttributes(det, v_vacuum_pipe_after_taper, x_det.regionStr(), x_det.limitsStr(),
0586                      "AnlBlue");
0587 
0588   auto pv_vacuum_7 = assembly.placeVolume(
0589       v_vacuum_pipe_after_taper, Transform3D(RotationY(beampipe_dimensions[pieceIdx].rotationAngle),
0590                                              Position(beampipe_dimensions[pieceIdx].xCenter,
0591                                                       beampipe_dimensions[pieceIdx].yCenter,
0592                                                       beampipe_dimensions[pieceIdx].zCenter)));
0593   pv_vacuum_7.addPhysVolID("sector", 1);
0594   DetElement vacuum_de_7(sdet, Form("sector_FF_vacuum_%d_de", pieceIdx), 1);
0595   vacuum_de_7.setPlacement(pv_vacuum_7);
0596 
0597   //-------------------------------------------------------------------
0598 
0599   pv_assembly = det.pickMotherVolume(sdet).placeVolume(assembly);
0600   pv_assembly.addPhysVolID("system", x_det.id()).addPhysVolID("barrel", 1);
0601   sdet.setPlacement(pv_assembly);
0602   assembly->GetShape()->ComputeBBox();
0603   return sdet;
0604 }
0605 
0606 DECLARE_DETELEMENT(forwardBeamPipeBrazil, create_detector)