diff --git a/compact/colors.xml b/compact/colors.xml index 4c320b287c..b233b2fb2b 100644 --- a/compact/colors.xml +++ b/compact/colors.xml @@ -11,6 +11,7 @@ + diff --git a/compact/display.xml b/compact/display.xml index 69e76b048d..1ba062ac8c 100644 --- a/compact/display.xml +++ b/compact/display.xml @@ -141,9 +141,13 @@ Beam line with magnets - - - + + + + + + + ZDC visualization diff --git a/compact/display_detailed.xml b/compact/display_detailed.xml index 0c98e51c29..9857e2d3b4 100644 --- a/compact/display_detailed.xml +++ b/compact/display_detailed.xml @@ -114,13 +114,6 @@ - - Beam line with magnets - - - - - ZDC visualization diff --git a/compact/display_geoviewer.xml b/compact/display_geoviewer.xml index eadeee7ff1..9ea8e3750c 100644 --- a/compact/display_geoviewer.xml +++ b/compact/display_geoviewer.xml @@ -114,13 +114,6 @@ - - Beam line with magnets - - - - - ZDC visualization diff --git a/compact/far_backward/beamline_extension_electron.xml b/compact/far_backward/beamline_extension_electron.xml index e1346df240..d3542c26da 100644 --- a/compact/far_backward/beamline_extension_electron.xml +++ b/compact/far_backward/beamline_extension_electron.xml @@ -1,5 +1,5 @@ - + @@ -9,7 +9,6 @@ - Electron side extended beam pipe volumes - + @@ -10,20 +10,12 @@ - Hadron side beam magnet volumes - - - - - - - + vis="MagnetVis"> @@ -50,7 +42,6 @@ - Hadron side beam pipe volumes diff --git a/compact/far_backward/magnets.xml b/compact/far_backward/magnets.xml index f4bc82bd45..6976fa2d4d 100644 --- a/compact/far_backward/magnets.xml +++ b/compact/far_backward/magnets.xml @@ -3,15 +3,93 @@ + + See compact/far_forward/ion_beamline.xml for hadron magnet element coordinate description-the same is applied to the electron magnet elements + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Electron side magnets + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Electron side beam pipe volumes Electron side beam magnet volumes - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Hadron side magnets + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compact/far_forward/B0_tracker.xml b/compact/far_forward/B0_tracker.xml index 88ec565e7a..3d44537cb3 100644 --- a/compact/far_forward/B0_tracker.xml +++ b/compact/far_forward/B0_tracker.xml @@ -46,19 +46,19 @@ - + - + - + - + diff --git a/compact/far_forward/beampipe_hadron_B0.xml b/compact/far_forward/beampipe_hadron_B0.xml index f23e72b590..21501127d7 100644 --- a/compact/far_forward/beampipe_hadron_B0.xml +++ b/compact/far_forward/beampipe_hadron_B0.xml @@ -16,7 +16,7 @@ - + diff --git a/compact/far_forward/electron_beamline.xml b/compact/far_forward/electron_beamline.xml index 6dbac133dc..e4af388608 100644 --- a/compact/far_forward/electron_beamline.xml +++ b/compact/far_forward/electron_beamline.xml @@ -1,10 +1,26 @@ - + + + See compact/far_forward/ion_beamline.xml for hadron magnet element coordinate description-the same is applied to the electron magnet elements + + + + + + + + + + + + + + @@ -22,69 +38,60 @@ - - + + - + - - - - - - - + - - - - - - !--unchecked-- - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - !--unchecked-- - - - - - - - - + + + + + diff --git a/compact/far_forward/ion_beamline.xml b/compact/far_forward/ion_beamline.xml index 17e27815c1..8fea2e790c 100644 --- a/compact/far_forward/ion_beamline.xml +++ b/compact/far_forward/ion_beamline.xml @@ -1,10 +1,93 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Instructions on how to obtain magnet element coordinates and dimensions. + + The reference STEP file, provided by the Superconducting Magnet Division (SMD), is available on SharePoint: + EIC Public Sharing Docs → Documents → Experimental Program → ePIC → Engineering → STR-Files → IR6_CRYOSTAT_2200m_top_4-24-2025.stp + [https://brookhavenlab.sharepoint.com/:u:/s/EICPublicSharingDocs/EdR44ODny1BEmMTTks61CCwBe8tJYMc0iWkPIYY_EjYEuw?e=2XLUEt] + + -The file can be opened using Onshape (www.onshape.com), a free, cloud-based CAD platform for 3D modeling and mechanical design. + -Both the forward (FWD) and backward (BWD/rear) cryostats contain multiple sub-cryostats, primarily associated with hadron magnets. + -The main components are the magnet yokes; most other elements—such as coils, support tubes, yoke shielding, heat shielding, and vessels—are positioned relative to these yokes. + -Since the STEP file provides coordinates in the RHIC coordinate system, a rotation and translation must be applied before using them in the geometry XML files. See page 19 of the following PDF from the IR Meeting on May 30, 2025: + [https://brookhavenlab.sharepoint.com/:b:/r/sites/eRHIC/bnl%26slac/EIC%20IR%20Meeting%20Minutes%20%20Documents/IR-Meeting/2025/05-30-2025/EIC_CRYO_GEANT4_May2025_NATOCHII_UPDATED.pdf] + + -- Apply a shift of 81 cm (the offset between RHIC and EIC IP6 interaction points). + -- Apply a rotation of 8 mrad to align with the ePIC detector axis. + + Example of how to extract coordinates from Onshape and compute the yoke's position and orientation: + + TVector3 coord1(-47.389536*cm, 0, -1704.865494*cm); // B1pF yoke endcap — IP side + TVector3 coord2(-41.351827*cm, 0, -2009.882603*cm); // B1pF yoke endcap — non-IP side + // Rotate around the Y axis by (π-8e-3) + double angle = M_PI-8e-3; // π flips the Z-axis; 8e-3 rad aligns with ePIC axis + coord1.RotateY(angle*rad); + coord2.RotateY(angle*rad); + // Compute center + TVector3 center = 0.5*(coord1+coord2); + center += TVector3(-81.*cm, 0, 0); // Apply RHIC → EIC IP6 offset + // Compute rotation angle around Y + double deltaX = coord2.X()-coord1.X(); + double deltaZ = coord2.Z()-coord1.Z(); + double rotY_angle = atan(deltaX/deltaZ)*rad; + // Threshold small angles + if (1e-6 > std::abs(rotY_angle)) { + rotY_angle = 0; + } + // Add 'center' and 'rotY_angle' to the XML file + + -Some barrel elements (e.g., heat shield, vessel) and endplates are described using polygons with two or more Z-planes. Example: + + + + + + Here, 160.817560 cm is the distance between the inner surfaces of the two Q1ApF endplates (mounted on both ends of the magnet), + and 15.246221 cm is the Z-thickness of the endplate on the IP side (note the minus sign). + + ===================================== (170-177) Forward Hadron Beamline Magnets (up to B0pf) @@ -21,54 +104,601 @@ ===================================== - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/compact/far_forward/offM_tracker.xml b/compact/far_forward/offM_tracker.xml index b3ba6d2f3f..d2fe86676e 100644 --- a/compact/far_forward/offM_tracker.xml +++ b/compact/far_forward/offM_tracker.xml @@ -30,7 +30,7 @@ readout="ForwardOffMTrackerHits" vis="FFTrackerVis" reflect="false"> - + @@ -55,7 +55,7 @@ readout="ForwardOffMTrackerHits" vis="AnlRed" reflect="false"> - + @@ -80,7 +80,7 @@ readout="ForwardOffMTrackerHits" vis="FFTrackerVis" reflect="false"> - + @@ -105,7 +105,7 @@ readout="ForwardOffMTrackerHits" vis="FFTrackerVis" reflect="false"> - + diff --git a/compact/far_forward/vacuum.xml b/compact/far_forward/vacuum.xml index ad5c8acab7..15b2688ca6 100644 --- a/compact/far_forward/vacuum.xml +++ b/compact/far_forward/vacuum.xml @@ -14,49 +14,49 @@ - + - + - + - + - + - + - + - + diff --git a/compact/materials.xml b/compact/materials.xml index 358f4b6954..7e79bb1f4a 100644 --- a/compact/materials.xml +++ b/compact/materials.xml @@ -547,4 +547,24 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/CryostatMagnet_geo.cpp b/src/CryostatMagnet_geo.cpp new file mode 100644 index 0000000000..42276e3746 --- /dev/null +++ b/src/CryostatMagnet_geo.cpp @@ -0,0 +1,394 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright (C) 2022 Alex Jentsch, Wouter Deconinck, Whitney Armstrong, Andrii Natochii + +#include "DD4hep/DetFactoryHelper.h" +#include "DD4hep/Printout.h" +#include "DD4hep/Shapes.h" +#include "DDRec/DetectorData.h" +#include "DDRec/Surface.h" +#include "TMath.h" +#include "XML/Layering.h" + +using namespace std; +using namespace dd4hep; +using namespace dd4hep::rec; +using namespace ROOT::Math; + +void buildTubeElement(dd4hep::DetElement& sdet, dd4hep::Assembly& assembly, dd4hep::Detector& dtor, + dd4hep::xml::DetElement x_det, string element, dd4hep::Material material); +void buildPolyElement(dd4hep::DetElement& sdet, dd4hep::Assembly& assembly, dd4hep::Detector& dtor, + dd4hep::xml::DetElement x_det, string element, dd4hep::Material material); + +static Ref_t build_magnet(Detector& dtor, xml_h e, SensitiveDetector /* sens */) { + xml_det_t x_det = e; + int det_id = x_det.id(); + string det_name = x_det.nameStr(); + + DetElement sdet(det_name, det_id); + Assembly assembly(det_name + "_assembly"); + + // get materials + Material iron = dtor.material("Iron"); + Material nbti = dtor.material("SolenoidCoil"); + Material steel_304l = dtor.material("StainlessSteelSAE304"); + Material alum = dtor.material("Al6061T6"); + Material steel_a53 = dtor.material("StainlessSteelA53"); + + // build magnet components + buildTubeElement(sdet, assembly, dtor, x_det, "yoke", iron); + buildTubeElement(sdet, assembly, dtor, x_det, "coil", nbti); + buildTubeElement(sdet, assembly, dtor, x_det, "tube", steel_304l); + buildPolyElement(sdet, assembly, dtor, x_det, "endplate", steel_304l); + buildTubeElement(sdet, assembly, dtor, x_det, "yokeshield", steel_304l); + buildTubeElement(sdet, assembly, dtor, x_det, "heatshieldbarrel", alum); + buildPolyElement(sdet, assembly, dtor, x_det, "heatshieldend", alum); + buildTubeElement(sdet, assembly, dtor, x_det, "cryobarrel", steel_a53); + buildPolyElement(sdet, assembly, dtor, x_det, "cryoend", steel_a53); + + // final placement + auto pv_assembly = dtor.pickMotherVolume(sdet).placeVolume(assembly); + pv_assembly.addPhysVolID("system", det_id); + sdet.setPlacement(pv_assembly); + + // update bounding box + assembly->GetShape()->ComputeBBox(); + + return sdet; +} + +void buildPolyElement(dd4hep::DetElement& sdet, dd4hep::Assembly& assembly, dd4hep::Detector& dtor, + dd4hep::xml::DetElement x_det, string element, dd4hep::Material material) { + // get all elems + xml_coll_t elems_c(x_det, element.c_str()); + int elem_id = 1; + + // loop over elems + for (; elems_c; ++elems_c) { + // get one element + xml_comp_t elem_c = elems_c; + string elem_name = elem_c.nameStr(); + // get placement coordinates + xml_dim_t elem_pos = elem_c.child(_U(placement)); + double elem_theta = elem_pos.attr("theta"); + std::vector z; + std::vector rmax; + std::vector rmin; + // loop over z-planes + xml_coll_t zplanes_c(elem_c, _Unicode(zplane)); + for (; zplanes_c; ++zplanes_c) { + // get z-plane + xml_comp_t zplane_c = zplanes_c; + z.push_back(zplane_c.attr(_Unicode(z))); + rmin.push_back(zplane_c.attr(_Unicode(rmin))); + rmax.push_back(zplane_c.attr(_Unicode(rmax))); + } + + // set attributes + const string elem_vis = + dd4hep::getAttrOrDefault(elem_c, _Unicode(vis), "FFMagnetVis"); + sdet.setAttributes(dtor, assembly, x_det.regionStr(), x_det.limitsStr(), elem_vis); + + // build solid + Polycone elem_tube(0, 2.0 * M_PI, rmin, rmax, z); + Solid elem_final(elem_tube); + + // get all adds + xml_coll_t adds_c(elem_c, _Unicode(add)); + // loop over adds + for (; adds_c; ++adds_c) { + Solid add_elem; + // get one cut + xml_comp_t add_c = adds_c; + // get shape + string add_shape = add_c.attr("shape"); + // get placement coordinates + xml_dim_t add_pos = add_c.child(_U(placement)); + double add_theta = add_pos.attr("theta"); + // get dimentions + xml_dim_t add_dim = add_c.child(_U(dimensions)); + + Transform3D tf_tmp(RotationZYX(0, add_theta, 0), + Position(add_pos.x(), add_pos.y(), add_pos.z())); + + if (add_shape == "Prism") { + double add_pdx1 = add_dim.attr("pdx1"); + double add_pdx2 = add_dim.attr("pdx2"); + double add_pdy1 = add_dim.attr("pdy1"); + double add_pdy2 = add_dim.attr("pdy2"); + double add_pdz = add_dim.attr("pdz"); + + // build a solid + Trapezoid add_prism(add_pdx1, add_pdx2, add_pdy1, add_pdy2, add_pdz); + add_elem = add_prism; + } else if (add_shape == "Tube") { + double add_rmin = add_dim.attr("rmin"); + double add_rmax = add_dim.attr("rmax"); + double add_half_l = add_dim.attr("half_length"); + + // build a solid + Tube add_tube(add_rmin, add_rmax, add_half_l); + add_elem = add_tube; + } + + // unite the add with the element solid + elem_final = UnionSolid("elem_final", elem_final, add_elem, tf_tmp); + } + + // get all cuts + xml_coll_t cuts_c(elem_c, _Unicode(cut)); + + Solid cut_final; + // loop over cuts + for (; cuts_c; ++cuts_c) { + // get one cut + xml_comp_t cut_c = cuts_c; + // get shape + string cut_shape = dd4hep::getAttrOrDefault(cut_c, _Unicode(shape), "Tube"); + + // get placement coordinates + xml_dim_t cut_pos = cut_c.child(_U(placement)); + double cut_rotX = cut_pos.attr("rotX"); + double cut_rotY = cut_pos.attr("rotY"); + double cut_rotZ = cut_pos.attr("rotZ"); + // get rotation coordinates + xml_dim_t cut_rot = cut_c.child(_U(rotation)); + int cut_rot_num = cut_rot.attr("num"); + double cut_rot_step = cut_rot.attr("step"); + double cut_rot_start = cut_rot.attr("start"); + string cut_rot_axis = cut_rot.attr("axis"); + + if (cut_shape == "Cone") { + // get dimentions + xml_dim_t cut_dim = cut_c.child(_U(dimensions)); + double cut_rmin1 = cut_dim.attr("rmin1"); + double cut_rmax1 = cut_dim.attr("rmax1"); + double cut_rmin2 = cut_dim.attr("rmin2"); + double cut_rmax2 = cut_dim.attr("rmax2"); + double cut_dz = cut_dim.attr("dz"); + + // build a solid + Cone cut_cone(cut_dz, cut_rmin1, cut_rmax1, cut_rmin2, cut_rmax2); + cut_final = cut_cone; + } else if (cut_shape == "Tube") { + // get dimentions + xml_dim_t cut_dim = cut_c.child(_U(dimensions)); + double cut_rmin = cut_dim.attr("rmin"); + double cut_rmax = cut_dim.attr("rmax"); + double cut_half_l = cut_dim.attr("half_length"); + + // build a solid + Tube cut_tube(cut_rmin, cut_rmax, cut_half_l); + cut_final = cut_tube; + } + + // loop over rot steps + for (int i = 0; i < cut_rot_num; i++) { + Position pos_tmp(cut_pos.x(), cut_pos.y(), cut_pos.z()); + double ang_tmp = cut_rot_start + i * cut_rot_step; + Rotation3D rot_tmp; + if (cut_rot_axis == "X") { + rot_tmp = RotationX(ang_tmp); + } else if (cut_rot_axis == "Y") { + rot_tmp = RotationY(ang_tmp); + } else { + rot_tmp = RotationZ(ang_tmp); + } + pos_tmp = rot_tmp * pos_tmp; + + Transform3D tf_tmp(RotationZYX(cut_rotZ, cut_rotY, cut_rotX), pos_tmp); + // subtract the cut from the element solid + elem_final = SubtractionSolid("elem_final", elem_final, cut_final, tf_tmp); + } + } + + // create volume + Volume elem_vol(elem_name, elem_final, material); + + // placement + auto elem_pv = assembly.placeVolume( + elem_vol, Transform3D(Translation3D(elem_pos.x(), elem_pos.y(), elem_pos.z()) * + RotationY(elem_theta))); + elem_pv.addPhysVolID(element, elem_id); + DetElement elem_de(sdet, elem_name, elem_id); + elem_de.setPlacement(elem_pv); + elem_de.setAttributes(dtor, elem_vol, x_det.regionStr(), x_det.limitsStr(), elem_vis); + elem_id++; + } + + return; +} + +void buildTubeElement(dd4hep::DetElement& sdet, dd4hep::Assembly& assembly, dd4hep::Detector& dtor, + dd4hep::xml::DetElement x_det, string element, dd4hep::Material material) { + // get all elems + xml_coll_t elems_c(x_det, element.c_str()); + int elem_id = 1; + + // loop over elems + for (; elems_c; ++elems_c) { + // get one element + xml_comp_t elem_c = elems_c; + string elem_name = elem_c.nameStr(); + // get placement coordinates + xml_dim_t elem_pos = elem_c.child(_U(placement)); + double elem_theta = elem_pos.attr("theta"); + + // set attributes + const string elem_vis = + dd4hep::getAttrOrDefault(elem_c, _Unicode(vis), "FFMagnetVis"); + sdet.setAttributes(dtor, assembly, x_det.regionStr(), x_det.limitsStr(), elem_vis); + + // get shape + string elem_shape = dd4hep::getAttrOrDefault(elem_c, _Unicode(shape), "Tube"); + + Solid elem_sub; + if (elem_shape == "Cone") { + // get dimentions + xml_dim_t elem_dim = elem_c.child(_U(dimensions)); + double elem_rmin1 = elem_dim.attr("rmin1"); + double elem_rmax1 = elem_dim.attr("rmax1"); + double elem_rmin2 = elem_dim.attr("rmin2"); + double elem_rmax2 = elem_dim.attr("rmax2"); + double elem_dz = elem_dim.attr("dz"); + + // build a solid + Cone elem_cone(elem_dz, elem_rmin1, elem_rmax1, elem_rmin2, elem_rmax2); + elem_sub = elem_cone; + } else if (elem_shape == "ConeSegment") { + // get dimentions + xml_dim_t elem_dim = elem_c.child(_U(dimensions)); + double elem_rmin1 = elem_dim.attr("rmin1"); + double elem_rmax1 = elem_dim.attr("rmax1"); + double elem_rmin2 = elem_dim.attr("rmin2"); + double elem_rmax2 = elem_dim.attr("rmax2"); + double elem_dz = elem_dim.attr("dz"); + double elem_sphi = elem_dim.attr("sphi"); + double elem_dphi = elem_dim.attr("dphi"); + + // build a solid + ConeSegment elem_conesegment(elem_dz, elem_rmin1, elem_rmax1, elem_rmin2, elem_rmax2, + elem_sphi, elem_sphi + elem_dphi); + elem_sub = elem_conesegment; + } else if (elem_shape == "Tube") { + // get dimentions + xml_dim_t elem_dim = elem_c.child(_U(dimensions)); + double elem_rmin = elem_dim.attr("rmin"); + double elem_rmax = elem_dim.attr("rmax"); + double elem_half_l = elem_dim.attr("half_length"); + double elem_sphi = elem_dim.attr("sphi"); + double elem_dphi = elem_dim.attr("dphi"); + + // build solid + Tube elem_tube(elem_rmin, elem_rmax, elem_half_l, elem_sphi, elem_sphi + elem_dphi); + elem_sub = elem_tube; + } + + Solid elem_final(elem_sub); + + // combine sub-elements + if (elem_pos.hasAttr(_Unicode(phiNum))) { + int phi_num = elem_pos.attr("phiNum"); + double phi_step = elem_pos.attr("phiStep"); + double phi_start = elem_pos.attr("phiStart"); + + // loop over steps + for (int i = 0; i < phi_num; i++) { + double phi_tmp = phi_start + i * phi_step; + Transform3D tf_tmp(RotationZ(phi_tmp), Position(0, 0, 0)); + // unite sub-elements + elem_final = UnionSolid("elem_final", elem_final, elem_sub, tf_tmp); + } + } + + // get all cuts + xml_coll_t cuts_c(elem_c, _Unicode(cut)); + // loop over cuts + for (; cuts_c; ++cuts_c) { + // get one cut + xml_comp_t cut_c = cuts_c; + // get shape + string add_shape = dd4hep::getAttrOrDefault(cut_c, _Unicode(shape), "Tube"); + // get placement coordinates + xml_dim_t cut_pos = cut_c.child(_U(placement)); + double cut_rotX = cut_pos.attr("rotX"); + double cut_rotY = cut_pos.attr("rotY"); + double cut_rotZ = cut_pos.attr("rotZ"); + // get rotation coordinates + xml_dim_t cut_rot = cut_c.child(_U(rotation)); + int cut_rot_num = cut_rot.attr("num"); + double cut_rot_step = cut_rot.attr("step"); + double cut_rot_start = cut_rot.attr("start"); + string cut_rot_axis = cut_rot.attr("axis"); + + Solid cut_elem; + if (add_shape == "Box") { + // get dimentions + xml_dim_t cut_dim = cut_c.child(_U(dimensions)); + double cut_dx = cut_dim.attr("dx"); + double cut_dy = cut_dim.attr("dy"); + double cut_dz = cut_dim.attr("dz"); + + // build a solid + Box cut_box(cut_dx, cut_dy, cut_dz); + cut_elem = cut_box; + } else if (add_shape == "Tube") { + // get dimentions + xml_dim_t cut_dim = cut_c.child(_U(dimensions)); + double cut_rmin = cut_dim.attr("rmin"); + double cut_rmax = cut_dim.attr("rmax"); + double cut_half_l = cut_dim.attr("half_length"); + + // build a solid + Tube cut_tube(cut_rmin, cut_rmax, cut_half_l); + cut_elem = cut_tube; + } else if (add_shape == "Cone") { + // get dimentions + xml_dim_t cut_dim = cut_c.child(_U(dimensions)); + double cut_rmin1 = cut_dim.attr("rmin1"); + double cut_rmax1 = cut_dim.attr("rmax1"); + double cut_rmin2 = cut_dim.attr("rmin2"); + double cut_rmax2 = cut_dim.attr("rmax2"); + double cut_dz = cut_dim.attr("dz"); + + // build a solid + Cone cut_cone(cut_dz, cut_rmin1, cut_rmax1, cut_rmin2, cut_rmax2); + cut_elem = cut_cone; + } + // loop over rot steps + for (int i = 0; i < cut_rot_num; i++) { + Position pos_tmp(cut_pos.x(), cut_pos.y(), cut_pos.z()); + double ang_tmp = cut_rot_start + i * cut_rot_step; + Rotation3D rot_tmp; + if (cut_rot_axis == "X") { + rot_tmp = RotationX(ang_tmp); + } else if (cut_rot_axis == "Y") { + rot_tmp = RotationY(ang_tmp); + } else { + rot_tmp = RotationZ(ang_tmp); + } + pos_tmp = rot_tmp * pos_tmp; + + Transform3D tf_tmp(RotationZYX(cut_rotZ, cut_rotY, cut_rotX), pos_tmp); + // subtract the cut from the element solid + elem_final = SubtractionSolid("elem_final", elem_final, cut_elem, tf_tmp); + } + } + + // create volume + Volume elem_vol(elem_name, elem_final, material); + + // placement + auto elem_pv = assembly.placeVolume( + elem_vol, Transform3D(Translation3D(elem_pos.x(), elem_pos.y(), elem_pos.z()) * + RotationY(elem_theta))); + elem_pv.addPhysVolID(element, elem_id); + DetElement elem_de(sdet, elem_name, elem_id); + elem_de.setPlacement(elem_pv); + elem_de.setAttributes(dtor, elem_vol, x_det.regionStr(), x_det.limitsStr(), elem_vis); + elem_id++; + } + + return; +} + +DECLARE_DETELEMENT(ip6_CryostatMagnet, build_magnet) diff --git a/src/CylindricalDipoleMagnet_geo.cpp b/src/CylindricalDipoleMagnet_geo.cpp deleted file mode 100644 index 33f9318849..0000000000 --- a/src/CylindricalDipoleMagnet_geo.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright (C) 2022 Alex Jentsch, Wouter Deconinck, Whitney Armstrong - -#include "DD4hep/DetFactoryHelper.h" -#include "DD4hep/Printout.h" -#include "DD4hep/Shapes.h" -#include "DDRec/DetectorData.h" -#include "DDRec/Surface.h" -#include "TMath.h" -#include "XML/Layering.h" - -using namespace std; -using namespace dd4hep; -using namespace dd4hep::rec; -using namespace ROOT::Math; - -static Ref_t build_magnet(Detector& dtor, xml_h e, SensitiveDetector /* sens */) { - xml_det_t x_det = e; - int det_id = x_det.id(); - string det_name = x_det.nameStr(); - xml_dim_t pos = x_det.child(_U(placement)); - double pos_x = pos.x(); - double pos_y = pos.y(); - double pos_z = pos.z(); - double pos_theta = pos.attr(_U(theta)); - xml_dim_t dims = x_det.dimensions(); - double dim_r = dims.r(); - double dim_z = dims.z(); - xml_dim_t apperture = x_det.child(_Unicode(apperture)); - double app_r = apperture.r(); - Material iron = dtor.material("Iron"); - - DetElement sdet(det_name, det_id); - Assembly assembly(det_name + "_assembly"); - - const string module_name = "Quad_magnet"; - - const string yoke_vis = - dd4hep::getAttrOrDefault(x_det, _Unicode(vis), "FFMagnetVis"); - - sdet.setAttributes(dtor, assembly, x_det.regionStr(), x_det.limitsStr(), yoke_vis); - - // -- yoke - Tube yoke_tube(app_r, dim_r, 0.5 * dim_z); - Volume yoke_vol("yoke_vol", yoke_tube, iron); - auto yoke_pv = assembly.placeVolume(yoke_vol); - yoke_pv.addPhysVolID("element", 1); - DetElement yoke_de(sdet, "yoke_de", 1); - yoke_de.setPlacement(yoke_pv); - yoke_de.setAttributes(dtor, yoke_vol, x_det.regionStr(), x_det.limitsStr(), yoke_vis); - - // -- finishing steps - auto final_pos = Transform3D(Translation3D(pos_x, pos_y, pos_z) * RotationY(pos_theta)); - auto pv = dtor.pickMotherVolume(sdet).placeVolume(assembly, final_pos); - pv.addPhysVolID("system", det_id); - sdet.setPlacement(pv); - - assembly->GetShape()->ComputeBBox(); - return sdet; -} - -DECLARE_DETELEMENT(ip6_CylindricalDipoleMagnet, build_magnet) diff --git a/src/forwardBeamPipeBrazil.cpp b/src/forwardBeamPipeBrazil.cpp index be797c9181..3e02e587ef 100644 --- a/src/forwardBeamPipeBrazil.cpp +++ b/src/forwardBeamPipeBrazil.cpp @@ -260,6 +260,8 @@ static Ref_t create_detector(Detector& det, xml_h e, SensitiveDetector /* sens * //------------------------------------------ //begin building main volumes here //------------------------------------------ + // A box to cut out from the beam pipe to avoid overlaps with the fwd cryostat + Box cutout_for_FWD_cryo(1 * dd4hep::m, 1 * dd4hep::m, 2 * dd4hep::m); //------------------------------------------------------------------- @@ -290,6 +292,12 @@ static Ref_t create_detector(Detector& det, xml_h e, SensitiveDetector /* sens * tmpAfterB1APF, neutral_exit_window_cutout, Position(160.0 * dd4hep::mm, 0.0, 0.5 * beampipe_dimensions[pieceIdx].length)); + //----------------------------------------------------------------- + // Cut on the IP side to avoid overlaps with the fwd cryostat + tmpAfterB1APF = SubtractionSolid(tmpAfterB1APF, cutout_for_FWD_cryo, + Position(0.0, 0.0, (-beampipe_dimensions[pieceIdx].length) / 2)); + //----------------------------------------------------------------- + Volume v_pipeAfterB1APF(Form("v_pipeAfterB1APF_%d", pieceIdx), tmpAfterB1APF, m_SS); sdet.setAttributes(det, v_pipeAfterB1APF, x_det.regionStr(), x_det.limitsStr(), vis_name); @@ -517,10 +525,23 @@ static Ref_t create_detector(Detector& det, xml_h e, SensitiveDetector /* sens * SubtractionSolid final_vacuum_main_pipe( vacuum_main_pipe, cutout_for_OMD_station, - Position(0.0, 0.0, (2251.0 - beampipe_dimensions[pieceIdx].zCenter))); - final_vacuum_main_pipe = - SubtractionSolid(final_vacuum_main_pipe, cutout_for_OMD_station, - Position(0.0, 0.0, (2451.0 - beampipe_dimensions[pieceIdx].zCenter))); + Position(0.0, 0.0, (2551.0 * dd4hep::cm - beampipe_dimensions[pieceIdx].zCenter))); + final_vacuum_main_pipe = SubtractionSolid( + final_vacuum_main_pipe, cutout_for_OMD_station, + Position(0.0, 0.0, (2701.0 * dd4hep::cm - beampipe_dimensions[pieceIdx].zCenter))); + + //----------------------------------------------------------------- + // Cut on the IP side to avoid overlaps with the fwd cryostat + final_vacuum_main_pipe = SubtractionSolid( + final_vacuum_main_pipe, cutout_for_FWD_cryo, + Position(0.0, 0.0, + (2400.0 * dd4hep::cm - 2 * dd4hep::m - beampipe_dimensions[pieceIdx].zCenter))); + Tube pipe_for_FWD_cryo(0.0, 16.0 * dd4hep::cm, 97.0 * dd4hep::cm); + final_vacuum_main_pipe = UnionSolid( + final_vacuum_main_pipe, pipe_for_FWD_cryo, + Position(6.5 * dd4hep::cm, 0.0, + (2400.0 * dd4hep::cm - 97.0 * dd4hep::cm - beampipe_dimensions[pieceIdx].zCenter))); + //----------------------------------------------------------------- Volume v_vacuum_main_pipe("v_vacuum_main_pipe", final_vacuum_main_pipe, m_vac); sdet.setAttributes(det, v_vacuum_main_pipe, x_det.regionStr(), x_det.limitsStr(), "AnlBlue"); diff --git a/src/magnetVacuumFF.cpp b/src/magnetVacuumFF.cpp index 94f915bbba..2f26763206 100644 --- a/src/magnetVacuumFF.cpp +++ b/src/magnetVacuumFF.cpp @@ -81,15 +81,15 @@ static Ref_t create_detector(Detector& det, xml_h e, SensitiveDetector /* sens * for (xml_coll_t c(x_det, _U(element)); c; ++c) { - xml_dim_t pos = c.child(_U(placement)); - double pos_x = pos.x(); - double pos_y = pos.y(); - double pos_z = pos.z(); - double pos_theta = pos.attr(_U(theta)); - xml_dim_t dims = c.child(_U(dimensions)); //dimensions(); - double dim_z = dims.z(); - xml_dim_t apperture = c.child(_Unicode(apperture)); - double app_r = apperture.r(); + xml_dim_t pos = c.child(_U(placement)); + double pos_x = pos.x(); + double pos_y = pos.y(); + double pos_z = pos.z(); + double pos_theta = pos.attr(_U(theta)); + xml_dim_t dims = c.child(_U(dimensions)); //dimensions(); + double dim_z = dims.z(); + xml_dim_t aperture = c.child(_Unicode(aperture)); + double app_r = aperture.r(); radii_magnet.push_back(app_r); // cm lengths_magnet.push_back(dim_z); //cm @@ -246,8 +246,8 @@ static Ref_t create_detector(Detector& det, xml_h e, SensitiveDetector /* sens * std::string piece_name = Form("GapVacuum%d", numGaps + numMagnets); - Cone specialGap(piece_name, specialGapLength / 2, 0.0, vacuumDiameterEntrance / 2, 0.0, - vacuumDiameterExit / 2); + ConeSegment specialGap(piece_name, specialGapLength / 2, 0.0, vacuumDiameterEntrance / 2, 0.0, + vacuumDiameterExit / 2, 40 * deg, (360 - 40) * deg); Volume specialGap_v(piece_name, specialGap, m_Vac); sdet.setAttributes(det, specialGap_v, x_det.regionStr(), x_det.limitsStr(), vis_name);