diff --git a/compact/central_beampipe.xml b/compact/central_beampipe.xml index d611b1fb9a..54d5dc0d84 100644 --- a/compact/central_beampipe.xml +++ b/compact/central_beampipe.xml @@ -62,7 +62,8 @@ - + + diff --git a/compact/definitions.xml b/compact/definitions.xml index 40fcef2a5b..4d0e5e99fe 100644 --- a/compact/definitions.xml +++ b/compact/definitions.xml @@ -513,7 +513,7 @@ Service gaps in FW direction (before endcapP ECAL) and BW direction (before endc ## Calorimeter Parameters - + diff --git a/compact/display.xml b/compact/display.xml index 4ebcbe9f93..7b6a19b457 100644 --- a/compact/display.xml +++ b/compact/display.xml @@ -66,10 +66,10 @@ - + diff --git a/compact/display_detailed.xml b/compact/display_detailed.xml index 1fb9e874c4..712d5026a6 100644 --- a/compact/display_detailed.xml +++ b/compact/display_detailed.xml @@ -60,7 +60,7 @@ - + diff --git a/compact/display_geoviewer.xml b/compact/display_geoviewer.xml index 51fda1130d..1c9abe7f20 100644 --- a/compact/display_geoviewer.xml +++ b/compact/display_geoviewer.xml @@ -59,7 +59,7 @@ - + diff --git a/compact/ecal/barrel_interlayers.xml b/compact/ecal/barrel_interlayers.xml index cf28c16fb4..5596242d52 100644 --- a/compact/ecal/barrel_interlayers.xml +++ b/compact/ecal/barrel_interlayers.xml @@ -27,7 +27,7 @@ - + @@ -149,7 +149,9 @@ space_before="EcalBarrel_ImagingLayerThickness + EcalBarrel_SpaceBetween/2."> + diff --git a/compact/far_backward/definitions.xml b/compact/far_backward/definitions.xml index fb57e60f5e..fd2e29559b 100644 --- a/compact/far_backward/definitions.xml +++ b/compact/far_backward/definitions.xml @@ -256,8 +256,8 @@ - + @@ -269,10 +269,9 @@ - - - + + diff --git a/compact/far_backward/lumi/spec_homo_cal.xml b/compact/far_backward/lumi/spec_homo_cal.xml index bbd475b446..218916cb18 100644 --- a/compact/far_backward/lumi/spec_homo_cal.xml +++ b/compact/far_backward/lumi/spec_homo_cal.xml @@ -5,7 +5,7 @@ - + diff --git a/compact/far_backward/lumi/spec_tracker.xml b/compact/far_backward/lumi/spec_tracker.xml index 7e62235491..9245aff567 100644 --- a/compact/far_backward/lumi/spec_tracker.xml +++ b/compact/far_backward/lumi/spec_tracker.xml @@ -67,7 +67,7 @@ - + system:8,sector:8,module:8,x:32:-16,y:-16 diff --git a/compact/far_forward.xml b/compact/far_forward.xml index aca73425ab..bab9440722 100644 --- a/compact/far_forward.xml +++ b/compact/far_forward.xml @@ -5,6 +5,7 @@ + diff --git a/compact/far_forward/definitions.xml b/compact/far_forward/definitions.xml index c930874818..2d106024c1 100644 --- a/compact/far_forward/definitions.xml +++ b/compact/far_forward/definitions.xml @@ -62,8 +62,8 @@ - - + + diff --git a/compact/far_forward/electron_beamline.xml b/compact/far_forward/electron_beamline.xml new file mode 100644 index 0000000000..88f4642019 --- /dev/null +++ b/compact/far_forward/electron_beamline.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + !--unchecked-- + + + + + + + + + + + + + + + + !--unchecked-- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/compact/far_forward/ion_beamline.xml b/compact/far_forward/ion_beamline.xml index bfd7e4efd9..5ca8bcd706 100644 --- a/compact/far_forward/ion_beamline.xml +++ b/compact/far_forward/ion_beamline.xml @@ -69,19 +69,6 @@ - - - - - - - - - - - - - diff --git a/compact/optical_materials.xml b/compact/optical_materials.xml index b791d4f92d..aaa3897a70 100644 --- a/compact/optical_materials.xml +++ b/compact/optical_materials.xml @@ -7,6 +7,82 @@ 1.0*eV 1.0 5.1*eV 1.0 "/> + + + + + + Absorption length is caculated using transmittance values for 2 mm thickness (crystan standard UV grade) from + https://www.crystran.co.uk/optical-materials/sapphire-al2o3 + + F = ((n - 1) * (n - 1)) / ((n + 1) * (n + 1)) + + Absorption length = (-1 / ln(transmittance + 2*F)) * 2 mm + where: + F - Fresnel reflection coefficient + n - Refractive index of Sapphire + + + + - - + + @@ -809,6 +1054,13 @@ Nlak33aMaterial->AddElement(O, natoms = 2); --> + + + + + + + @@ -848,6 +1100,9 @@ --> + + + diff --git a/compact/pid/dirc.xml b/compact/pid/dirc.xml index d82159dcf6..42437a1f9c 100644 --- a/compact/pid/dirc.xml +++ b/compact/pid/dirc.xml @@ -32,9 +32,13 @@ - + + + + + @@ -45,8 +49,8 @@ - - + + @@ -56,8 +60,6 @@ - - @@ -94,7 +96,7 @@ - + @@ -127,11 +129,11 @@ repeat_y="DIRCBar_count_y" repeat_z="DIRCBar_count_z" gap="DIRCBar_gap" - material="Quartz" + material="QuartzOptical" vis="DIRCBar" /> - + @@ -163,7 +165,7 @@ height="DIRCMCP_height" width="DIRCMCP_width" thickness="DIRCMCP_thickness" - material="Quartz" + material="QuartzOptical" vis="DIRCMCP" /> diff --git a/compact/pid/drich.xml b/compact/pid/drich.xml index 67e30071c8..1d23e5a4d4 100644 --- a/compact/pid/drich.xml +++ b/compact/pid/drich.xml @@ -216,8 +216,8 @@ /> diff --git a/scripts/subdetector_tests/draw_bemc_scfi_grids.py b/scripts/subdetector_tests/draw_bemc_scfi_grids.py index 3fa29aaa4c..59ca58e7b5 100644 --- a/scripts/subdetector_tests/draw_bemc_scfi_grids.py +++ b/scripts/subdetector_tests/draw_bemc_scfi_grids.py @@ -61,7 +61,7 @@ def get_grid_fibers(det_elem, vol_man, id_conv, id_dict): for i in np.arange(gnode.GetNdaughters()): fnode = gnode.GetDaughter(int(i)) # NOTE, this is defined in geometry plugin, fiber_core is the only wanted sensitive detector - if 'fiber_core' not in fnode.GetName(): + if 'fiber' not in fnode.GetName(): continue fpos = np.array([0., 0., 0.]) gpos = np.array([0., 0., 0.]) @@ -129,7 +129,11 @@ def get_grid_fibers(det_elem, vol_man, id_conv, id_dict): ) parser.add_argument( '--no-marker', action='store_true', - help='Switch to draw a marker for grid center or not' + help='Switch on to not draw a marker for each grid\'s center', + ) + parser.add_argument( + '--no-fiber-edge', action='store_true', + help='Switch on to not draw fiber edge, might be helpful for a crowded plot.', ) args = parser.parse_args() @@ -181,7 +185,8 @@ def get_grid_fibers(det_elem, vol_man, id_conv, id_dict): patches = [] for fi in fibers: patches.append(Circle((fi[0], fi[1]), fi[3])) - p = PatchCollection(patches, alpha=0.6, facecolors=(c,), edgecolors=('k',)) + ec = 'k' if not args.no_fiber_edge else c + p = PatchCollection(patches, alpha=0.6, facecolors=(c,), edgecolors=(ec,)) if not args.no_marker: ax.plot(gr_pos[0], gr_pos[1], marker='P', mfc=c, mec='k', ms=9, label='grid {}'.format(ids['grid'])) ax.add_collection(p) diff --git a/src/BarrelCalorimeterInterlayers_geo.cpp b/src/BarrelCalorimeterInterlayers_geo.cpp index 8f8ed5fd1e..8706fc0a3a 100644 --- a/src/BarrelCalorimeterInterlayers_geo.cpp +++ b/src/BarrelCalorimeterInterlayers_geo.cpp @@ -50,8 +50,7 @@ struct FiberGrid { vector fiberPositions(double r, double sx, double sz, double trx, double trz, double phi, bool shift_first = false, double stol = 1e-2); -std::pair getNdivisions(double x, double z, double dx, double dz); -vector gridPoints(int div_x, int div_z, double x, double z, double phi); +vector gridPoints(int div_n_phi, double div_dr, double x, double z, double phi); // geometry helpers void buildFibers(Detector& desc, SensitiveDetector& sens, Volume& mother, int layer_nunber, xml_comp_t x_fiber, @@ -187,9 +186,9 @@ static Ref_t create_detector(Detector& desc, xml_h e, SensitiveDetector sens) if (x_det.hasChild(_U(staves))) { xml_comp_t x_staves = x_det.staves(); mod_vol.setVisAttributes(desc.visAttributes(x_staves.visStr())); - if (x_staves.hasChild(_U(support))) { - buildSupport(desc, mod_vol, x_staves.child(_U(support)), {inner_r, l_pos_z, x_dim.z(), hphi}); - } + } + if (x_det.hasChild(_U(support))) { + buildSupport(desc, mod_vol, x_det.child(_U(support)), {inner_r, l_pos_z, x_dim.z(), hphi}); } // Set envelope volume attributes. @@ -205,6 +204,8 @@ void buildFibers(Detector& desc, SensitiveDetector& sens, Volume& s_vol, int lay double f_cladding_thickness = getAttrOrDefault(x_fiber, _Unicode(cladding_thickness), 0.0 * cm); double f_spacing_x = getAttrOrDefault(x_fiber, _Unicode(spacing_x), 0.122 * cm); double f_spacing_z = getAttrOrDefault(x_fiber, _Unicode(spacing_z), 0.134 * cm); + int grid_n_phi = getAttrOrDefault(x_fiber, _Unicode(grid_n_phi), 5); + double grid_dr = getAttrOrDefault(x_fiber, _Unicode(grid_dr), 2.0*cm); std::string f_id_grid = getAttrOrDefault(x_fiber, _Unicode(identifier_grid), "grid"); std::string f_id_fiber = getAttrOrDefault(x_fiber, _Unicode(identifier_fiber), "fiber"); @@ -217,7 +218,7 @@ void buildFibers(Detector& desc, SensitiveDetector& sens, Volume& s_vol, int lay // fiber and its cladding double f_radius_core = f_radius - f_cladding_thickness; - Tube f_tube_clad(f_radius_core, f_radius, s_length); + Tube f_tube_clad(0, f_radius, s_length); Volume f_vol_clad("fiber_vol", f_tube_clad, desc.material(x_fiber.materialStr())); Tube f_tube_core(0, f_radius_core, s_length); Volume f_vol_core("fiber_core_vol", f_tube_core, desc.material(x_fiber.materialStr())); @@ -225,13 +226,13 @@ void buildFibers(Detector& desc, SensitiveDetector& sens, Volume& s_vol, int lay f_vol_core.setSensitiveDetector(sens); } f_vol_core.setAttributes(desc, x_fiber.regionStr(), x_fiber.limitsStr(), x_fiber.visStr()); + f_vol_clad.placeVolume(f_vol_core); - // Calculate number of divisions - auto grid_div = getNdivisions(s_trd_x1, s_thick, 2.0 * cm, 2.0 * cm); - // Calculate polygonal grid coordinates (vertices) - auto grids = gridPoints(grid_div.first, grid_div.second, s_trd_x1, s_thick, hphi); - vector f_id_count(grid_div.first * grid_div.second, 0); + // calculate polygonal grid coordinates (vertices) + auto grids = gridPoints(grid_n_phi, grid_dr, s_trd_x1, s_thick, hphi); + vector f_id_count(grids.size(), 0); + // use layer_number % 2 to add correct shifts for the adjacent fibers at layer boundary auto f_pos = fiberPositions(f_radius, f_spacing_x, f_spacing_z, s_trd_x1, s_thick, hphi, (layer_number % 2 == 0)); // a helper struct to speed up searching struct Fiber { @@ -267,9 +268,8 @@ void buildFibers(Detector& desc, SensitiveDetector& sens, Volume& s_vol, int lay // place fiber in grid auto p = fi.pos - gr.mean_centroid; - auto core_phv = grid_vol.placeVolume(f_vol_core, Position(p.x(), p.y(), 0.)); - core_phv.addPhysVolID(f_id_fiber, f_id); - grid_vol.placeVolume(f_vol_clad, Position(p.x(), p.y(), 0.)); + auto clad_phv = grid_vol.placeVolume(f_vol_clad, Position(p.x(), p.y(), 0.)); + clad_phv.addPhysVolID(f_id_fiber, f_id); fi.assigned = true; f_id ++; } @@ -279,7 +279,7 @@ void buildFibers(Detector& desc, SensitiveDetector& sens, Volume& s_vol, int lay // fiber is along y-axis of the layer volume, so grids are arranged on X-Z plane Transform3D gr_tr(RotationZYX(0., 0., M_PI*0.5), Position(gr.mean_centroid.x(), 0., gr.mean_centroid.y())); auto grid_phv = s_vol.placeVolume(grid_vol, gr_tr); - grid_phv.addPhysVolID(f_id_grid, gr.ix + gr.iy * grid_div.first + 1); + grid_phv.addPhysVolID(f_id_grid, gr.ix + gr.iy * grid_n_phi + 1); grid_vol.ptr()->Voxelize(""); } } @@ -297,93 +297,22 @@ void buildFibers(Detector& desc, SensitiveDetector& sens, Volume& s_vol, int lay */ } -// DAWN view seems to have some issue with overlapping solids even if they were unions -// The support is now built without overlapping +// simple aluminum sheet cover +// dimensions: (inner r, position in z, length, phi) void buildSupport(Detector& desc, Volume& mod_vol, xml_comp_t x_support, const std::tuple& dimensions) { - auto [inner_r, l_pos_z, stave_length, hphi] = dimensions; - - double support_thickness = getAttrOrDefault(x_support, _Unicode(thickness), 5. * cm); - double beam_thickness = getAttrOrDefault(x_support, _Unicode(beam_thickness), support_thickness / 4.); - // sanity check - if (beam_thickness > support_thickness / 3.) { - std::cerr << Form("beam_thickness (%.2f) cannot be greater than support_thickness/3 (%.2f), shrink it to fit", - beam_thickness, support_thickness / 3.) - << std::endl; - beam_thickness = support_thickness / 3.; - } - Assembly env_vol("support_envelope"); - double trd_y = stave_length / 2.; - double trd_x1_support = std::tan(hphi) * l_pos_z; - // FIXME trd_x2_support is filled but unused - // double trd_x2_support = std::tan(hphi) * (l_pos_z + support_thickness); - - double grid_size = getAttrOrDefault(x_support, _Unicode(grid_size), 25. * cm); - int n_cross_supports = std::floor(trd_y - beam_thickness) / grid_size; - // number of "beams" running the length of the stave. - // @TODO make it configurable - int n_beams = getAttrOrDefault(x_support, _Unicode(n_beams), 3); - ; - double beam_width = 2. * trd_x1_support / (n_beams + 1); // quick hack to make some gap between T beams - double beam_gap = getAttrOrDefault(x_support, _Unicode(beam_gap), 3. * cm); - - // build T-shape beam - double beam_space_x = beam_width + beam_gap; - [[maybe_unused]] double beam_space_z = support_thickness - beam_thickness; - double cross_thickness = support_thickness - beam_thickness; - double beam_pos_z = beam_thickness / 2.; - [[maybe_unused]] double beam_center_z = support_thickness / 2. - beam_pos_z; - - Box beam_vert_s(beam_thickness / 2., trd_y, cross_thickness / 2.); - Box beam_hori_s(beam_width / 2., trd_y, beam_thickness / 2.); - UnionSolid T_beam_s(beam_hori_s, beam_vert_s, Position(0., 0., support_thickness / 2.)); - Volume H_beam_vol("H_beam", T_beam_s, desc.material(x_support.materialStr())); - H_beam_vol.setVisAttributes(desc, x_support.visStr()); - // place H beams first - double beam_start_x = -(n_beams - 1) * (beam_width + beam_gap) / 2.; - for (int i = 0; i < n_beams; ++i) { - Position beam_pos(beam_start_x + i * (beam_width + beam_gap), 0., -support_thickness / 2. + beam_pos_z); - env_vol.placeVolume(H_beam_vol, beam_pos); - } - - // place central crossing beams that connects the H beams - double cross_x = beam_space_x - beam_thickness; - Box cross_s(cross_x / 2., beam_thickness / 2., cross_thickness / 2.); - Volume cross_vol("cross_center_beam", cross_s, desc.material(x_support.materialStr())); - cross_vol.setVisAttributes(desc, x_support.visStr()); - for (int i = 0; i < n_beams - 1; ++i) { - env_vol.placeVolume(cross_vol, Position(beam_start_x + beam_space_x * (i + 0.5), 0., beam_pos_z)); - for (int j = 1; j < n_cross_supports; j++) { - env_vol.placeVolume(cross_vol, Position(beam_start_x + beam_space_x * (i + 0.5), -j * grid_size, beam_pos_z)); - env_vol.placeVolume(cross_vol, Position(beam_start_x + beam_space_x * (i + 0.5), j * grid_size, beam_pos_z)); - } - } - - // place edge crossing beams that connects the neighbour support - // @TODO: connection part is still using boolean volumes, maybe problematic to DAWN - double cross_edge_x = trd_x1_support + beam_start_x - beam_thickness / 2.; - double cross_trd_x1 = cross_edge_x + std::tan(hphi) * beam_thickness; - double cross_trd_x2 = cross_trd_x1 + 2. * std::tan(hphi) * cross_thickness; - double edge_pos_x = beam_start_x - cross_trd_x1 / 2. - beam_thickness / 2; - Trapezoid cross_s2_trd(cross_trd_x1 / 2., cross_trd_x2 / 2., beam_thickness / 2., beam_thickness / 2., - cross_thickness / 2.); - Box cross_s2_box((cross_trd_x2 - cross_trd_x1) / 4., beam_thickness / 2., cross_thickness / 2.); - SubtractionSolid cross_s2(cross_s2_trd, cross_s2_box, Position((cross_trd_x2 + cross_trd_x1) / 4., 0., 0.)); - Volume cross_vol2("cross_edge_beam", cross_s2, desc.material(x_support.materialStr())); - cross_vol2.setVisAttributes(desc, x_support.visStr()); - env_vol.placeVolume(cross_vol2, Position(edge_pos_x, 0., beam_pos_z)); - env_vol.placeVolume(cross_vol2, Transform3D(Translation3D(-edge_pos_x, 0., beam_pos_z) * RotationZ(M_PI))); - for (int j = 1; j < n_cross_supports; j++) { - env_vol.placeVolume(cross_vol2, Position(edge_pos_x, -j * grid_size, beam_pos_z)); - env_vol.placeVolume(cross_vol2, Position(edge_pos_x, j * grid_size, beam_pos_z)); - env_vol.placeVolume(cross_vol2, - Transform3D(Translation3D(-edge_pos_x, -j * grid_size, beam_pos_z) * RotationZ(M_PI))); - env_vol.placeVolume(cross_vol2, - Transform3D(Translation3D(-edge_pos_x, j * grid_size, beam_pos_z) * RotationZ(M_PI))); - } - - mod_vol.placeVolume(env_vol, Position(0.0, 0.0, l_pos_z + support_thickness / 2.)); + auto [inner_r, pos_z, stave_length, hphi] = dimensions; + double support_thickness = getAttrOrDefault(x_support, _Unicode(thickness), 3.*cm); + auto material = desc.material(x_support.materialStr()); + double trd_y = stave_length / 2.; + double trd_x1_support = std::tan(hphi) * pos_z; + double trd_x2_support = std::tan(hphi) * (pos_z + support_thickness); + + Trapezoid s_shape(trd_x1_support, trd_x2_support, trd_y, trd_y, support_thickness / 2.); + Volume s_vol("support_layer", s_shape, material); + s_vol.setVisAttributes(desc.visAttributes(x_support.visStr())); + mod_vol.placeVolume(s_vol, Position(0.0, 0.0, pos_z + support_thickness / 2.)); } // Fill fiber lattice into trapezoid starting from position (0,0) in x-z coordinate system @@ -422,13 +351,12 @@ vector fiberPositions(double r, double sx, double sz, double trx, double return positions; } -// Calculate number of divisions for the readout grid for the fiber layers -std::pair getNdivisions(double x, double z, double dx, double dz) +// Determine the number of divisions for the readout grid for the fiber layers +// Calculate dimensions of the polygonal grid +vector gridPoints(int div_n_phi, double div_dr, double trd_x1, double height, double phi) { - // x and z defined as in vector fiberPositions - // dx, dz - size of the grid in x and z we want to get close to with the polygons - // See also descripltion when the function is called - + /* + // TODO: move this test to xml file double SiPMsize = 13.0 * mm; double grid_min = SiPMsize + 3.0 * mm; @@ -439,56 +367,44 @@ std::pair getNdivisions(double x, double z, double dx, double dz) if (dx < grid_min) { dx = grid_min; } + */ + // number of divisions + int nph = div_n_phi; + int nr = floor(height / div_dr); + if (nr == 0) { + nr++; + } - int nfit_cells_z = floor(z / dz); - int n_cells_z = nfit_cells_z; - - if (nfit_cells_z == 0) - n_cells_z++; - - int nfit_cells_x = floor((2 * x) / dx); - int n_cells_x = nfit_cells_x; - - if (nfit_cells_x == 0) - n_cells_x++; - - return std::make_pair(n_cells_x, n_cells_z); -} - -// Calculate dimensions of the polygonal grid in the cartesian coordinate system x-z -vector gridPoints(int div_x, int div_z, double x, double z, double phi) -{ - // x, z and phi defined as in vector fiberPositions - // div_x, div_z - number of divisions in x and z + // grid vertices vector results; - double dz = z / div_z; + double dr = height / nr; - for (int iz = 0; iz < div_z + 1; iz++) { - for (int ix = 0; ix < div_x + 1; ix++) { - double A_z = -z / 2 + iz * dz; - double B_z = -z / 2 + (iz + 1) * dz; + for (int ir = 0; ir <= nr; ir++) { + for (int iph = 0; iph <= nph; iph++) { + double A_y = -height / 2. + ir * dr; + double B_y = -height / 2. + (ir + 1) * dr; - double len_x_for_z = 2 * (x + iz * dz * tan(phi)); - double len_x_for_z_plus_1 = 2 * (x + (iz + 1) * dz * tan(phi)); + double botl_dr = 2 * (trd_x1 + ir * dr * tan(phi)); + double topl_dr = 2 * (trd_x1 + (ir + 1) * dr * tan(phi)); - double dx_for_z = len_x_for_z / div_x; - double dx_for_z_plus_1 = len_x_for_z_plus_1 / div_x; + double botl_dph_dr = botl_dr / nph; + double topl_dph_dr = topl_dr / nph; - double A_x = -len_x_for_z / 2. + ix * dx_for_z; - double B_x = -len_x_for_z_plus_1 / 2. + ix * dx_for_z_plus_1; + double A_x = -botl_dr / 2. + iph * botl_dph_dr; + double B_x = -topl_dr / 2. + iph * topl_dph_dr; - double C_z = B_z; - double D_z = A_z; - double C_x = B_x + dx_for_z_plus_1; - double D_x = A_x + dx_for_z; + double C_y = B_y; + double D_y = A_y; + double C_x = B_x + topl_dph_dr; + double D_x = A_x + botl_dph_dr; - auto A = Point(A_x, A_z); - auto B = Point(B_x, B_z); - auto C = Point(C_x, C_z); - auto D = Point(D_x, D_z); + auto A = Point(A_x, A_y); + auto B = Point(B_x, B_y); + auto C = Point(C_x, C_y); + auto D = Point(D_x, D_y); // vertex points filled in the clock-wise direction - results.emplace_back(FiberGrid(ix, iz, {A, B, C, D})); + results.emplace_back(FiberGrid(iph, ir, {A, B, C, D})); } } diff --git a/src/DIRC_geo.cpp b/src/DIRC_geo.cpp index f42c0054cc..29db0c2adf 100644 --- a/src/DIRC_geo.cpp +++ b/src/DIRC_geo.cpp @@ -64,21 +64,11 @@ static Ref_t createDetector(Detector& desc, xml_h e, SensitiveDetector sens) Volume glue_vol("glue_vol", glue_box, desc.material(xml_glue.materialStr())); glue_vol.setVisAttributes(desc.visAttributes(xml_glue.visStr())); - // Place bars + glue into module assembly - // FIXME place bars + glue into separate box volume auto bar_repeat_y = xml_bar.attr(_Unicode(repeat_y)); auto bar_repeat_z = xml_bar.attr(_Unicode(repeat_z)); auto bar_gap = xml_bar.gap(); auto bar_assm_width = (bar_width + bar_gap) * bar_repeat_y - bar_gap; auto bar_assm_length = (bar_length + glue_thickness) * bar_repeat_z; - for (int y_index = 0; y_index < bar_repeat_y; y_index++) { - double y = 0.5 * bar_assm_width - 0.5 * bar_width - (bar_width + bar_gap) * y_index; - for (int z_index = 0; z_index < bar_repeat_z; z_index++) { - double z = 0.5 * bar_assm_length - 0.5 * bar_length - (bar_length + glue_thickness) * z_index; - dirc_module.placeVolume(glue_vol, Position(0, y, z - 0.5 * (bar_length + glue_thickness))); - dirc_module.placeVolume(bar_vol, Position(0, y, z)).addPhysVolID("section", z_index).addPhysVolID("bar", y_index); - } - } // Mirror construction xml_comp_t xml_mirror = xml_module.child(_Unicode(mirror)); @@ -91,12 +81,26 @@ static Ref_t createDetector(Detector& desc, xml_h e, SensitiveDetector sens) // Mirror optical surface auto surfMgr = desc.surfaceManager(); - auto surf = surfMgr.opticalSurface("MirrorOpticalSurface"); + auto surf = surfMgr.opticalSurface("DIRC_MirrorOpticalSurface"); SkinSurface skin(desc, det, Form("dirc_mirror_optical_surface"), surf, mirror_vol); skin.isValid(); + // Envelope for bars + mirror + Box Envelope_box("Envelope_box", (mirror_height + 1*mm)/2, 5*(bar_width + 0.15*mm), 2*(bar_length + glue_thickness) + 0.5*mirror_thickness); + Volume Envelope_box_vol("Envelope_box_vol", Envelope_box, desc.material("AirOptical")); + dirc_module.placeVolume(Envelope_box_vol, Position(0, 0, 0.5*mirror_thickness)); + + for (int y_index = 0; y_index < bar_repeat_y; y_index++) { + double y = 0.5 * bar_assm_width - 0.5 * bar_width - (bar_width + bar_gap) * y_index; + for (int z_index = 0; z_index < bar_repeat_z; z_index++) { + double z = 0.5 * bar_assm_length - 0.5 * mirror_thickness - 0.5 * bar_length - (bar_length + glue_thickness) * z_index; + Envelope_box_vol.placeVolume(glue_vol, Position(0, y, z - 0.5 * (bar_length + glue_thickness))); + Envelope_box_vol.placeVolume(bar_vol, Position(0, y, z)).addPhysVolID("section", z_index).addPhysVolID("bar", y_index); + } + } + // Place mirror - dirc_module.placeVolume(mirror_vol, Position(0, 0, 0.5 * (bar_assm_length + mirror_thickness))); + Envelope_box_vol.placeVolume(mirror_vol, Position(0, 0, 0.5 * bar_assm_length)); // Prism variables xml_comp_t xml_prism = xml_module.child(_Unicode(prism)); @@ -108,46 +112,39 @@ static Ref_t createDetector(Detector& desc, xml_h e, SensitiveDetector sens) // Lens variables xml_comp_t xml_lens = xml_module.child(_Unicode(lens)); - double lens_height = getAttrOrDefault(xml_lens, _Unicode(height), 50 * mm); double lens_shift = getAttrOrDefault(xml_lens, _Unicode(shift), 0 * mm); - // double lens_width = getAttrOrDefault(xml_lens, _Unicode(width), 25 * mm); + double lens_width = getAttrOrDefault(xml_lens, _Unicode(width), 35 * mm); double lens_thickness = getAttrOrDefault(xml_lens, _Unicode(thickness), 12 * mm); double lens_r1 = getAttrOrDefault(xml_lens, _Unicode(r1), 62 * mm); double lens_r2 = getAttrOrDefault(xml_lens, _Unicode(r2), 36 * mm); // Lens construction - // FIXME avoid negative impact of booleans by putting lens inside box + // 3-layer spherical lens --- - // lens_min_thickness is distance from face to r1, and from r1 to r2 at lens top edge - double lens_min_thickness = 0.5 * mm; - double layer01 = 1.0 * lens_min_thickness; - double layer12 = 2.0 * lens_min_thickness; + double lens_radius = sqrt(lens_width * lens_width / 4. + bar_height * bar_height / 4.); - // ztrans1 and ztrans2 are the z shifts of the lens center for r1 and r2 - double ztrans1 = lens_thickness / 2. + sqrt(lens_r1 * lens_r1 - lens_height / 2. * lens_height / 2.) - layer01; - double ztrans2 = lens_thickness / 2. + sqrt(lens_r2 * lens_r2 - lens_height / 2. * lens_height / 2.) - layer12; + double lens_min_thickness = 2.0 * mm; - Box gfbox("fbox", 0.5 * prism_short_edge, 0.5 * prism_width, 0.5 * lens_thickness); - Box gcbox("cbox", 0.5 * prism_short_edge, 0.5 * prism_width + 1 * mm, 0.5 * lens_thickness); + double ztrans1 = -lens_thickness / 2. - sqrt(lens_r1 * lens_r1 - lens_radius * lens_radius) + lens_min_thickness; + double ztrans2 = -lens_thickness / 2. - sqrt(lens_r2 * lens_r2 - lens_radius * lens_radius) + lens_min_thickness * 2; - Position tTrans1(0.5 * (prism_short_edge + lens_height), 0, lens_thickness - layer12); - Position tTrans0(-0.5 * (prism_short_edge + lens_height), 0, lens_thickness - layer12); - SubtractionSolid tubox("tubox", gfbox, gcbox, tTrans1); - SubtractionSolid gubox("gubox", tubox, gcbox, tTrans0); + Box lens_symm_box("lens_symm_box", 0.5 * prism_short_edge, 0.5 * lens_width, 0.5 * lens_thickness); + Volume Envelope_lens_vol("Envelope_lens_vol", lens_symm_box, desc.material("AirOptical")); - Tube gcylinder1("Cylinder1", 0, lens_r1, 0.5 * prism_width, 0 * deg, 360 * deg); - Tube gcylinder2("Cylinder2", 0, lens_r2, 0.5 * prism_width - 0.5 * mm, 0 * deg, 360 * deg); - Tube gcylinder1c("Cylinder1c", 0, lens_r1, 0.5 * prism_width + 0.5 * mm, 0 * deg, 360 * deg); - Tube gcylinder2c("Cylinder2c", 0, lens_r2, 0.5 * prism_width + 0.5 * mm, 0 * deg, 360 * deg); + Tube lens_symm_tube(0, lens_radius, 0.5 * lens_thickness); - IntersectionSolid lens_layer1_solid("lens_layer1_solid", gubox, gcylinder1, - Transform3D(RotationX(M_PI / 2.), Position(0, 0, ztrans1))); - SubtractionSolid gLenst("temp", gubox, gcylinder1c, Transform3D(RotationX(M_PI / 2.), Position(0, 0, ztrans1))); + Sphere lens_sphere1(0, lens_r1); + Sphere lens_sphere2(0, lens_r2); - IntersectionSolid lens_layer2_solid("lens_layer2_solid", gLenst, gcylinder2, - Transform3D(RotationX(M_PI / 2.), Position(0, 0, ztrans2))); - SubtractionSolid lens_layer3_solid("lens_layer3_solid", gLenst, gcylinder2c, - Transform3D(RotationX(M_PI / 2.), Position(0, 0, ztrans2))); + IntersectionSolid lens_box("lens_box", lens_symm_box, lens_symm_box, Position(0, 0, -lens_min_thickness * 2)); + IntersectionSolid lens_tube("lens_tube", lens_symm_tube, lens_symm_box, Position(0, 0, lens_min_thickness * 2)); + UnionSolid lens_box_tube("lens_box_tube", lens_box, lens_tube); + + IntersectionSolid lens_layer1_solid("lens_layer1_solid", lens_box_tube, lens_sphere1, Position(0, 0, -ztrans1)); + SubtractionSolid lens_layer23_solid("lens_layer23_solid", lens_box_tube, lens_sphere1, Position(0, 0, -ztrans1)); + + IntersectionSolid lens_layer2_solid("lens_layer2_solid", lens_layer23_solid, lens_sphere2, Position(0, 0, -ztrans2)); + SubtractionSolid lens_layer3_solid("lens_layer3_solid", lens_layer23_solid, lens_sphere2, Position(0, 0, -ztrans2)); Volume lens_layer1_vol("lens_layer1_vol", lens_layer1_solid, desc.material(xml_lens.attr(_Unicode(material1)))); @@ -162,10 +159,18 @@ static Ref_t createDetector(Detector& desc, xml_h e, SensitiveDetector sens) double lens_position_x = lens_shift; double lens_position_z = -0.5 * (bar_assm_length + lens_thickness); - Position lens_position(lens_position_x, 0, lens_position_z); - dirc_module.placeVolume(lens_layer1_vol, lens_position); - dirc_module.placeVolume(lens_layer2_vol, lens_position); - dirc_module.placeVolume(lens_layer3_vol, lens_position); + + for(int y_index = 0; y_index < bar_repeat_y; y_index++) + { + double lens_position_y = y_index*lens_width - 0.5*(prism_width - lens_width); + + Position lens_position(lens_position_x, lens_position_y, lens_position_z); + dirc_module.placeVolume(Envelope_lens_vol, lens_position); + } + + Envelope_lens_vol.placeVolume(lens_layer1_vol); + Envelope_lens_vol.placeVolume(lens_layer2_vol); + Envelope_lens_vol.placeVolume(lens_layer3_vol); // Prism construction Trap prism_trap = MakeTrap("prism_trap", prism_width, prism_length, prism_long_edge, prism_short_edge); @@ -176,7 +181,21 @@ static Ref_t createDetector(Detector& desc, xml_h e, SensitiveDetector sens) double prism_position_z = -0.5 * (bar_assm_length + prism_length) - lens_thickness; RotationX prism_rotation(M_PI / 2.); Position prism_position(prism_position_x, 0, prism_position_z); - dirc_module.placeVolume(prism_vol, Transform3D(prism_rotation, prism_position)); + + // Envelope for prism + mcp + + double Envelope_trap_width = prism_width + 1*mm; + double Envelope_trap_length = prism_length + 1*mm; // mcp thickness is 1 mm + double Envelope_trap_short_edge = prism_short_edge + 1*mm; + double Envelope_trap_long_edge = Envelope_trap_short_edge + Envelope_trap_length * tan(prism_angle); + + Trap Envelope_trap = MakeTrap("Envelope_trap", Envelope_trap_width, Envelope_trap_length, Envelope_trap_long_edge, Envelope_trap_short_edge); + Position Envelope_trap_position(prism_position_x, 0, prism_position_z - 0.5*mm); + + Volume Envelope_trap_vol("Envelope_trap_vol", Envelope_trap, desc.material("AirOptical")); + dirc_module.placeVolume(Envelope_trap_vol, Transform3D(prism_rotation, Envelope_trap_position)); + + Envelope_trap_vol.placeVolume(prism_vol, Position(0, 0.5*mm, 0)); // MCP variables xml_comp_t xml_mcp = xml_module.child(_Unicode(mcp)); @@ -189,10 +208,11 @@ static Ref_t createDetector(Detector& desc, xml_h e, SensitiveDetector sens) Volume mcp_vol("mcp_vol", mcp_box, desc.material(xml_mcp.materialStr())); mcp_vol.setVisAttributes(desc.visAttributes(xml_mcp.visStr())).setSensitiveDetector(sens); - double mcp_position_x = 0.5 * prism_long_edge - 0.5 * prism_short_edge + lens_shift; - double mcp_position_z = -0.5 * bar_assm_length - lens_thickness - prism_length - 0.5 * mcp_thickness; - Position mcp_position(mcp_position_x, 0, mcp_position_z); - dirc_module.placeVolume(mcp_vol, mcp_position); + double mcp_position_z = -0.5 * prism_length; + Position mcp_position(prism_position_x, mcp_position_z, 0); + RotationX mcp_rotation(-M_PI / 2.); + + Envelope_trap_vol.placeVolume(mcp_vol, Transform3D(mcp_rotation, mcp_position)); // Place modules const int module_repeat = xml_module.repeat(); diff --git a/templates/epic.xml.jinja2 b/templates/epic.xml.jinja2 index ffbf78a482..742196c5f4 100644 --- a/templates/epic.xml.jinja2 +++ b/templates/epic.xml.jinja2 @@ -59,7 +59,9 @@ - + + + @@ -71,6 +73,12 @@ + + + + + + @@ -83,6 +91,8 @@ + +