Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:28:33

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("StainlessSteelP506");
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   // A box to cut out from the beam pipe to avoid overlaps with the fwd cryostat
0264   Box cutout_for_FWD_cryo(1 * dd4hep::m, 1 * dd4hep::m, 2 * dd4hep::m);
0265 
0266   //-------------------------------------------------------------------
0267 
0268   int pieceIdx =
0269       0; //Larger, rectangular pipe transporting proton and neutral envelopes (neutral exit window and transfer to smaller proton line at the end)
0270 
0271   Box pipeAfterB1APF_outer(beampipe_dimensions[pieceIdx].outerXRadius,
0272                            beampipe_dimensions[pieceIdx].outerYRadius,
0273                            beampipe_dimensions[pieceIdx].length / 2);
0274   Box pipeAfterB1APF_inner(beampipe_dimensions[pieceIdx].innerXRadius,
0275                            beampipe_dimensions[pieceIdx].innerYRadius,
0276                            (beampipe_dimensions[pieceIdx].length) / 2);
0277   Box pipeAfterB1APF_firstEndCap(beampipe_dimensions[pieceIdx].outerXRadius,
0278                                  beampipe_dimensions[pieceIdx].outerYRadius, 5.0 / 2.0);
0279   Tube neutral_exit_window_cutout(0.0, windowRadius, 1.0); // 1.0cm thick
0280   //FIXME: proton transfer window is done by hand right now - not a nicer way to do it until we get the CAD drawing
0281   Box protonTransferWindow(155.0 * dd4hep::mm, beampipe_dimensions[1].outerYRadius, (5.0 / 2));
0282 
0283   SubtractionSolid tmpAfterB1APF(
0284       pipeAfterB1APF_outer,
0285       pipeAfterB1APF_inner); //This gets rid of the inner portion of the pipe, but leaves the endcaps
0286   tmpAfterB1APF = SubtractionSolid(tmpAfterB1APF, pipeAfterB1APF_firstEndCap,
0287                                    Position(0.0, 0.0, (-beampipe_dimensions[pieceIdx].length) / 2));
0288   tmpAfterB1APF = SubtractionSolid(
0289       tmpAfterB1APF, protonTransferWindow,
0290       Position((-120.0 * dd4hep::mm), 0.0, (beampipe_dimensions[pieceIdx].length) / 2));
0291   tmpAfterB1APF = SubtractionSolid(
0292       tmpAfterB1APF, neutral_exit_window_cutout,
0293       Position(160.0 * dd4hep::mm, 0.0, 0.5 * beampipe_dimensions[pieceIdx].length));
0294 
0295   //-----------------------------------------------------------------
0296   // Cut on the IP side to avoid overlaps with the fwd cryostat
0297   tmpAfterB1APF = SubtractionSolid(tmpAfterB1APF, cutout_for_FWD_cryo,
0298                                    Position(0.0, 0.0, (-beampipe_dimensions[pieceIdx].length) / 2));
0299   //-----------------------------------------------------------------
0300 
0301   Volume v_pipeAfterB1APF(Form("v_pipeAfterB1APF_%d", pieceIdx), tmpAfterB1APF, m_SS);
0302   sdet.setAttributes(det, v_pipeAfterB1APF, x_det.regionStr(), x_det.limitsStr(), vis_name);
0303 
0304   auto pv_pipe_0 = assembly.placeVolume(
0305       v_pipeAfterB1APF,
0306       Transform3D(RotationY(crossingAngle),
0307                   Position(beampipe_dimensions[pieceIdx].xCenter + 4.0,
0308                            beampipe_dimensions[pieceIdx].yCenter,
0309                            beampipe_dimensions[pieceIdx].zCenter))); // 2353.06094)));
0310   pv_pipe_0.addPhysVolID("sector", 1);
0311   DetElement pipe_de_0(sdet, Form("sector_pipe_%d_de", pieceIdx), 1);
0312   pipe_de_0.setPlacement(pv_pipe_0);
0313 
0314   //--------------------------------------------------------------------
0315 
0316   double lengthDelta = 0.0; //over-length value to remove end-pieces for hollow rectangular pipes
0317 
0318   // 1 -- small pipe connecting big pipe to RP station 1
0319   // 2 -- roman pots scattering chamber 1
0320   // 3 -- small pipe connecting RP1 and RP2
0321   // 4 -- roman pots scattering chamber 2
0322   // 5 -- small pipe connecting RP2 to ZDC taper
0323 
0324   lengthDelta = 5.0; //for small beam pipes to remove endcaps
0325 
0326   for (int idx = 1; idx < 6; idx++) { //loop for the easier pieces to simplify
0327 
0328     if (idx == 2 || idx == 4) {
0329       continue;
0330     }
0331 
0332     Box outer(beampipe_dimensions[idx].outerXRadius, beampipe_dimensions[idx].outerYRadius,
0333               beampipe_dimensions[idx].length / 2);
0334     Box inner(beampipe_dimensions[idx].innerXRadius, beampipe_dimensions[idx].innerYRadius,
0335               (beampipe_dimensions[idx].length + lengthDelta) / 2);
0336 
0337     SubtractionSolid hollow_pipe(outer, inner);
0338 
0339     Volume v_hollow_pipe(Form("v_pipe_%d", idx), hollow_pipe, m_SS);
0340     sdet.setAttributes(det, v_hollow_pipe, x_det.regionStr(), x_det.limitsStr(), vis_name);
0341 
0342     auto pv_final = assembly.placeVolume(
0343         v_hollow_pipe,
0344         Transform3D(RotationY(beampipe_dimensions[idx].rotationAngle),
0345                     Position(beampipe_dimensions[idx].xCenter, beampipe_dimensions[idx].yCenter,
0346                              beampipe_dimensions[idx].zCenter)));
0347     pv_final.addPhysVolID("sector", 1);
0348     DetElement final_de(sdet, Form("sector_pipe_%d_de", idx), 1);
0349     final_de.setPlacement(pv_final);
0350   }
0351 
0352   lengthDelta = 0.0; //not needed for scattering chambers
0353 
0354   for (int idx = 1; idx < 6; idx++) { //loop for the easier pieces to simplify
0355 
0356     if (idx == 1 || idx == 3 || idx == 5) {
0357       continue;
0358     }
0359 
0360     Box outer(beampipe_dimensions[idx].outerXRadius, beampipe_dimensions[idx].outerYRadius,
0361               beampipe_dimensions[idx].length / 2);
0362     Box inner(beampipe_dimensions[idx].innerXRadius, beampipe_dimensions[idx].innerYRadius,
0363               (beampipe_dimensions[idx].length + lengthDelta) / 2);
0364     Box RP_subtract_outer(beampipe_dimensions[1].outerXRadius, beampipe_dimensions[1].outerYRadius,
0365                           (beampipe_dimensions[2].length + 5.0) / 2);
0366 
0367     SubtractionSolid hollow_pipe(outer, inner);
0368     hollow_pipe = SubtractionSolid(hollow_pipe, RP_subtract_outer);
0369 
0370     Volume v_hollow_pipe(Form("v_pipe_%d", idx), hollow_pipe, m_SS);
0371     sdet.setAttributes(det, v_hollow_pipe, x_det.regionStr(), x_det.limitsStr(), vis_name);
0372 
0373     auto pv_final = assembly.placeVolume(
0374         v_hollow_pipe,
0375         Transform3D(RotationY(beampipe_dimensions[idx].rotationAngle),
0376                     Position(beampipe_dimensions[idx].xCenter, beampipe_dimensions[idx].yCenter,
0377                              beampipe_dimensions[idx].zCenter)));
0378     pv_final.addPhysVolID("sector", 1);
0379     DetElement final_de(sdet, Form("sector_pipe_%d_de", idx), 1);
0380     final_de.setPlacement(pv_final);
0381   }
0382 
0383   //----------------------------------------------------------------
0384 
0385   pieceIdx = 6;
0386 
0387   Double_t trpVertices[16];
0388   Double_t trpVerticesInner[16];
0389   //(x0, y0, x1, y1, ... , x7, y7)
0390   //opening side - larger size
0391   trpVertices[0] = -beampipe_dimensions[6].outerXRadius;
0392   trpVertices[1] = -beampipe_dimensions[6].outerYRadius;
0393 
0394   trpVertices[2] = -beampipe_dimensions[6].outerXRadius;
0395   trpVertices[3] = beampipe_dimensions[6].outerYRadius;
0396 
0397   trpVertices[4] = beampipe_dimensions[6].outerXRadius;
0398   trpVertices[5] = beampipe_dimensions[6].outerYRadius;
0399 
0400   trpVertices[6] = beampipe_dimensions[6].outerXRadius;
0401   trpVertices[7] = -beampipe_dimensions[6].outerYRadius;
0402 
0403   //exiting side - smaller size
0404 
0405   trpVertices[8] = -beampipe_dimensions[6].outerYRadius;
0406   trpVertices[9] = -beampipe_dimensions[6].outerYRadius;
0407 
0408   trpVertices[10] = -beampipe_dimensions[6].outerYRadius;
0409   trpVertices[11] = beampipe_dimensions[6].outerYRadius;
0410 
0411   trpVertices[12] = beampipe_dimensions[6].outerYRadius;
0412   trpVertices[13] = beampipe_dimensions[6].outerYRadius;
0413 
0414   trpVertices[14] = beampipe_dimensions[6].outerYRadius;
0415   trpVertices[15] = -beampipe_dimensions[6].outerYRadius;
0416 
0417   for (int i = 0; i < 16; i++) {
0418 
0419     if (trpVertices[i] > 0.0) {
0420       trpVerticesInner[i] = trpVertices[i] - (pipeThickness);
0421     }
0422     if (trpVertices[i] < 0.0) {
0423       trpVerticesInner[i] = trpVertices[i] + (pipeThickness);
0424     }
0425   }
0426 
0427   EightPointSolid taper_outer((0.5 * beampipe_dimensions[pieceIdx].length), trpVertices);
0428   EightPointSolid taper_inner((0.5 * beampipe_dimensions[pieceIdx].length), trpVerticesInner);
0429 
0430   Box taper_entrance(beampipe_dimensions[pieceIdx].innerXRadius,
0431                      beampipe_dimensions[pieceIdx].innerYRadius, (0.5 * (pipeThickness + 5.0)));
0432   Box taper_exit(beampipe_dimensions[pieceIdx].innerYRadius,
0433                  beampipe_dimensions[pieceIdx].innerYRadius, (0.5 * (pipeThickness + 5.0)));
0434   SubtractionSolid hollowTaper(taper_outer, taper_inner);
0435   hollowTaper = SubtractionSolid(hollowTaper, taper_entrance,
0436                                  Position(0.0, 0.0, (-0.5 * beampipe_dimensions[pieceIdx].length)));
0437   hollowTaper = SubtractionSolid(hollowTaper, taper_exit,
0438                                  Position(0.0, 0.0, (0.5 * beampipe_dimensions[pieceIdx].length)));
0439 
0440   Volume v_taper(Form("v_taper_%d", pieceIdx), hollowTaper, m_SS);
0441   sdet.setAttributes(det, v_taper, x_det.regionStr(), x_det.limitsStr(), vis_name);
0442 
0443   auto pv_pipe_6 = assembly.placeVolume(
0444       v_taper, Transform3D(RotationY(beampipe_dimensions[pieceIdx].rotationAngle),
0445                            Position(beampipe_dimensions[pieceIdx].xCenter,
0446                                     beampipe_dimensions[pieceIdx].yCenter,
0447                                     beampipe_dimensions[pieceIdx].zCenter)));
0448   pv_pipe_6.addPhysVolID("sector", 1);
0449   DetElement pipe_de_6(sdet, Form("sector_pipe_%d_de", pieceIdx), 1);
0450   pipe_de_6.setPlacement(pv_pipe_6);
0451 
0452   //---------------------------------------------------------------
0453 
0454   pieceIdx = 7; //pipe between taper and B2PF
0455 
0456   Tube pipe_after_taper(beampipe_dimensions[pieceIdx].innerXRadius,
0457                         beampipe_dimensions[pieceIdx].outerXRadius,
0458                         beampipe_dimensions[pieceIdx].length / 2);
0459 
0460   Volume v_pipe_7(Form("v_pipe_7_%d", pieceIdx), pipe_after_taper, m_SS);
0461   sdet.setAttributes(det, v_pipe_7, x_det.regionStr(), x_det.limitsStr(), vis_name);
0462 
0463   auto pv_pipe_7 = assembly.placeVolume(
0464       v_pipe_7, Transform3D(RotationY(beampipe_dimensions[pieceIdx].rotationAngle),
0465                             Position(beampipe_dimensions[pieceIdx].xCenter,
0466                                      beampipe_dimensions[pieceIdx].yCenter,
0467                                      beampipe_dimensions[pieceIdx].zCenter))); // 2353.06094)));
0468   pv_pipe_7.addPhysVolID("sector", 1);
0469   DetElement pipe_de_7(sdet, Form("sector_pipe_%d_de", pieceIdx), 1);
0470   pipe_de_7.setPlacement(pv_pipe_7);
0471 
0472   //--------------------------------------------------------------
0473   // This is the beam tube in the B0 magnet for the hadron beam
0474   // doesn't use the slope information calculated before - it stands alone
0475 
0476   pieceIdx = 8;
0477 
0478   Tube b0_hadron_tube(b0_hadron_tube_inner_r, b0_hadron_tube_outer_r, b0_hadron_tube_length / 2.0);
0479   Volume v_b0_hadron_tube("v_b0_hadron_tube", b0_hadron_tube, m_Be);
0480   sdet.setAttributes(det, v_b0_hadron_tube, x_det.regionStr(), x_det.limitsStr(), vis_name);
0481 
0482   auto pv_pipe_8 = assembly.placeVolume(
0483       v_b0_hadron_tube, Transform3D(RotationY(crossingAngle),
0484                                     Position(b0PFCenter_z * sin(crossingAngle), 0.0,
0485                                              b0PFCenter_z * cos(crossingAngle)))); // 2353.06094)));
0486   pv_pipe_8.addPhysVolID("sector", 1);
0487   DetElement pipe_de_8(sdet, Form("sector_pipe_%d_de", pieceIdx), 1);
0488   pipe_de_8.setPlacement(pv_pipe_6);
0489 
0490   //----------------------------------------------------------------
0491 
0492   pieceIdx = 9; //neutral exit window
0493 
0494   Box pipeAfterB1APF_LARGE((beampipe_dimensions[0].outerXRadius + 5.0),
0495                            (beampipe_dimensions[0].outerYRadius + 5.0),
0496                            (beampipe_dimensions[0].length + 5.0) / 2);
0497   Tube neutral_exit_window(0.0, windowRadius, 1.0); // 1.0cm thick
0498 
0499   IntersectionSolid finalWindow(
0500       pipeAfterB1APF_outer, neutral_exit_window,
0501       Position(160.0 * dd4hep::mm, 0.0, 0.5 * beampipe_dimensions[0].length));
0502 
0503   Volume v_neutral_exit_window("v_neutral_exit_window", finalWindow, m_Al);
0504   sdet.setAttributes(det, v_neutral_exit_window, x_det.regionStr(), x_det.limitsStr(), "AnlRed");
0505 
0506   auto pv_pipe_9 = assembly.placeVolume(
0507       v_neutral_exit_window,
0508       Transform3D(RotationY(crossingAngle), Position(beampipe_dimensions[0].xCenter + 4.0, 0.0,
0509                                                      beampipe_dimensions[0].zCenter)));
0510   pv_pipe_9.addPhysVolID("sector", 1);
0511   DetElement pipe_de_9(sdet, Form("sector_pipe_%d_de", pieceIdx), 1);
0512   pipe_de_9.setPlacement(pv_pipe_9);
0513 
0514   //-----------------------------------------------------------------
0515   // Build vacuum volumes here
0516   //-----------------------------------------------------------------
0517 
0518   pieceIdx = 0;
0519 
0520   Box vacuum_main_pipe(beampipe_dimensions[pieceIdx].innerXRadius,
0521                        beampipe_dimensions[pieceIdx].innerYRadius,
0522                        (beampipe_dimensions[pieceIdx].length - 2.0) / 2);
0523   Box cutout_for_OMD_station(beampipe_dimensions[pieceIdx].innerXRadius,
0524                              beampipe_dimensions[pieceIdx].innerYRadius, 2.0);
0525 
0526   SubtractionSolid final_vacuum_main_pipe(
0527       vacuum_main_pipe, cutout_for_OMD_station,
0528       Position(0.0, 0.0, (2551.0 * dd4hep::cm - beampipe_dimensions[pieceIdx].zCenter)));
0529   final_vacuum_main_pipe = SubtractionSolid(
0530       final_vacuum_main_pipe, cutout_for_OMD_station,
0531       Position(0.0, 0.0, (2701.0 * dd4hep::cm - beampipe_dimensions[pieceIdx].zCenter)));
0532 
0533   //-----------------------------------------------------------------
0534   // Cut on the IP side to avoid overlaps with the fwd cryostat
0535   final_vacuum_main_pipe = SubtractionSolid(
0536       final_vacuum_main_pipe, cutout_for_FWD_cryo,
0537       Position(0.0, 0.0,
0538                (2400.0 * dd4hep::cm - 2 * dd4hep::m - beampipe_dimensions[pieceIdx].zCenter)));
0539   Tube pipe_for_FWD_cryo(0.0, 16.0 * dd4hep::cm, 97.0 * dd4hep::cm);
0540   final_vacuum_main_pipe = UnionSolid(
0541       final_vacuum_main_pipe, pipe_for_FWD_cryo,
0542       Position(6.5 * dd4hep::cm, 0.0,
0543                (2400.0 * dd4hep::cm - 97.0 * dd4hep::cm - beampipe_dimensions[pieceIdx].zCenter)));
0544   //-----------------------------------------------------------------
0545 
0546   Volume v_vacuum_main_pipe("v_vacuum_main_pipe", final_vacuum_main_pipe, m_vac);
0547   sdet.setAttributes(det, v_vacuum_main_pipe, x_det.regionStr(), x_det.limitsStr(), "AnlBlue");
0548 
0549   auto pv_vacuum_0 = assembly.placeVolume(
0550       v_vacuum_main_pipe,
0551       Transform3D(RotationY(crossingAngle), Position(beampipe_dimensions[pieceIdx].xCenter + 4.0,
0552                                                      0.0, beampipe_dimensions[pieceIdx].zCenter)));
0553   pv_vacuum_0.addPhysVolID("sector", 1);
0554   DetElement vacuum_de_0(sdet, Form("sector_FF_vacuum_%d_de", pieceIdx), 1);
0555   vacuum_de_0.setPlacement(pv_vacuum_0);
0556 
0557   //------------------------------------------------------------------
0558 
0559   for (int idx = 1; idx < 6; idx++) { //loop for the easier pieces to simplify
0560 
0561     if (idx == 2 || idx == 4) {
0562       continue;
0563     } //FIXME: don't fill RP chambers with vacuum yet - still an issue with RP geometry
0564 
0565     Box inner_vacuum(beampipe_dimensions[idx].innerXRadius, beampipe_dimensions[idx].innerYRadius,
0566                      (beampipe_dimensions[idx].length) / 2);
0567 
0568     Volume v_inner_vacuum(Form("v_vacuum_%d", idx), inner_vacuum, m_vac);
0569     sdet.setAttributes(det, v_inner_vacuum, x_det.regionStr(), x_det.limitsStr(), "AnlBlue");
0570 
0571     auto pv_final = assembly.placeVolume(
0572         v_inner_vacuum,
0573         Transform3D(RotationY(beampipe_dimensions[idx].rotationAngle),
0574                     Position(beampipe_dimensions[idx].xCenter, beampipe_dimensions[idx].yCenter,
0575                              beampipe_dimensions[idx].zCenter)));
0576     pv_final.addPhysVolID("sector", 1);
0577     DetElement final_de(sdet, Form("sector_FF_vacuum_%d_de", idx), 1);
0578     final_de.setPlacement(pv_final);
0579   }
0580 
0581   //------------------------------------------------------------------
0582 
0583   pieceIdx = 6;
0584 
0585   EightPointSolid vacuum_taper((0.5 * beampipe_dimensions[pieceIdx].length), trpVerticesInner);
0586 
0587   Volume v_vacuum_taper("v_vacuum_taper", vacuum_taper, m_vac);
0588   sdet.setAttributes(det, v_vacuum_taper, x_det.regionStr(), x_det.limitsStr(), "AnlBlue");
0589 
0590   auto pv_vacuum_6 = assembly.placeVolume(
0591       v_vacuum_taper, Transform3D(RotationY(beampipe_dimensions[pieceIdx].rotationAngle),
0592                                   Position(beampipe_dimensions[pieceIdx].xCenter, 0.0,
0593                                            beampipe_dimensions[pieceIdx].zCenter)));
0594   pv_vacuum_6.addPhysVolID("sector", 1);
0595   DetElement vacuum_de_6(sdet, Form("sector_FF_vacuum_%d_de", pieceIdx), 1);
0596   vacuum_de_6.setPlacement(pv_vacuum_6);
0597 
0598   //-------------------------------------------------------------------
0599 
0600   pieceIdx = 7; //vacuum between taper and B2PF
0601 
0602   Tube vacuum_pipe_after_taper(0.0, beampipe_dimensions[pieceIdx].innerXRadius,
0603                                beampipe_dimensions[pieceIdx].length / 2);
0604 
0605   Volume v_vacuum_pipe_after_taper("v_vacuum_pipe_after_taper", vacuum_pipe_after_taper, m_vac);
0606   sdet.setAttributes(det, v_vacuum_pipe_after_taper, x_det.regionStr(), x_det.limitsStr(),
0607                      "AnlBlue");
0608 
0609   auto pv_vacuum_7 = assembly.placeVolume(
0610       v_vacuum_pipe_after_taper, Transform3D(RotationY(beampipe_dimensions[pieceIdx].rotationAngle),
0611                                              Position(beampipe_dimensions[pieceIdx].xCenter,
0612                                                       beampipe_dimensions[pieceIdx].yCenter,
0613                                                       beampipe_dimensions[pieceIdx].zCenter)));
0614   pv_vacuum_7.addPhysVolID("sector", 1);
0615   DetElement vacuum_de_7(sdet, Form("sector_FF_vacuum_%d_de", pieceIdx), 1);
0616   vacuum_de_7.setPlacement(pv_vacuum_7);
0617 
0618   //-------------------------------------------------------------------
0619 
0620   pv_assembly = det.pickMotherVolume(sdet).placeVolume(assembly);
0621   pv_assembly.addPhysVolID("system", x_det.id()).addPhysVolID("barrel", 1);
0622   sdet.setPlacement(pv_assembly);
0623   assembly->GetShape()->ComputeBBox();
0624   return sdet;
0625 }
0626 
0627 DECLARE_DETELEMENT(forwardBeamPipeBrazil, create_detector)