예제 #1
0
static DD4hep::Geometry::Ref_t createTkLayoutTrackerEndcap(DD4hep::Geometry::LCDD& lcdd,
        DD4hep::XML::Handle_t xmlElement,
        DD4hep::Geometry::SensitiveDetector sensDet) {
    // shorthands
    DD4hep::XML::DetElement xmlDet = static_cast<DD4hep::XML::DetElement>(xmlElement);
    Dimension dimensions(xmlDet.dimensions());

    // get sensitive detector type from xml
    DD4hep::XML::Dimension sdTyp = xmlElement.child("sensitive");  // retrieve the type
    sensDet.setType(sdTyp.typeStr());  // set for the whole detector

    // definition of top volume
    std::string detName = xmlDet.nameStr();
    DetElement GenericTrackerEndcapWorld(detName, xmlDet.id());

    // envelope volume with the max dimensions of tracker for visualization etc.
    // contains both endcaps, in forward and in backwards direction
    // the part between -z1 and z1 is subtracted from the envelope
    DD4hep::Geometry::Tube posnegEnvelopeShape_add(dimensions.rmin(), dimensions.rmax(), dimensions.zmax());
    // make the negative shape slighly larger in the radial direction
    // to be sure that everything is subtracted between -z1 and z1
    DD4hep::Geometry::Box posnegEnvelopeShape_subtract(
        dimensions.rmax() * 1.001, dimensions.rmax() * 1.001, dimensions.zmin());
    DD4hep::Geometry::SubtractionSolid posnegEnvelopeShape(posnegEnvelopeShape_add, posnegEnvelopeShape_subtract);
    Volume posnegEnvelopeVolume(detName, posnegEnvelopeShape, lcdd.air());
    posnegEnvelopeVolume.setVisAttributes(lcdd.invisible());

    // envelope volume for one of the endcaps, either forward or backward
    DD4hep::Geometry::Tube envelopeShape(
        dimensions.rmin(), dimensions.rmax(), 0.5 * (dimensions.zmax() - dimensions.zmin()));
    Volume envelopeVolume(detName, envelopeShape, lcdd.air());
    envelopeVolume.setVisAttributes(lcdd.invisible());

    Component xDiscs = xmlElement.child("discs");
    Component xFirstDisc = xDiscs.child("discZPls");
    Component xFirstDiscRings = xFirstDisc.child("rings");

    // create disc volume
    double discThickness = (xFirstDisc.zmax() - xFirstDisc.zmin());
    DD4hep::Geometry::Tube discShape(dimensions.rmin(), dimensions.rmax(), 0.5 * discThickness);
    Volume discVolume("disc", discShape, lcdd.air());
    discVolume.setVisAttributes(lcdd.invisible());

    // generate rings and place in  discs
    int moduleCounter = 0;
    for (DD4hep::XML::Collection_t xRingColl(xFirstDiscRings, _U(ring)); nullptr != xRingColl; ++xRingColl) {
        Component xRing = static_cast<Component>(xRingColl);
        Component xRingModules = xRing.child("modules");
        Component xModuleOdd = xRingModules.child("moduleOdd");
        Component xModuleEven = xRingModules.child("moduleEven");
        Component xModuleProperties = xRing.child("moduleProperties");
        Component xModulePropertiesComp = xModuleProperties.child("components");
        Component xSensorProperties = xRing.child("sensorProperties");
        Volume moduleVolume("module",
                            DD4hep::Geometry::Trapezoid(0.5 * xModuleProperties.attr<double>("modWidthMin"),
                                    0.5 * xModuleProperties.attr<double>("modWidthMax"),
                                    0.5 * xModuleProperties.attr<double>("modThickness"),
                                    0.5 * xModuleProperties.attr<double>("modThickness"),
                                    0.5 * xSensorProperties.attr<double>("sensorLength")),
                            lcdd.material("Air"));

        // place components in module
        double integratedCompThickness = 0;
        int componentCounter = 0;
        for (DD4hep::XML::Collection_t xCompColl(xModulePropertiesComp, _U(component)); nullptr != xCompColl; ++xCompColl) {
            Component xComp = static_cast<Component>(xCompColl);
            Volume componentVolume("component",
                                   DD4hep::Geometry::Trapezoid(0.5 * xModuleProperties.attr<double>("modWidthMin"),
                                           0.5 * xModuleProperties.attr<double>("modWidthMax"),
                                           0.5 * xComp.thickness(),
                                           0.5 * xComp.thickness(),
                                           0.5 * xSensorProperties.attr<double>("sensorLength")),
                                   lcdd.material(xComp.materialStr()));
            PlacedVolume placedComponentVolume = moduleVolume.placeVolume(
                    componentVolume,
                    DD4hep::Geometry::Position(
                        0, integratedCompThickness - 0.5 * xModuleProperties.attr<double>("modThickness"), 0));
            placedComponentVolume.addPhysVolID("component", componentCounter);

            componentVolume.setSensitiveDetector(sensDet);
            integratedCompThickness += xComp.thickness();
            ++componentCounter;
        }
        unsigned int nPhi = xRing.attr<int>("nModules");
        double lX, lY, lZ;
        double phi = 0;
        double phiTilt, thetaTilt;
        for (unsigned int phiIndex = 0; phiIndex < nPhi; ++phiIndex) {
            if (0 == phiIndex % 2) {
                // the rotation for the odd module is already taken care
                // of by the position in tklayout xml
                phi = 2 * dd4hep::pi * static_cast<double>(phiIndex) / static_cast<double>(nPhi);
                lX = xModuleEven.X();
                lY = xModuleEven.Y();
                lZ = xModuleEven.Z() - dimensions.zmin() - discThickness * 0.5;
                phiTilt = xModuleEven.attr<double>("phiTilt");
                thetaTilt = xModuleEven.attr<double>("thetaTilt");
            } else {
                lX = xModuleOdd.X();
                lY = xModuleOdd.Y();
                lZ = xModuleOdd.Z() - dimensions.zmin() - discThickness * 0.5;
                phiTilt = xModuleOdd.attr<double>("phiTilt");
                thetaTilt = xModuleOdd.attr<double>("thetaTilt");
            }
            // position module in the x-y plane, smaller end inward
            // and incorporate phi tilt if any
            DD4hep::Geometry::RotationY lRotation1(M_PI * 0.5);
            DD4hep::Geometry::RotationX lRotation2(M_PI * 0.5 + phiTilt);
            // align radially
            DD4hep::Geometry::RotationZ lRotation3(atan(lY / lX));
            // theta tilt, if any -- note the different convention between
            // tklayout and here, thus the subtraction of pi / 2
            DD4hep::Geometry::RotationY lRotation4(thetaTilt - M_PI * 0.5);
            DD4hep::Geometry::RotationZ lRotation_PhiPos(phi);
            // position in  disk
            DD4hep::Geometry::Translation3D lTranslation(lX, lY, lZ);
            DD4hep::Geometry::Transform3D myTrafo(lRotation4 * lRotation3 * lRotation2 * lRotation1, lTranslation);
            PlacedVolume placedModuleVolume = discVolume.placeVolume(moduleVolume, lRotation_PhiPos * myTrafo);
            placedModuleVolume.addPhysVolID("module", moduleCounter);
            ++moduleCounter;
        }
    }

    unsigned int discCounter = 0;
    double currentZ;
    for (DD4hep::XML::Collection_t xDiscColl(xDiscs, "discZPls"); nullptr != xDiscColl; ++xDiscColl) {
        Component xDisc = static_cast<Component>(xDiscColl);
        currentZ = xDisc.z() - dimensions.zmin() - 0.5 * (dimensions.zmax() - dimensions.zmin());
        PlacedVolume placedDiscVolume = envelopeVolume.placeVolume(discVolume, DD4hep::Geometry::Position(0, 0, currentZ));
        placedDiscVolume.addPhysVolID("disc", discCounter);
        ++discCounter;
    }

    // top of the hierarchy
    Volume motherVol = lcdd.pickMotherVolume(GenericTrackerEndcapWorld);
    PlacedVolume placedEnvelopeVolume = motherVol.placeVolume(posnegEnvelopeVolume);
    placedEnvelopeVolume.addPhysVolID("system", xmlDet.id());

    // place everything twice -- forward / backward
    DD4hep::Geometry::Translation3D lTranslation_posEnvelope(
        0, 0, -dimensions.zmin() - 0.5 * (dimensions.zmax() - dimensions.zmin()));
    PlacedVolume placedGenericTrackerEndcap_pos = posnegEnvelopeVolume.placeVolume(
                envelopeVolume,
                DD4hep::Geometry::Position(0, 0, dimensions.zmin() + 0.5 * (dimensions.zmax() - dimensions.zmin())));
    PlacedVolume placedGenericTrackerEndcap_neg = posnegEnvelopeVolume.placeVolume(
                envelopeVolume, lTranslation_posEnvelope * DD4hep::Geometry::RotationX(dd4hep::pi));
    placedGenericTrackerEndcap_pos.addPhysVolID("posneg", 0);
    placedGenericTrackerEndcap_neg.addPhysVolID("posneg", 1);
    GenericTrackerEndcapWorld.setPlacement(placedEnvelopeVolume);
    return GenericTrackerEndcapWorld;
}
예제 #2
0
static DD4hep::Geometry::Ref_t createGenericTrackerBarrel(DD4hep::Geometry::LCDD& lcdd,
                                                          DD4hep::XML::Handle_t xmlElement,
                                                          DD4hep::Geometry::SensitiveDetector sensDet) {
  // shorthands
  DD4hep::XML::DetElement xmlDet = static_cast<DD4hep::XML::DetElement>(xmlElement);
  Dimension dimensions(xmlDet.dimensions());
  // get sensitive detector type from xml
  DD4hep::XML::Dimension sdTyp = xmlElement.child("sensitive");
  if (xmlDet.isSensitive()) {
    // sensitive detector used for all sensitive parts of this detector
    sensDet.setType(sdTyp.typeStr());
  }
  // definition of top volume
  // has min/max dimensions of tracker for visualization etc.
  std::string detectorName = xmlDet.nameStr();
  DetElement topDetElement(detectorName, xmlDet.id());
  DD4hep::Geometry::Tube topVolumeShape(dimensions.rmin(), dimensions.rmax(), dimensions.dz());
  Volume topVolume(detectorName, topVolumeShape, lcdd.air());
  topVolume.setVisAttributes(lcdd.invisible());

  // counts all layers - incremented in the inner loop over repeat - tags
  unsigned int layerCounter = 0;
  // loop over 'layer' nodes in xml
  for (DD4hep::XML::Collection_t xLayerColl(xmlElement, _U(layers)); nullptr != xLayerColl; ++xLayerColl) {
    DD4hep::XML::Component xLayer = static_cast<DD4hep::XML::Component>(xLayerColl);

    DD4hep::XML::Component xModuleComponents = xmlElement.child("module_components");
    DD4hep::XML::Component xModule =
        utils::getNodeByStrAttr(xmlElement, "module", "name", xLayer.attr<std::string>("module"));

    // optional parameters
    double stereo_offset = utils::getAttrValueWithFallback(xLayer, "stereo_offset", 0.0);
    double module_twist_angle = utils::getAttrValueWithFallback(xLayer, "module_twist_angle", 0.1 * M_PI);
    double stereo_module_overlap = utils::getAttrValueWithFallback(xLayer, "stereo_module_overlap", 0.0);

    // get total thickness of module
    unsigned int idxSubMod = 0;
    double totalModuleComponentThickness = 0;
    for (DD4hep::XML::Collection_t xCompColl(xModuleComponents, _U(module_component)); nullptr != xCompColl;
         ++xCompColl, ++idxSubMod) {
      DD4hep::XML::Component xComp = static_cast<DD4hep::XML::Component>(xCompColl);
      totalModuleComponentThickness += xComp.thickness();
    }
    // now that thickness is known: define module components volumes
    idxSubMod = 0;
    double integratedModuleComponentThickness = 0;
    std::vector<Volume> moduleComponentVector;
    for (DD4hep::XML::Collection_t xCompColl(xModuleComponents, _U(module_component)); nullptr != xCompColl;
         ++xCompColl, ++idxSubMod) {
      DD4hep::XML::Component xComp = static_cast<DD4hep::XML::Component>(xCompColl);
      std::string moduleComponentName = "layer" + std::to_string(layerCounter) + "_rod_module_component" +
          std::to_string(idxSubMod) + "_" + xComp.materialStr();
      Volume moduleComponentVolume(moduleComponentName,
                                   DD4hep::Geometry::Box(xModule.width(), xComp.thickness(), xModule.length()),
                                   lcdd.material(xComp.materialStr()));
      moduleComponentVolume.setVisAttributes(lcdd, xComp.visStr());
      if (xComp.isSensitive()) {
        moduleComponentVolume.setSensitiveDetector(sensDet);
      }
      moduleComponentVector.push_back(moduleComponentVolume);
    }

    // definition of module volume (smallest independent subdetector)
    // define the module whose name was given in the "layer" xml Element
    Volume moduleVolume("module", DD4hep::Geometry::Box(xModule.width(), xModule.thickness(), xModule.length()),
                        lcdd.material("Air"));
    moduleVolume.setVisAttributes(lcdd, xModule.visStr());

    // definition of rod volume (longitudinal arrangement of modules)
    Volume rodVolume("GenericTrackerBarrel_layer" + std::to_string(layerCounter) + "_rod",
                     DD4hep::Geometry::Box(xModule.width(), xModule.thickness(), xLayer.dz()),
                     lcdd.material("Air"));
    rodVolume.setVisAttributes(lcdd.invisible());

    /// @todo: allow for more than one type of module components
    // analogous to module
    // place module substructure in module
    std::string moduleComponentName = "moduleComponent";
    idxSubMod = 0;
    for (DD4hep::XML::Collection_t xCompColl(xModuleComponents, _U(module_component)); nullptr != xCompColl;
         ++xCompColl, ++idxSubMod) {
      DD4hep::XML::Component xComp = static_cast<DD4hep::XML::Component>(xCompColl);
      DD4hep::Geometry::Position offset(0, -0.5 * totalModuleComponentThickness + integratedModuleComponentThickness,
                                        0);
      integratedModuleComponentThickness += xComp.thickness();
      PlacedVolume placedModuleComponentVolume = moduleVolume.placeVolume(moduleComponentVector[idxSubMod], offset);
      placedModuleComponentVolume.addPhysVolID("module_component", idxSubMod);
    }

    // handle repeat attribute in xml
    // "repeat" layers  equidistant between rmin and rmax
    double numRepeat = xLayer.repeat();
    double layerThickness = (xLayer.rmax() - xLayer.rmin()) / numRepeat;
    double layer_rmin = xLayer.rmin();
    unsigned int nPhi = 0;
    double r = 0;
    double phi = 0;
    // loop over repeated layers defined by one layer tag
    for (unsigned int repeatIndex = 0; repeatIndex < numRepeat; ++repeatIndex) {
      ++layerCounter;
      // let r be the middle between two equidistant layer boundaries
      r = layer_rmin + (0.5 + repeatIndex) * layerThickness;
      // definition of layer volumes
      DD4hep::Geometry::Tube layerShape(r - 0.5*layerThickness, r + 0.5*layerThickness, xLayer.dz());
      std::string layerName = "layer" + std::to_string(layerCounter);
      Volume layerVolume(layerName, layerShape, lcdd.material("Silicon"));
      layerVolume.setVisAttributes(lcdd.invisible());
      PlacedVolume placedLayerVolume = topVolume.placeVolume(layerVolume);
      placedLayerVolume.addPhysVolID("layer", layerCounter);
      // approximation of tklayout values
      double phiOverlapFactor = utils::getAttrValueWithFallback(xLayer, "phi_overlap_factor", 1.15);
      nPhi = static_cast<unsigned int>( phiOverlapFactor * 2 * M_PI * r / (2 * xModule.width()));
      for (unsigned int phiIndex = 0; phiIndex < nPhi; ++phiIndex) {
        phi = 2 * M_PI * static_cast<double>(phiIndex) / static_cast<double>(nPhi);
        DD4hep::Geometry::Translation3D lTranslation(r * cos(phi), r * sin(phi), 0);
        DD4hep::Geometry::RotationZ lRotation(phi + module_twist_angle + 0.5 * M_PI);
        PlacedVolume placedRodVolume = layerVolume.placeVolume(rodVolume, lTranslation * lRotation);
        placedRodVolume.addPhysVolID("rod", phiIndex);
      }
    }
    // placement of modules within rods
    unsigned int zRepeat = static_cast<int>(xLayer.dz() / (xModule.length() - stereo_module_overlap));
    // stereo overlap
    for (unsigned int zIndex = 0; zIndex < zRepeat; ++zIndex) {
      stereo_offset *= -1.;
      DD4hep::Geometry::Position moduleOffset(0, stereo_offset,
                                              zIndex * 2 * (xModule.length() - stereo_module_overlap) - xLayer.dz() +
                                                  xModule.length() - stereo_module_overlap);
      PlacedVolume placedModuleVolume = rodVolume.placeVolume(moduleVolume, moduleOffset);
      placedModuleVolume.addPhysVolID("module", zIndex);
    }
  }
  Volume motherVol = lcdd.pickMotherVolume(topDetElement);
  PlacedVolume placedGenericTrackerBarrel = motherVol.placeVolume(topVolume);
  placedGenericTrackerBarrel.addPhysVolID("system", topDetElement.id());
  topDetElement.setPlacement(placedGenericTrackerBarrel);
  return topDetElement;
}