static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens)   {
  xml_det_t  x_det     = e;
  xml_dim_t  dim       = x_det.dimensions();
  Material   air       = description.air();
  string     det_name  = x_det.nameStr();
  DetElement sdet       (det_name,x_det.id());
  double     z         = dim.outer_z();
  double     rmin      = dim.inner_r();
  double     r         = rmin;
  int        n         = 0;
  Tube       envelope(rmin,2*rmin,2*z);
  Volume     envelopeVol(det_name+"_envelope",envelope,air);
    
  for(xml_coll_t c(x_det,_U(layer)); c; ++c)  {
    xml_comp_t x_layer = c;
    for(int i=0, im=0, repeat=x_layer.repeat(); i<repeat; ++i, im=0)  {
      string layer_name = det_name + _toString(n,"_layer%d");
      double rlayer = r;
      Tube   layer_tub(rmin,rlayer,2*z);
      Volume layer_vol(layer_name,layer_tub,air);
        
      for(xml_coll_t l(x_layer,_U(slice)); l; ++l, ++im)  {
        xml_comp_t x_slice = l;
        double     router = r + x_slice.thickness();
        Material   slice_mat  = description.material(x_slice.materialStr());
        string     slice_name = layer_name + _toString(im,"slice%d");
        Tube       slice_tube(r,router,z*2);
        Volume     slice_vol (slice_name,slice_tube,slice_mat);
          
        if ( x_slice.isSensitive() ) {
          sens.setType("calorimeter");
          slice_vol.setSensitiveDetector(sens);
        }
        r = router;
        slice_vol.setAttributes(description,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
        // Instantiate physical volume
        layer_vol.placeVolume(slice_vol);
      }
      layer_vol.setVisAttributes(description,x_layer.visStr());
      layer_tub.setDimensions(rlayer,r,z*2,0,2*M_PI);
        
      PlacedVolume layer_physvol = envelopeVol.placeVolume(layer_vol);
      layer_physvol.addPhysVolID("layer",n);
      ++n;
    }
  }
  envelope.setDimensions(rmin,r,2*z);
  // Set region of slice
  envelopeVol.setAttributes(description,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
    
  PlacedVolume physvol = description.pickMotherVolume(sdet).placeVolume(envelopeVol);
  physvol.addPhysVolID("system",sdet.id()).addPhysVolID(_U(barrel),0);
  sdet.setPlacement(physvol);
  return sdet;
}
static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens)  {
  xml_det_t   x_det     = e;
  Layering    layering(x_det);
  //xml_comp_t  staves      = x_det.staves();
  xml_dim_t   dim         = x_det.dimensions();
  string      det_name    = x_det.nameStr();
  Material    air         = description.air();
  double      totalThickness = layering.totalThickness();
  int         numSides    = dim.numsides();
  double      detZ        = dim.z();
  double      rmin        = dim.rmin();
  double      rmax        = dim.rmax();
  DetElement  sdet(det_name,x_det.id());
  DetElement  stave("stave1",x_det.id());
  Volume      motherVol = description.pickMotherVolume(sdet);
  PolyhedraRegular polyhedron(numSides,0.,rmin,detZ+10);
  Tube tube(0.,rmin+totalThickness,detZ/2,0,2*M_PI);
  SubtractionSolid sub(tube,polyhedron);  
  Volume           envelopeVol(det_name+"_envelope",sub,air);

  // Add the subdetector envelope to the structure.
  double externalAngle     = 2*M_PI/numSides;
  double halfExternalAngle = externalAngle/2;
  double tan_external      = std::tan(externalAngle);
  double tan_half      = std::tan(halfExternalAngle);
  
  double half_polyFace = rmin * tan_half;
  
  double innerFaceLen   = std::sqrt(rmax*rmax - rmin*rmin)+half_polyFace;
  //double outerFaceLen   = (rmin+totalThickness) * tan_external;
  double staveThickness = totalThickness;

//   Trapezoid staveTrdOuter(innerFaceLen/2,outerFaceLen/2,detZ/2,detZ/2,staveThickness/2);
//   Volume    staveOuterVol(det_name+"_stave",staveTrdOuter,air);
  Assembly    staveOuterVol(det_name+"_stave");
  
//   Trapezoid staveTrdInner(innerFaceLen/2-gap,outerFaceLen/2-gap,detZ/2,detZ/2,staveThickness/2);
//   Volume    staveInnerVol(det_name+"_inner",staveTrdInner,air);
  
  //double layerOuterAngle = (M_PI-externalAngle)/2;
  //double layerexternalAngle = (M_PI/2 - layerOuterAngle);
  double layer_pos_z = -(staveThickness / 2);    
  double layer_pos_x = 0; 
  
  double layer_dim_x = innerFaceLen/2;
  int layer_num = 1;
  
  double layerR = rmin;

  // Set envelope volume attributes.
  envelopeVol.setAttributes(description,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());

  for(xml_coll_t c(x_det,_U(layer)); c; ++c)  {
    xml_comp_t   x_layer = c;
    int          repeat = x_layer.repeat();            // Get number of times to repeat this layer.
    const Layer* lay    = layering.layer(layer_num-1); // Get the layer from the layering engine.
    // Loop over repeats for this layer.
    for (int j = 0; j < repeat; j++)    {
      string     layer_name      = det_name+_toString(layer_num,"_layer%d");
      double     layer_thickness = lay->thickness();
      DetElement layer(stave,_toString(layer_num,"layer%d"),x_det.id());

      // Layer position in Z within the stave.
      layer_pos_z += layer_thickness / 2;
      // Layer box & volume
      Volume layer_vol(layer_name, Box(layer_dim_x,detZ/2,layer_thickness/2), air);

      // Create the slices (sublayers) within the layer.
      double slice_pos_z = -(layer_thickness / 2);
      int slice_number = 1;
      for(xml_coll_t k(x_layer,_U(slice)); k; ++k)  {
	xml_comp_t x_slice = k;
	string   slice_name      = layer_name + _toString(slice_number,"_slice%d");
	double   slice_thickness = x_slice.thickness();
	Material slice_material  = description.material(x_slice.materialStr());
	DetElement slice(layer,_toString(slice_number,"slice%d"),x_det.id());

	slice_pos_z += slice_thickness / 2;
	// Slice volume & box
	Volume slice_vol(slice_name,Box(layer_dim_x,detZ/2,slice_thickness/2),slice_material);

	if ( x_slice.isSensitive() ) {
	  sens.setType("calorimeter");
	  slice_vol.setSensitiveDetector(sens);
	}
	// Set region, limitset, and vis.
	slice_vol.setAttributes(description,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
	// slice PlacedVolume
	PlacedVolume slice_phv = layer_vol.placeVolume(slice_vol,Position(0,0,slice_pos_z));
	slice_phv.addPhysVolID("slice",slice_number);

	slice.setPlacement(slice_phv);
	// Increment Z position for next slice.
	slice_pos_z += slice_thickness / 2;
	// Increment slice number.
	++slice_number;
      }
      // Set region, limitset, and vis.
      layer_vol.setAttributes(description,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());

      // Layer physical volume.
      PlacedVolume layer_phv = staveOuterVol.placeVolume(layer_vol,Position((layer_dim_x+layer_pos_x-half_polyFace),0,layer_pos_z));
      layer_phv.addPhysVolID("layer",layer_num);
      layer.setPlacement(layer_phv);

      layerR += layer_thickness;
      // Increment the layer X dimension.
      layer_pos_x = (layerR-rmin)/tan_external;
      layer_dim_x =  (std::sqrt(rmax*rmax - layerR*layerR)+half_polyFace - layer_pos_x)/2.0;
      cout<<"Rmin: "<< rmin<<" Rmax: "<<rmax<<" half_polyFace: "<<half_polyFace<<" Layer " <<layer_num<<" layerR: "<<layerR<<" layer_dim_x:" <<layer_dim_x<<endl;
      // Increment the layer Z position.
      layer_pos_z += layer_thickness / 2;
      // Increment the layer number.
      ++layer_num;
    }
  }

  // Add stave inner physical volume to outer stave volume.
//   staveOuterVol.placeVolume(staveInnerVol); //not needed
  // Set the vis attributes of the outer stave section.
//   stave.setVisAttributes(description,staves.visStr(),staveOuterVol); //not applicable for Assembly
  // Place the staves.
  placeStaves(sdet,stave,rmin,numSides,totalThickness,envelopeVol,externalAngle,staveOuterVol);

  double z_offset = dim.hasAttr(_U(z_offset)) ? dim.z_offset() : 0.0;
  Transform3D transform(RotationZ(M_PI-(M_PI/numSides)),Translation3D(0,0,z_offset));
  PlacedVolume env_phv = motherVol.placeVolume(envelopeVol,transform);
  env_phv.addPhysVolID("system", sdet.id());
  env_phv.addPhysVolID("barrel", 0);
  sdet.setPlacement(env_phv);

  //sdet.addExtension<LayerStack>(new PolyhedralCalorimeterLayerStack(sdet));
  return sdet;
}
Пример #3
0
static Ref_t create_element(Detector& theDetector, xml_h xmlHandle, SensitiveDetector /*sens*/) {

  //------------------------------------------
  //  See comments starting with '//**' for
  //     hints on porting issues
  //------------------------------------------

  std::cout << "This is the Mask:" << std::endl;

  // Access to the XML File
  xml_det_t xmlMask = xmlHandle;
  const std::string name = xmlMask.nameStr();

  //--------------------------------
  Assembly envelope(name + "_assembly");
  //--------------------------------

  DetElement tube(name, xmlMask.id());

  //  const double phi1 = 0 ;
  //  const double phi2 = 360.0*dd4hep::degree;

  // Parameters we have to know about
  dd4hep::xml::Component xmlParameter = xmlMask.child(_Unicode(parameter));
  const double crossingAngle = xmlParameter.attr<double>(_Unicode(crossingangle)) * 0.5;  //  only half the angle

  for (xml_coll_t c(xmlMask, Unicode("section")); c; ++c) {

    xml_comp_t xmlSection(c);

    ODH::ECrossType crossType = ODH::getCrossType(xmlSection.attr<std::string>(_Unicode(type)));
    const double zStart = xmlSection.attr<double>(_Unicode(start));
    const double zEnd = xmlSection.attr<double>(_Unicode(end));
    const double rInnerStart = xmlSection.attr<double>(_Unicode(rMin1));
    const double rInnerEnd = xmlSection.attr<double>(_Unicode(rMin2));
    const double rOuterStart = xmlSection.attr<double>(_Unicode(rMax1));
    const double rOuterEnd = xmlSection.attr<double>(_Unicode(rMax2));
    const double phi1 = xmlSection.attr<double>(_Unicode(Phi1));
    const double phi2 = xmlSection.attr<double>(_Unicode(Phi2));
    const double thickness = rOuterStart - rInnerStart;
    Material sectionMat = theDetector.material(xmlSection.materialStr());
    const std::string volName = "tube_" + xmlSection.nameStr();

    std::cout << std::setw(8) << zStart << std::setw(8) << zEnd << std::setw(8) << rInnerStart << std::setw(8)
              << rInnerEnd << std::setw(8) << rOuterStart << std::setw(8) << rOuterEnd << std::setw(8) << thickness
              << std::setw(8) << crossType << std::setw(8) << phi1 << std::setw(8) << phi2 << std::setw(15) << volName
              << std::setw(15) << sectionMat.name() << std::endl;

    // things which can be calculated immediately
    const double zHalf = fabs(zEnd - zStart) * 0.5;      // half z length of the cone
    const double zPosition = fabs(zEnd + zStart) * 0.5;  // middle z position
    Material material = sectionMat;

    // this could mess up your geometry, so better check it
    if (not ODH::checkForSensibleGeometry(crossingAngle, crossType)) {
      throw std::runtime_error(" Mask_o1_v01_noRot_geo.cpp : checkForSensibleGeometry() failed ");
    }

    const double rotateAngle =
        getCurrentAngle(crossingAngle, crossType);  // for the placement at +z (better make it const now)
    const double mirrorAngle = M_PI - rotateAngle;  // for the "mirrored" placement at -z
    // the "mirroring" in fact is done by a rotation of (almost) 180 degrees around the y-axis

    switch (crossType) {
    case ODH::kCenter:
    case ODH::kUpstream:
    case ODH::kDnstream: {
      // a volume on the z-axis, on the upstream branch, or on the downstream branch

      // absolute transformations for the placement in the world, rotate over X
      Transform3D transformer(RotationX(rotateAngle), RotateX(Position(0, 0, zPosition), rotateAngle));
      Transform3D transmirror(RotationX(mirrorAngle), RotateX(Position(0, 0, zPosition), mirrorAngle));

      // solid for the tube (including vacuum and wall): a solid cone
      ConeSegment tubeSolid(zHalf, rInnerStart, rOuterStart, rInnerEnd, rOuterEnd, phi1, phi2);

      // tube consists of vacuum
      Volume tubeLog(volName, tubeSolid, material);
      tubeLog.setVisAttributes(theDetector, xmlMask.visStr());

      // placement of the tube in the world, both at +z and -z
      envelope.placeVolume(tubeLog, transformer);
      envelope.placeVolume(tubeLog, transmirror);

    } break;

    case ODH::kPunchedCenter: {
      // a cone with one or two inner holes (two tubes are punched out)

      const double rUpstreamPunch = rInnerStart;  // just alias names denoting what is meant here
      const double rDnstreamPunch = rInnerEnd;    // (the database entries are "abused" in this case)

      // relative transformations for the composition of the SubtractionVolumes
      Transform3D upstreamTransformer(RotationY(-crossingAngle), Position(zPosition * tan(-crossingAngle), 0, 0));
      Transform3D dnstreamTransformer(RotationY(+crossingAngle), Position(zPosition * tan(+crossingAngle), 0, 0));

      // absolute transformations for the final placement in the world (angles always equal zero and 180 deg)
      Transform3D placementTransformer(RotationY(rotateAngle), RotateY(Position(0, 0, zPosition), rotateAngle));
      Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY(Position(0, 0, zPosition), mirrorAngle));

      // the main solid and the two pieces (only tubes, for the moment) which will be punched out
      ConeSegment wholeSolid(zHalf, 0, rOuterStart, 0, rOuterEnd, phi1, phi2);
      Solid tmpSolid0, tmpSolid1, finalSolid0, finalSolid1;

      // the punched subtraction solids can be asymmetric and therefore have to be created twice:
      // one time in the "right" way, another time in the "reverse" way, because the "mirroring"
      // rotation around the y-axis will not only exchange +z and -z, but also +x and -x

      if (rUpstreamPunch > 1e-6) {                                     // do we need a hole on the upstream branch?
        Tube upstreamPunch(0, rUpstreamPunch, 5 * zHalf, phi1, phi2);  // a bit longer
        tmpSolid0 = SubtractionSolid(wholeSolid, upstreamPunch, upstreamTransformer);
        tmpSolid1 = SubtractionSolid(wholeSolid, upstreamPunch, dnstreamTransformer);  // [sic]
      } else {  // dont't do anything, just pass on the unmodified shape
        tmpSolid0 = wholeSolid;
        tmpSolid1 = wholeSolid;
      }

      if (rDnstreamPunch > 1e-6) {                                     // do we need a hole on the downstream branch?
        Tube dnstreamPunch(0, rDnstreamPunch, 5 * zHalf, phi1, phi2);  // a bit longer
        finalSolid0 = SubtractionSolid(tmpSolid0, dnstreamPunch, dnstreamTransformer);
        finalSolid1 = SubtractionSolid(tmpSolid1, dnstreamPunch, upstreamTransformer);  // [sic]
      } else {  // dont't do anything, just pass on the unmodified shape
        finalSolid0 = tmpSolid0;
        finalSolid1 = tmpSolid1;
      }

      // tube consists of vacuum (will later have two different daughters)
      Volume tubeLog0(volName + "_0", finalSolid0, material);
      Volume tubeLog1(volName + "_1", finalSolid1, material);
      tubeLog0.setVisAttributes(theDetector, xmlMask.visStr());
      tubeLog1.setVisAttributes(theDetector, xmlMask.visStr());

      // placement of the tube in the world, both at +z and -z
      envelope.placeVolume(tubeLog0, placementTransformer);
      envelope.placeVolume(tubeLog1, placementTransmirror);

      break;
    }

    case ODH::kPunchedUpstream:
    case ODH::kPunchedDnstream: {
      // a volume on the upstream or downstream branch with two inner holes
      // (implemented as a cone from which another tube is punched out)

      const double rCenterPunch = (crossType == ODH::kPunchedUpstream)
          ? (rInnerStart)
          : (rInnerEnd);  // just alias names denoting what is meant here
      const double rOffsetPunch = (crossType == ODH::kPunchedDnstream)
          ? (rInnerStart)
          : (rInnerEnd);  // (the database entries are "abused" in this case)

      // relative transformations for the composition of the SubtractionVolumes
      Transform3D punchTransformer(RotationY(-2 * rotateAngle), Position(zPosition * tan(-2 * rotateAngle), 0, 0));
      Transform3D punchTransmirror(RotationY(+2 * rotateAngle), Position(zPosition * tan(+2 * rotateAngle), 0, 0));

      // absolute transformations for the final placement in the world
      Transform3D placementTransformer(RotationY(rotateAngle), RotateY(Position(0, 0, zPosition), rotateAngle));
      Transform3D placementTransmirror(RotationY(mirrorAngle), RotateY(Position(0, 0, zPosition), mirrorAngle));

      // the main solid and the piece (only a tube, for the moment) which will be punched out
      ConeSegment wholeSolid(zHalf, rCenterPunch, rOuterStart, rCenterPunch, rOuterEnd, phi1, phi2);
      Tube punchSolid(0, rOffsetPunch, 5 * zHalf, phi1, phi2);  // a bit longer

      // the punched subtraction solids can be asymmetric and therefore have to be created twice:
      // one time in the "right" way, another time in the "reverse" way, because the "mirroring"
      // rotation around the y-axis will not only exchange +z and -z, but also +x and -x
      SubtractionSolid finalSolid0(wholeSolid, punchSolid, punchTransformer);
      SubtractionSolid finalSolid1(wholeSolid, punchSolid, punchTransmirror);

      // tube consists of vacuum (will later have two different daughters)
      Volume tubeLog0(volName + "_0", finalSolid0, material);
      Volume tubeLog1(volName + "_1", finalSolid1, material);
      tubeLog0.setVisAttributes(theDetector, xmlMask.visStr());
      tubeLog1.setVisAttributes(theDetector, xmlMask.visStr());

      // placement of the tube in the world, both at +z and -z
      envelope.placeVolume(tubeLog0, placementTransformer);
      envelope.placeVolume(tubeLog1, placementTransmirror);

      break;
    }
    default: { throw std::runtime_error(" Mask_o1_v01_geo.cpp : fatal failure !! ??  "); }

    }  // end switch
  }    // for all xmlSections

  //--------------------------------------
  Volume mother = theDetector.pickMotherVolume(tube);
  PlacedVolume pv(mother.placeVolume(envelope));
  pv.addPhysVolID("system", xmlMask.id());  //.addPhysVolID("side", 0 ) ;

  tube.setVisAttributes(theDetector, xmlMask.visStr(), envelope);

  tube.setPlacement(pv);

  return tube;
}
Пример #4
0
static Ref_t create_detector(Detector& description, xml_h e, SensitiveDetector sens)  {
  xml_det_t  x_det     = e;
  Material   air       = description.air();
  string     det_name  = x_det.nameStr();
  bool       reflect   = x_det.reflect();
  DetElement sdet(det_name,x_det.id());
  Assembly   assembly(det_name);
  PlacedVolume pv;
  int l_num = 0;
    
  for(xml_coll_t i(x_det,_U(layer)); i; ++i, ++l_num)  {
    xml_comp_t x_layer = i;
    string l_nam = det_name+_toString(l_num,"_layer%d");
    double  zmin = x_layer.inner_z();
    double  rmin = x_layer.inner_r();
    double  rmax = x_layer.outer_r();
    double  z    = zmin, layerWidth = 0.;
    int     s_num = 0;
      
    for(xml_coll_t j(x_layer,_U(slice)); j; ++j)  {
      double thickness = xml_comp_t(j).thickness();
      layerWidth += thickness;
    }
    Tube    l_tub(rmin,rmax,layerWidth,2*M_PI);
    Volume  l_vol(l_nam,l_tub,air);
    l_vol.setVisAttributes(description,x_layer.visStr());
    for(xml_coll_t j(x_layer,_U(slice)); j; ++j, ++s_num)  {
      xml_comp_t x_slice = j;
      double thick = x_slice.thickness();
      Material mat = description.material(x_slice.materialStr());
      string s_nam = l_nam+_toString(s_num,"_slice%d");
      Volume s_vol(s_nam, Tube(rmin,rmax,thick), mat);
        
      if ( x_slice.isSensitive() ) {
        sens.setType("tracker");
        s_vol.setSensitiveDetector(sens);
      }
      s_vol.setAttributes(description,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
      pv = l_vol.placeVolume(s_vol,Position(0,0,z-zmin-layerWidth/2+thick/2));
      pv.addPhysVolID("slice",s_num);
    }

    DetElement layer(sdet,l_nam+"_pos",l_num);
    pv = assembly.placeVolume(l_vol,Position(0,0,zmin+layerWidth/2.));
    pv.addPhysVolID("layer",l_num);
    pv.addPhysVolID("barrel",1);
    layer.setPlacement(pv);
    if ( reflect )  {
      pv = assembly.placeVolume(l_vol,Transform3D(RotationY(M_PI),Position(0,0,-zmin-layerWidth/2)));
      pv.addPhysVolID("layer",l_num);
      pv.addPhysVolID("barrel",2);
      DetElement layerR = layer.clone(l_nam+"_neg");
      sdet.add(layerR.setPlacement(pv));
    }
  }
  if ( x_det.hasAttr(_U(combineHits)) ) {
    sdet.setCombineHits(x_det.attr<bool>(_U(combineHits)),sens);
  }
  pv = description.pickMotherVolume(sdet).placeVolume(assembly);
  pv.addPhysVolID("system", x_det.id());      // Set the subdetector system ID.
  sdet.setPlacement(pv);
  return sdet;
}