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;
}
예제 #2
0
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens)  {

  xml_det_t   x_det       = element;
  string      det_name    = x_det.nameStr();
  DetElement  sdet( det_name,x_det.id() );

  Layering    layering(x_det);
  xml_dim_t dim = x_det.dimensions();

  // --- create an envelope volume and position it into the world ---------------------
  
  Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector,  element , sdet ) ;
  
  dd4hep::xml::setDetectorTypeFlag( element, sdet ) ;
  
  if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;

  //-----------------------------------------------------------------------------------

  Material      air               = theDetector.air();

  sens.setType("calorimeter");

//====================================================================
//
// Read all the dimensions from compact.xml, user can update the value.
// Use them to build a calo box prototye.
//
//====================================================================

  double      Calo_dim_x          = dim.x();
  double      Calo_dim_y          = dim.y();
  double      Calo_dim_z          = dim.z();

  printout( dd4hep::DEBUG,  "building SamplingCaloBoxPrototype_v01",
	    "Calo_dim_x : %e    Calo_dim_y: %e    Calo_dim_z: %e ",
  	    Calo_dim_x, Calo_dim_y, Calo_dim_z) ;


//====================================================================
//
// general calculated parameters
//
//====================================================================
 
  //calorimeter dimensions
  double cal_hx = Calo_dim_x/2.0;
  double cal_hy = Calo_dim_y/2.0;
  double cal_hz = Calo_dim_z/2.0;


//====================================================================
//
// build sampling layers in the CaloBox
//
//====================================================================

    int layer_num = 0;
    int layerType   = 0;

    double layer_pos_z = - cal_hz;

    for (xml_coll_t c(x_det, _U(layer)); c; ++c) {
        xml_comp_t x_layer = c;
        int repeat = x_layer.repeat();
        const Layer* lay = layering.layer(layer_num);
        double layer_thickness = lay->thickness();
        string layer_type_name   = _toString(layerType,"layerType%d");

        // Loop over repeats for this layer.
        for (int j = 0; j < repeat; j++) {
            string layer_name = _toString(layer_num, "layer%d");
            DetElement layer(layer_name, layer_num);

            // Layer box & volume
            Volume layer_vol(layer_type_name, Box(cal_hx, cal_hy, layer_thickness / 2), air);
            
            // Create the slices (sublayers) within the layer.
            double slice_pos_z = -(layer_thickness / 2);
            int slice_number = 0;
            
            for (xml_coll_t k(x_layer, _U(slice)); k; ++k) {
                xml_comp_t x_slice = k;
                string slice_name = _toString(slice_number, "slice%d");
                double slice_thickness = x_slice.thickness();
                Material slice_material = theDetector.material(x_slice.materialStr());
                DetElement slice(layer, slice_name, slice_number);

                slice_pos_z += slice_thickness / 2;
                // Slice volume & box
                Volume slice_vol(slice_name, Box(cal_hx, cal_hy, slice_thickness / 2), slice_material);
                
                
                if (x_slice.isSensitive()) {
                    sens.setType("calorimeter");
                    slice_vol.setSensitiveDetector(sens);                   
                } 

                
                // Set region, limitset, and vis.
                slice_vol.setAttributes(theDetector, 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(theDetector, x_layer.regionStr(), x_layer.limitsStr(), x_layer.visStr());
           
            // Layer position in Z within the stave.
            layer_pos_z += layer_thickness / 2;
            // Layer physical volume.
            PlacedVolume layer_phv = envelope.placeVolume(layer_vol, Position(0, 0, layer_pos_z));
            layer_phv.addPhysVolID("layer", layer_num);
            layer.setPlacement(layer_phv);
            
            // Increment the layer Z position.
            layer_pos_z += layer_thickness / 2;
            // Increment the layer number.
            ++layer_num;
        }
        
        ++layerType;
    }

 
    return sdet;

}
예제 #3
0
static Ref_t create_detector(Detector& theDetector, 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);
    
    // --- create an envelope volume and position it into the world ---------------------
    
    Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector,  e , sdet ) ;
    dd4hep::xml::setDetectorTypeFlag( e, sdet ) ;
    
    if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
    
    //-----------------------------------------------------------------------------------
    
    xml_dim_t   dim       = x_det.dimensions();
    Material    air       = theDetector.air();
    int         nsides_inner = dim.nsides_inner();
    int         nsides_outer = dim.nsides_outer();
    double      rmin      = dim.rmin();
    double      rmax      = dim.rmax(); /// FIXME: IS THIS RIGHT?
    double      zmin      = dim.zmin();
    
    double       rcutout   = dim.hasAttr(_U(rmin2)) ? dim.rmin2() : 0.;
    double       zcutout   = dim.hasAttr(_U(z2)) ? dim.z2() : 0.;
    
    Layering    layering(x_det);
    double      totalThickness = layering.totalThickness();
    Readout readout = sens.readout();
    Segmentation seg = readout.segmentation();
    
    std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0); //Assume uniform cell sizes, provide dummy cellID
    double cell_sizeX      = cellSizeVector[0];
    double cell_sizeY      = cellSizeVector[1];
    
    
    PolyhedraRegular polyVolume(nsides_outer,rmin,rmax,totalThickness);
    Volume      endcapVol("endcap",polyVolume,air);
    
    
    if(zcutout >0. || rcutout > 0.){
        PolyhedraRegular cutoutPolyVolume(nsides_inner,0,rmin+rcutout,zcutout);
        Position cutoutPos(0,0,(zcutout-totalThickness)/2.0);
        std::cout<<"Cutout z width will be  "<<zcutout<<std::endl; 
        endcapVol=Volume("endcap",SubtractionSolid(polyVolume,cutoutPolyVolume,cutoutPos),air);
        
    }
    
    
    DetElement  endcapA(sdet,"endcap",det_id);
    Ref_t(endcapA)->SetName((det_name+"_A").c_str());
    
    int layer_num = 0;
    int layerType   = 0;
    double layerZ   = -totalThickness/2;
    
    //Create caloData object to extend driver with data required for reconstruction
    LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
    caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
    caloData->inner_symmetry = nsides_inner;
    caloData->outer_symmetry = nsides_outer; 
    
    /** NOTE: phi0=0 means lower face flat parallel to experimental floor
     *  This is achieved by rotating the modules with respect to the envelope
     *  which is assumed to be a Polyhedron and has its axes rotated with respect
     *  to the world by 180/nsides. In any other case (e.g. if you want to have
     *  a tip of the calorimeter touching the ground) this value needs to be computed
     */
    
    caloData->inner_phi0 = 0.; 
    caloData->outer_phi0 = 0.; 
    caloData->gap0 = 0.; //FIXME
    caloData->gap1 = 0.; //FIXME
    caloData->gap2 = 0.; //FIXME  
    
    
    /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
    caloData->extent[0] = rmin ;
    caloData->extent[1] = rmax ; ///FIXME: CHECK WHAT IS NEEDED (EXSCRIBED?)
    caloData->extent[2] = zmin ;
    caloData->extent[3] = zmin + totalThickness;
    
    endcapVol.setAttributes(theDetector,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;
        double           layer_thick  = layering.layer(layer_num)->thickness();
        string           layer_type_name   = _toString(layerType,"layerType%d");
        int              layer_repeat = x_layer.repeat();
        double            layer_rcutout = x_layer.hasAttr(_U(gap)) ? x_layer.gap() : 0;
        
        std::cout<<"Number of layers in group "<<layerType<<" : "<<layer_repeat<<std::endl; 
        
        Volume           layer_vol(layer_type_name,PolyhedraRegular(nsides_outer,rmin+layer_rcutout,rmax,layer_thick),air);
        
        int slice_num = 0;
        double sliceZ = -layer_thick/2;
        
        //Create a caloLayer struct for thiss layer type to store copies of in the parent struct
        LayeredCalorimeterData::Layer caloLayer ;
        caloLayer.cellSize0 = cell_sizeX;
        caloLayer.cellSize1 = cell_sizeY; 
        
        double nRadiationLengths=0.;
        double nInteractionLengths=0.;
        double thickness_sum=0;
        
        for(xml_coll_t s(x_layer,_U(slice)); s; ++s)  {
            xml_comp_t x_slice = s;
            string     slice_name  = _toString(slice_num,"slice%d");
            double     slice_thickness = x_slice.thickness();
            Material   slice_material   = theDetector.material(x_slice.materialStr());
            Volume     slice_vol(slice_name,PolyhedraRegular(nsides_outer,rmin+layer_rcutout,rmax,slice_thickness),slice_material);
            
            slice_vol.setVisAttributes(theDetector.visAttributes(x_slice.visStr()));
            sliceZ += slice_thickness/2;
            layer_vol.placeVolume(slice_vol,Position(0,0,sliceZ));
            
            nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
            nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
            thickness_sum += slice_thickness/2;
            
            if ( x_slice.isSensitive() )  {
                sens.setType("calorimeter");
                slice_vol.setSensitiveDetector(sens);
                
#if DD4HEP_VERSION_GE( 0, 15 )
                //Store "inner" quantities
                caloLayer.inner_nRadiationLengths = nRadiationLengths;
                caloLayer.inner_nInteractionLengths = nInteractionLengths;
                caloLayer.inner_thickness = thickness_sum;
                //Store scintillator thickness
                caloLayer.sensitive_thickness = slice_thickness;
#endif
                //Reset counters to measure "outside" quantitites
                nRadiationLengths=0.;
                nInteractionLengths=0.;
                thickness_sum = 0.;
            } 
            
            nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
            nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
            thickness_sum += slice_thickness/2;

            sliceZ += slice_thickness/2;
            slice_num++;
        }
        
#if DD4HEP_VERSION_GE( 0, 15 )
        //Store "outer" quantities
        caloLayer.outer_nRadiationLengths = nRadiationLengths;
        caloLayer.outer_nInteractionLengths = nInteractionLengths;
        caloLayer.outer_thickness = thickness_sum;
#endif        
        layer_vol.setVisAttributes(theDetector.visAttributes(x_layer.visStr()));
        
        
        if ( layer_repeat <= 0 ) throw std::runtime_error(x_det.nameStr()+"> Invalid repeat value");
        
        for(int j=0; j<layer_repeat; ++j) {
            string phys_lay = _toString(layer_num,"layer%d");
            
            //The rest of the data is constant; only the distance needs to be updated  
            //Store the position up to the inner face of the layer
            caloLayer.distance = zmin +  totalThickness/2 + layerZ;
            //Push back a copy to the caloData structure
            caloData->layers.push_back( caloLayer );
            
            layerZ += layer_thick/2;
            DetElement    layer_elt(endcapA, phys_lay, layer_num);
            PlacedVolume  pv = endcapVol.placeVolume(layer_vol,Position(0,0,layerZ));
            pv.addPhysVolID("layer", layer_num);
            layer_elt.setPlacement(pv);
            
            layerZ += layer_thick/2;
            ++layer_num;
        }
        ++layerType;
    }
    
    double z_pos = zmin+totalThickness/2;
    PlacedVolume pv;
    // Reflect it.
    
    DetElement  endcapB = endcapA.clone(det_name+"_B",x_det.id());
    
    //Removed rotations to align with envelope
    //NOTE: If the envelope is not a polyhedron (eg. if you use a tube)
    //you may need to rotate so the axes match
    
    pv = envelope.placeVolume(endcapVol,Transform3D(RotationZYX(0,0,0),
                                                    Position(0,0,z_pos)));
    pv.addPhysVolID("side", 1);
    endcapA.setPlacement(pv);
    
    //Removed rotations
    pv = envelope.placeVolume(endcapVol,Transform3D(RotationZYX(0,M_PI,0),
                                                    Position(0,0,-z_pos)));
    pv.addPhysVolID("side", 2);
    endcapB.setPlacement(pv);
    
    sdet.add(endcapB);
    
    sdet.addExtension< LayeredCalorimeterData >( caloData ) ;
    
    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;
}
예제 #5
0
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens)  {
  static double tolerance = 0e0;

  xml_det_t     x_det     = element;
  string        det_name  = x_det.nameStr();
  Layering      layering (element);

  Material      air       = theDetector.air();
  //unused: Material      vacuum    = theDetector.vacuum();

  int           det_id    = x_det.id();
  xml_comp_t    x_staves  = x_det.staves();
  DetElement    sdet      (det_name,det_id);

  xml_comp_t    x_dim     = x_det.dimensions();
  int           nsides    = x_dim.numsides();
  double        dphi      = (2*M_PI/nsides);
  double        hphi      = dphi/2;


 // --- create an envelope volume and position it into the world ---------------------

  Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector,  element , sdet ) ;

  dd4hep::xml::setDetectorTypeFlag( element, sdet ) ;
 
  if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;

  //-----------------------------------------------------------------------------------


  sens.setType("calorimeter");

  Material stave_material  = theDetector.material(x_staves.materialStr());

  DetElement    stave_det("module0stave0",det_id);

  Readout readout = sens.readout();
  Segmentation seg = readout.segmentation();
  
  // check if we have a WaferGridXY segmentation :
  WaferGridXY* waferSeg = 
    dynamic_cast< WaferGridXY*>( seg.segmentation() ) ;

  std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0); //Assume uniform cell sizes, provide dummy cellID
  double cell_sizeX      = cellSizeVector[0];
  double cell_sizeY      = cellSizeVector[1];

//====================================================================
//
// Read all the constant from ILD_o1_v05.xml
// Use them to build HcalBarrel
//
//====================================================================

  int N_FIBERS_W_STRUCTURE = 2; 
  int N_FIBERS_ALVOULUS = 3;

  //  read parametere from compact.xml file
  double Ecal_Alveolus_Air_Gap              = theDetector.constant<double>("Ecal_Alveolus_Air_Gap");
  double Ecal_Slab_shielding                = theDetector.constant<double>("Ecal_Slab_shielding");
  double Ecal_Slab_copper_thickness         = theDetector.constant<double>("Ecal_Slab_copper_thickness");
  double Ecal_Slab_PCB_thickness            = theDetector.constant<double>("Ecal_Slab_PCB_thickness");
  double Ecal_Slab_glue_gap                 = theDetector.constant<double>("Ecal_Slab_glue_gap");
  double Ecal_Slab_ground_thickness         = theDetector.constant<double>("Ecal_Slab_ground_thickness");
  double Ecal_fiber_thickness               = theDetector.constant<double>("Ecal_fiber_thickness");
  double Ecal_Si_thickness                  = theDetector.constant<double>("Ecal_Si_thickness");
  
  double Ecal_inner_radius                  = theDetector.constant<double>("TPC_outer_radius") +theDetector.constant<double>("Ecal_Tpc_gap");
  double Ecal_radiator_thickness1           = theDetector.constant<double>("Ecal_radiator_layers_set1_thickness");
  double Ecal_radiator_thickness2           = theDetector.constant<double>("Ecal_radiator_layers_set2_thickness");
  double Ecal_radiator_thickness3           = theDetector.constant<double>("Ecal_radiator_layers_set3_thickness");
  double Ecal_Barrel_halfZ                  = theDetector.constant<double>("Ecal_Barrel_halfZ");
  
  double Ecal_support_thickness             = theDetector.constant<double>("Ecal_support_thickness");
  double Ecal_front_face_thickness          = theDetector.constant<double>("Ecal_front_face_thickness");
  double Ecal_lateral_face_thickness        = theDetector.constant<double>("Ecal_lateral_face_thickness");
  double Ecal_Slab_H_fiber_thickness        = theDetector.constant<double>("Ecal_Slab_H_fiber_thickness");

  double Ecal_Slab_Sc_PCB_thickness         = theDetector.constant<double>("Ecal_Slab_Sc_PCB_thickness");
  double Ecal_Sc_thickness                  = theDetector.constant<double>("Ecal_Sc_thickness");
  double Ecal_Sc_reflector_thickness        = theDetector.constant<double>("Ecal_Sc_reflector_thickness");

  int    Ecal_nlayers1                      = theDetector.constant<int>("Ecal_nlayers1");
  int    Ecal_nlayers2                      = theDetector.constant<int>("Ecal_nlayers2");
  int    Ecal_nlayers3                      = theDetector.constant<int>("Ecal_nlayers3");
  int    Ecal_barrel_number_of_towers       = theDetector.constant<int>("Ecal_barrel_number_of_towers");
  
  //double      Ecal_cells_size                  = theDetector.constant<double>("Ecal_cells_size");
  double Ecal_guard_ring_size               = theDetector.constant<double>("Ecal_guard_ring_size");
  
//====================================================================
//
// general calculated parameters
//
//====================================================================
  
  double Ecal_total_SiSlab_thickness = 
    Ecal_Slab_shielding + 
    Ecal_Slab_copper_thickness + 
    Ecal_Slab_PCB_thickness +
    Ecal_Slab_glue_gap + 
    Ecal_Si_thickness + 
    Ecal_Slab_ground_thickness +
    Ecal_Alveolus_Air_Gap / 2;
#ifdef VERBOSE
  std::cout << " Ecal_total_SiSlab_thickness = " << Ecal_total_SiSlab_thickness  << std::endl;
#endif
  
  

  double Ecal_total_ScSlab_thickness = 
    Ecal_Slab_shielding + 
    Ecal_Slab_copper_thickness + 
    Ecal_Slab_Sc_PCB_thickness +
    Ecal_Sc_thickness + 
    Ecal_Sc_reflector_thickness * 2 +
    Ecal_Alveolus_Air_Gap / 2;
#ifdef VERBOSE
  std::cout << " Ecal_total_ScSlab_thickness = " << Ecal_total_ScSlab_thickness  << std::endl;
#endif
  

    int Number_of_Si_Layers_in_Barrel = 0;
    int Number_of_Sc_Layers_in_Barrel = 0;


#ifdef VERBOSE
  std::cout << " Ecal total number of Silicon layers = " << Number_of_Si_Layers_in_Barrel  << std::endl;
  std::cout << " Ecal total number of Scintillator layers = " << Number_of_Sc_Layers_in_Barrel  << std::endl;
#endif
  
  // In this release the number of modules is fixed to 5
  double Ecal_Barrel_module_dim_z = 2 * Ecal_Barrel_halfZ / 5. ;
#ifdef VERBOSE
  std::cout << "Ecal_Barrel_module_dim_z  = " << Ecal_Barrel_module_dim_z  << std::endl;
#endif

  // The alveolus size takes in account the module Z size
  // but also 4 fiber layers for the alveoulus wall, the all
  // divided by the number of towers
  double alveolus_dim_z = 
    (Ecal_Barrel_module_dim_z - 2. * Ecal_lateral_face_thickness) /
    Ecal_barrel_number_of_towers - 
    2 * N_FIBERS_ALVOULUS  * Ecal_fiber_thickness  - 
    2 * Ecal_Slab_H_fiber_thickness -
    2 * Ecal_Slab_shielding;


#ifdef VERBOSE
  std::cout << "alveolus_dim_z = " <<  alveolus_dim_z << std::endl;
#endif

  int n_total_layers = Ecal_nlayers1 + Ecal_nlayers2 + Ecal_nlayers3;
  Number_of_Si_Layers_in_Barrel = n_total_layers+1;

  double module_thickness = 
    Ecal_nlayers1 * Ecal_radiator_thickness1 +
    Ecal_nlayers2 * Ecal_radiator_thickness2 +
    Ecal_nlayers3 * Ecal_radiator_thickness3 +
    
    int(n_total_layers/2) * // fiber around W struct layers
    (N_FIBERS_W_STRUCTURE * 2 *  Ecal_fiber_thickness) +
    
    Number_of_Si_Layers_in_Barrel * // Silicon slabs plus fiber around and inside
    (Ecal_total_SiSlab_thickness +
     (N_FIBERS_ALVOULUS + 1 ) * Ecal_fiber_thickness) +
    
    Number_of_Sc_Layers_in_Barrel * // Scintillator slabs plus fiber around and inside
    (Ecal_total_ScSlab_thickness +
     (N_FIBERS_ALVOULUS + 1 ) * Ecal_fiber_thickness) +
    
    Ecal_support_thickness + Ecal_front_face_thickness;
  
#ifdef VERBOSE
  std::cout << "For information : module_thickness = " << module_thickness  << std::endl;
#endif
  
  // module barrel key parameters
  double  bottom_dim_x = 2. * tan(M_PI/8.) * Ecal_inner_radius +
    module_thickness/sin(M_PI/4.);
  
  double top_dim_x = bottom_dim_x - 2 * module_thickness;

  //------------------------------------------------------------------------------------

  LayeredCalorimeterData::Layer caloLayer ;
  caloLayer.cellSize0 = cell_sizeX;
  caloLayer.cellSize1 = cell_sizeY;

  //== For Wafer ===  
  double cell_dim_x = caloLayer.cellSize0;
  double total_Si_dim_z = alveolus_dim_z;

  double util_SI_wafer_dim_z = 
    total_Si_dim_z/2 -  2 * Ecal_guard_ring_size;

  double cell_dim_z =  util_SI_wafer_dim_z/ 
    floor(util_SI_wafer_dim_z/
	  cell_dim_x);

  int N_cells_in_Z = int(util_SI_wafer_dim_z/cell_dim_z);
  int N_cells_in_X = N_cells_in_Z;
  
  cell_dim_x = cell_dim_z;


  
#ifdef VERBOSE
  std::cout << " bottom_dim_x = " << bottom_dim_x  << std::endl;
  std::cout << " top_dim_x = " << top_dim_x << std::endl;
  std::cout << " Ecal total number of Silicon layers = " << Number_of_Si_Layers_in_Barrel  << std::endl;
  std::cout << " Ecal total number of Scintillator layers = " << Number_of_Sc_Layers_in_Barrel  << std::endl;
#endif
  


// ========= Create Ecal Barrel stave   ====================================
//  It will be the volume for palcing the Ecal Barrel alveolus(i.e. Layers).
//  And the structure W plate.
//  Itself will be placed into the world volume.
// ==========================================================================

  // The TOP_X and BOTTOM_X is different in Mokka and DD4hep
  Trapezoid trd(top_dim_x / 2,
		bottom_dim_x / 2, 
		Ecal_Barrel_module_dim_z / 2,
		Ecal_Barrel_module_dim_z / 2,
		module_thickness/2);

  //  Volume mod_vol(det_name+"_module",trd,theDetector.material("g10"));
  Volume mod_vol(det_name+"_module",trd,theDetector.material("CarbonFiber")); // DJeans 5-sep-2016

  // We count the layers starting from IP and from 1,
  // so odd layers should be inside slabs and
  // even ones on the structure.
  // The structure W layers are here big plans, as the 
  // gap between each W plate is too small to create problems 
  // The even W layers are part of H structure placed inside
  // the alveolus.

  // ############################
  //  Dimension of radiator wLog
  //  slice provide the thickness
  // ############################


  double y_floor = 
    Ecal_front_face_thickness +
    N_FIBERS_ALVOULUS * Ecal_fiber_thickness;


  // ############################
  //  Dimension of alveolus
  //  slice provide the thickness
  // ############################
  
    // =====  build Si Slab and put into the Layer volume =====
    // =====  place the layer into the module 5 time for one full layer into the trd module ====
    // =====  build and place barrel structure into trd module ====
    // Parameters for computing the layer X dimension:
    double stave_z  =(Ecal_Barrel_module_dim_z - 2. * Ecal_lateral_face_thickness) / Ecal_barrel_number_of_towers/2.;
    double l_dim_x  = bottom_dim_x/2.;                            // Starting X dimension for the layer.
    double l_pos_z  = module_thickness/2;

    l_dim_x -= y_floor;
    l_pos_z -= y_floor;


    // ------------- create extension objects for reconstruction -----------------
    
    //========== fill data for reconstruction ============================
    LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
    caloData->layoutType = LayeredCalorimeterData::BarrelLayout ;
    caloData->inner_symmetry = nsides  ;
    //added by Thorben Quast
    caloData->outer_symmetry = nsides  ;
    caloData->phi0 = 0 ; // hardcoded 
    
    /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
    caloData->extent[0] = Ecal_inner_radius ;
    //line fixed by Thorben Quast since actual conversion is made during the drawing
    caloData->extent[1] = ( Ecal_inner_radius + module_thickness );
    //caloData->extent[1] = ( Ecal_inner_radius + module_thickness ) / cos( M_PI/8. ) ;
    caloData->extent[2] = 0. ;
    caloData->extent[3] = Ecal_Barrel_halfZ ;

    // // base vectors for surfaces:
    // dd4hep::rec::Vector3D u(1,0,0) ;
    // dd4hep::rec::Vector3D v(0,1,0) ;
    // dd4hep::rec::Vector3D n(0,0,1) ;


    //-------------------- start loop over ECAL layers ----------------------
    // Loop over the sets of layer elements in the detector.

    double nRadiationLengths   = 0. ;
    double nInteractionLengths = 0. ;
    double thickness_sum       = 0. ;

    nRadiationLengths   = Ecal_radiator_thickness1/(stave_material.radLength())
      + y_floor/air.radLength();
    nInteractionLengths = Ecal_radiator_thickness1/(stave_material.intLength())
      + y_floor/air.intLength();
    thickness_sum       = Ecal_radiator_thickness1 + y_floor;

    int l_num = 1;
    bool isFirstSens = true;
    int myLayerNum = 0 ;

    for(xml_coll_t li(x_det,_U(layer)); li; ++li)  {
      xml_comp_t x_layer = li;
      int repeat = x_layer.repeat();
      // Loop over number of repeats for this layer.
      for (int j=0; j<repeat; j++)    {
	string l_name = _toString(l_num,"layer%d");
	double l_thickness = layering.layer(l_num-1)->thickness();  // Layer's thickness.
	double xcut = (l_thickness);                     // X dimension for this layer.
	l_dim_x -= xcut;


	Box        l_box(l_dim_x-tolerance,stave_z-tolerance,l_thickness/2.0-tolerance);
	Volume     l_vol(det_name+"_"+l_name,l_box,air);

	l_vol.setVisAttributes(theDetector.visAttributes(x_layer.visStr()));

	//fg: need vector of DetElements for towers ! 
	//    DetElement layer(stave_det, l_name, det_id);
	std::vector< DetElement > layers( Ecal_barrel_number_of_towers )  ;
	
	// place layer 5 times in module. at same layer position (towers !)
	double l_pos_y = Ecal_Barrel_module_dim_z / 2. 
	  - ( Ecal_lateral_face_thickness +
	      Ecal_fiber_thickness * N_FIBERS_ALVOULUS +
	      Ecal_Slab_shielding + 
	      Ecal_Slab_H_fiber_thickness +
	      alveolus_dim_z /2.);						  
       	for (int i=0; i<Ecal_barrel_number_of_towers; i++){ // need four clone

	  layers[i] = DetElement( stave_det, l_name+_toString(i,"tower%02d") , det_id ) ;

	  Position   l_pos(0,l_pos_y,l_pos_z-l_thickness/2.);      // Position of the layer.
	  PlacedVolume layer_phv = mod_vol.placeVolume(l_vol,l_pos);
	  // layer_phv.addPhysVolID("layer", l_num);
	  layer_phv.addPhysVolID("tower", i);

	  layers[i].setPlacement(layer_phv);
	  l_pos_y -= (alveolus_dim_z + 
		      2. * Ecal_fiber_thickness * N_FIBERS_ALVOULUS +
		      2. * Ecal_Slab_H_fiber_thickness +
		      2. * Ecal_Slab_shielding);
	}




	// Loop over the sublayers or slices for this layer.
	int s_num = 1;
	double s_pos_z = l_thickness / 2.;


	//--------------------------------------------------------------------------------
	// BuildBarrelAlveolus: BuildSiliconSlab:
	//--------------------------------------------------------------------------------
	double radiator_dim_y = Ecal_radiator_thickness1; //to be updated with slice radiator thickness 

	for(xml_coll_t si(x_layer,_U(slice)); si; ++si)  {
	  xml_comp_t x_slice = si;
	  string     s_name  =  _toString(s_num,"slice%d");
	  double     s_thick = x_slice.thickness();
	  Material slice_material  = theDetector.material(x_slice.materialStr());
#ifdef VERBOSE
	  std::cout<<"Ecal_barrel_number_of_towers: "<< Ecal_barrel_number_of_towers <<std::endl;
#endif
	  double slab_dim_x = l_dim_x-tolerance;
	  double slab_dim_y = s_thick/2.;
	  double slab_dim_z = stave_z-tolerance;

	  Box        s_box(slab_dim_x,slab_dim_z,slab_dim_y);
	  Volume     s_vol(det_name+"_"+l_name+"_"+s_name,s_box,slice_material);
	  //fg: not needed          DetElement slice(layer,s_name,det_id);

	  s_vol.setVisAttributes(theDetector.visAttributes(x_slice.visStr()));
#ifdef VERBOSE
	  std::cout<<"x_slice.materialStr(): "<< x_slice.materialStr() <<std::endl;
#endif
	  if (x_slice.materialStr().compare(x_staves.materialStr()) == 0){
	    radiator_dim_y = s_thick;
	  // W StructureLayer has the same thickness as W radiator layer in the Alveolus layer
	    
#if DD4HEP_VERSION_GE( 0, 15 )
	    caloLayer.outer_nRadiationLengths   = nRadiationLengths;
	    caloLayer.outer_nInteractionLengths = nInteractionLengths;
	    caloLayer.outer_thickness           = thickness_sum;

	    if (!isFirstSens){ caloData->layers.push_back( caloLayer ) ;
#ifdef VERBOSE
	    std::cout<<" caloLayer.distance: "<< caloLayer.distance <<std::endl;

	    std::cout<<" caloLayer.inner_nRadiationLengths: "<< caloLayer.inner_nRadiationLengths <<std::endl;
	    std::cout<<" caloLayer.inner_nInteractionLengths: "<< caloLayer.inner_nInteractionLengths <<std::endl;
	    std::cout<<" caloLayer.inner_thickness: "<< caloLayer.inner_thickness <<std::endl;
	    std::cout<<" caloLayer.sensitive_thickness: "<< caloLayer.sensitive_thickness <<std::endl;

	    std::cout<<" caloLayer.outer_nRadiationLengths: "<< caloLayer.outer_nRadiationLengths <<std::endl;
	    std::cout<<" caloLayer.outer_nInteractionLengths: "<< caloLayer.outer_nInteractionLengths <<std::endl;
	    std::cout<<" caloLayer.outer_thickness: "<< caloLayer.outer_thickness <<std::endl;

	    std::cout<<" EcalBarrel[1]==>caloLayer.inner_thickness + caloLayer.outer_thickness: "
		     << caloLayer.inner_thickness + caloLayer.outer_thickness <<std::endl;
#endif
	    }
#endif
	    // Init for inner
	    nRadiationLengths   = 0. ;
	    nInteractionLengths = 0. ;
	    thickness_sum       = 0. ;	    
	    isFirstSens         = false;

	  }
	  nRadiationLengths   += s_thick/(2.*slice_material.radLength());
	  nInteractionLengths += s_thick/(2.*slice_material.intLength());
	  thickness_sum       += s_thick/2.;

          if ( x_slice.isSensitive() ) {
	    //s_vol.setSensitiveDetector(sens);

	    // Normal squared wafers
	    double wafer_dim_x = 
	      N_cells_in_X * cell_dim_x;
	    double wafer_dim_z = 
	      N_cells_in_Z * cell_dim_z;
	    Box WaferSiSolid( wafer_dim_x/2,wafer_dim_z/2,slab_dim_y);
	    //Volume WaferSiLog(det_name+"_"+l_name+"_"+s_name+"Wafer",WaferSiSolid,slice_material);
	    //WaferSiLog.setSensitiveDetector(sens);

	    double real_wafer_size_x =
	      wafer_dim_x + 2 * Ecal_guard_ring_size;
      
	    int n_wafers_x =
	      int(floor(slab_dim_x*2 / real_wafer_size_x));
      
	    double wafer_pos_x =
	      -slab_dim_x + 
	      Ecal_guard_ring_size +
	      wafer_dim_x /2 ;
	    int n_wafer_x;
	    int wafer_num = 0;
	    for (n_wafer_x = 1;
		 n_wafer_x < n_wafers_x + 1;
		 n_wafer_x++)
	      {
		double wafer_pos_z =
		  -alveolus_dim_z/2.0 + 
		  Ecal_guard_ring_size +
		  wafer_dim_z /2;
		for (int n_wafer_z = 1;
		     n_wafer_z < 3;
		     n_wafer_z++)
		  {
		    wafer_num++;
		    string Wafer_name  =  _toString(wafer_num,"wafer%d");
		    Volume WaferSiLog(det_name+"_"+l_name+"_"+s_name+"_"+Wafer_name,WaferSiSolid,slice_material);
		    WaferSiLog.setSensitiveDetector(sens);
		    //WaferSiLog.setVisAttributes(theDetector.visAttributes(x_slice.visStr()));
		    PlacedVolume wafer_phv = s_vol.placeVolume(WaferSiLog,Position(wafer_pos_x,
							  wafer_pos_z,
							  0));
		    wafer_phv.addPhysVolID("wafer", wafer_num);

		    // Normal squared wafers, this waferOffsetX is 0.0 
		    waferSeg->setWaferOffsetX(myLayerNum, wafer_num, 0.0);

		    wafer_pos_z +=
		      wafer_dim_z +
		      2 * Ecal_guard_ring_size;
		  }
		wafer_pos_x += 
		  wafer_dim_x +
		  2 * Ecal_guard_ring_size;
	      }

	    // Magic wafers to complete the slab...
	    // (wafers with variable number of cells just
	    // to complete the slab. in reality we think that
	    // we'll have just a few models of special wafers
	    // for that.
	    double resting_dim_x =
	      slab_dim_x*2 - 
	      (wafer_dim_x + 2 * Ecal_guard_ring_size) * 
	      n_wafers_x;

	    if(resting_dim_x >
	       (cell_dim_x + 2 * Ecal_guard_ring_size))
	      {
		int N_cells_x_remaining =
		  int(floor((resting_dim_x - 
			     2 * Ecal_guard_ring_size)
			    /cell_dim_x));
		
		wafer_dim_x =
		  N_cells_x_remaining *
		  cell_dim_x;
		
		Box MagicWaferSiSolid( wafer_dim_x/2,wafer_dim_z/2,slab_dim_y);
		//Volume MagicWaferSiLog(det_name+"_"+l_name+"_"+s_name+"MagicWafer",MagicWaferSiSolid,slice_material);

		// Magic wafers, this waferOffsetX has to be taken care, 0.0 or half cell size in X.
		double thisWaferOffsetX = 0.0;
		if ( N_cells_x_remaining%2 ) thisWaferOffsetX = cell_dim_x/2.0;

		wafer_pos_x =
		  -slab_dim_x +
		  n_wafers_x * real_wafer_size_x +
		  (wafer_dim_x + 2 * Ecal_guard_ring_size)/2;
	  
		real_wafer_size_x =
		  wafer_dim_x + 2 * Ecal_guard_ring_size;
	  
		double wafer_pos_z =
		  -alveolus_dim_z/2.0 + 
		  Ecal_guard_ring_size +
		  wafer_dim_z /2;

		//int MagicWafer_num = 0;
		for (int n_wafer_z = 1;
		     n_wafer_z < 3;
		     n_wafer_z++)
		  {
		    wafer_num++;
		    string MagicWafer_name  =  _toString(wafer_num,"MagicWafer%d");
		    Volume MagicWaferSiLog(det_name+"_"+l_name+"_"+s_name+"_"+MagicWafer_name,MagicWaferSiSolid,slice_material);
		    MagicWaferSiLog.setSensitiveDetector(sens);
		    //MagicWaferSiLog.setVisAttributes(theDetector.visAttributes(x_slice.visStr()));
		    PlacedVolume wafer_phv = s_vol.placeVolume(MagicWaferSiLog,Position(wafer_pos_x,
							       wafer_pos_z,
							       0));
		    wafer_phv.addPhysVolID("wafer", wafer_num);

		    // Magic wafers, set the waferOffsetX for this layer this wafer.
		    waferSeg->setWaferOffsetX(myLayerNum, wafer_num, thisWaferOffsetX);

		    wafer_pos_z +=
		      wafer_dim_z +
		      2 * Ecal_guard_ring_size;
		  }
	      }
	    

#if DD4HEP_VERSION_GE( 0, 15 )
	    //Store "inner" quantities
	    caloLayer.inner_nRadiationLengths   = nRadiationLengths ;
	    caloLayer.inner_nInteractionLengths = nInteractionLengths ;
	    caloLayer.inner_thickness           = thickness_sum ;
	    //Store sensitive slice thickness
	    caloLayer.sensitive_thickness       = s_thick ;
#ifdef VERBOSE	    
	    std::cout<<" l_num: "<<l_num <<std::endl;
	    std::cout<<" s_num: "<<s_num <<std::endl;
	    std::cout<<" Ecal_inner_radius: "<< Ecal_inner_radius <<std::endl;
	    std::cout<<" module_thickness: "<< module_thickness <<std::endl;
	    std::cout<<" l_pos_z: "<< l_pos_z <<std::endl;
	    std::cout<<" l_thickness: "<< l_thickness <<std::endl;
	    std::cout<<" s_pos_z: "<< s_pos_z <<std::endl;
	    std::cout<<" s_thick: "<< s_thick <<std::endl;
	    std::cout<<" radiator_dim_y: "<< radiator_dim_y <<std::endl;
#endif	    
	    //-----------------------------------------------------------------------------------------
	    caloLayer.distance  = Ecal_inner_radius + module_thickness/2.0 - l_pos_z + l_thickness/2. + (s_pos_z+s_thick/2.) 
	      - caloLayer.inner_thickness;
	    caloLayer.absorberThickness = radiator_dim_y ;

	    //-----------------------------------------------------------------------------------------
#endif
	    // Init for outer
	    nRadiationLengths   = 0. ;
	    nInteractionLengths = 0. ;
	    thickness_sum       = 0. ;

	  }

	  nRadiationLengths   += s_thick/(2.*slice_material.radLength());
	  nInteractionLengths += s_thick/(2.*slice_material.intLength());
	  thickness_sum       += s_thick/2;


          // Slice placement.
          PlacedVolume slice_phv = l_vol.placeVolume(s_vol,Position(0,0,s_pos_z-s_thick/2));

          if ( x_slice.isSensitive() ) {
	    slice_phv.addPhysVolID("layer", myLayerNum++ );
	    //	    slice_phv.addPhysVolID("slice",s_num);
	  }

	  //fg: not needed   slice.setPlacement(slice_phv);

          // Increment Z position of slice.
          s_pos_z -= s_thick;
                                        
          // Increment slice number.
          ++s_num;

        }        

#if DD4HEP_VERSION_GE( 0, 15 )
	caloLayer.outer_nRadiationLengths   = nRadiationLengths
	  + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.radLength();
	caloLayer.outer_nInteractionLengths = nInteractionLengths
	  + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.intLength();
	caloLayer.outer_thickness           = thickness_sum 
	  + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE));

	if (!isFirstSens) caloData->layers.push_back( caloLayer ) ;
#ifdef VERBOSE
	std::cout<<" caloLayer.distance: "<< caloLayer.distance <<std::endl;
	
	std::cout<<" caloLayer.inner_nRadiationLengths: "<< caloLayer.inner_nRadiationLengths <<std::endl;
	std::cout<<" caloLayer.inner_nInteractionLengths: "<< caloLayer.inner_nInteractionLengths <<std::endl;
	std::cout<<" caloLayer.inner_thickness: "<< caloLayer.inner_thickness <<std::endl;
	std::cout<<" caloLayer.sensitive_thickness: "<< caloLayer.sensitive_thickness <<std::endl;

	std::cout<<" caloLayer.outer_nRadiationLengths: "<< caloLayer.outer_nRadiationLengths <<std::endl;
	std::cout<<" caloLayer.outer_nInteractionLengths: "<< caloLayer.outer_nInteractionLengths <<std::endl;
	std::cout<<" caloLayer.outer_thickness: "<< caloLayer.outer_thickness <<std::endl;

	std::cout<<" EcalBarrel[2]==>caloLayer.inner_thickness + caloLayer.outer_thickness: "
		 << caloLayer.inner_thickness + caloLayer.outer_thickness <<std::endl;
#endif
#endif
	// Init for next double layer
	nRadiationLengths   = radiator_dim_y/(stave_material.radLength())
	  + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.radLength();
	nInteractionLengths = radiator_dim_y/(stave_material.intLength())
	  + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE))/air.intLength();
	thickness_sum       = radiator_dim_y
	  + (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE));
	
	if(radiator_dim_y <= 0) {
	  stringstream err;
	  err << " \n ERROR: The subdetector " << x_det.nameStr() << " geometry parameter -- radiator_dim_y = " << radiator_dim_y ;
	  err << " \n Please check the radiator material name in the subdetector xml file";
	  throw runtime_error(err.str());
	}

	// #########################
	// BuildBarrelStructureLayer
	// #########################


	l_dim_x -=  (radiator_dim_y +  Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE));
	double radiator_dim_x = l_dim_x*2.;

#ifdef VERBOSE
	std::cout << "radiator_dim_x = " << radiator_dim_x << std::endl;
#endif  

	double radiator_dim_z =
	  Ecal_Barrel_module_dim_z -
	  2 * Ecal_lateral_face_thickness -
	  2 * N_FIBERS_W_STRUCTURE * Ecal_fiber_thickness;
	
	string bs_name="bs";
	Box        barrelStructureLayer_box(radiator_dim_x/2.,radiator_dim_z/2.,radiator_dim_y/2.);
	Volume     barrelStructureLayer_vol(det_name+"_"+l_name+"_"+bs_name,barrelStructureLayer_box,stave_material);

	barrelStructureLayer_vol.setVisAttributes(theDetector.visAttributes(x_layer.visStr()));	


        // Increment to next layer Z position.
        l_pos_z -= l_thickness;          

	// Without last W StructureLayer, the last part is Si SD even layer.
	// the last number of  Ecal_nlayers1, Ecal_nlayers2 and  Ecal_nlayers3 is odd.
	int even_layer = l_num*2;
	if(even_layer > Ecal_nlayers1 + Ecal_nlayers2 + Ecal_nlayers3) continue;
	//if ( Number_of_Si_Layers_in_Barrel > n_total_layers ) continue;

	double bsl_pos_z = l_pos_z - (radiator_dim_y/2. + Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE));
	l_pos_z -= (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE));

	Position   bsl_pos(0,0,bsl_pos_z);      // Position of the layer.
	// PlacedVolume  barrelStructureLayer_phv =
	  mod_vol.placeVolume(barrelStructureLayer_vol,bsl_pos);

	l_dim_x -=  (Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE));	
	l_pos_z -= (radiator_dim_y + Ecal_fiber_thickness * (N_FIBERS_ALVOULUS + N_FIBERS_W_STRUCTURE));
	
        ++l_num;

      }
    }
  

    // Set stave visualization.
    if (x_staves)   {
      mod_vol.setVisAttributes(theDetector.visAttributes(x_staves.visStr()));
    }
    
    
    
//====================================================================
// Place ECAL Barrel stave module into the envelope volume
//====================================================================
    double X,Y;
    X = module_thickness * sin(M_PI/4.);
    Y = Ecal_inner_radius + module_thickness / 2.;
    
    for (int stave_id = 1; stave_id <= nsides ; stave_id++)
      for (int module_id = 1; module_id < 6; module_id++)
	{
	  double phirot =  (stave_id-1) * dphi - hphi*3.0;
	  double module_z_offset =  (2 * module_id-6) * Ecal_Barrel_module_dim_z/2.;
	  
	  // And the rotation in Mokka is right hand rule, and the rotation in DD4hep is clockwise rule
	  // So there is a negitive sign when port Mokka into DD4hep 
	  Transform3D tr(RotationZYX(0,phirot,M_PI*0.5),Translation3D(X*cos(phirot)-Y*sin(phirot),
								      X*sin(phirot)+Y*cos(phirot),
								      module_z_offset));
	  PlacedVolume pv = envelope.placeVolume(mod_vol,tr);
	  pv.addPhysVolID("module",module_id);
	  pv.addPhysVolID("stave",stave_id);
	  DetElement sd = (module_id==0&&stave_id==0) ? stave_det : stave_det.clone(_toString(module_id,"module%d")+_toString(stave_id,"stave%d"));
	  sd.setPlacement(pv);
	  sdet.add(sd);
	  
	}
    
    // Set envelope volume attributes.
    envelope.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
    
    sdet.addExtension< LayeredCalorimeterData >( caloData ) ; 


    return sdet;
}
예제 #6
0
static Ref_t create_detector(Detector& theDetector, xml_h e, SensitiveDetector sens)  {
    typedef vector<PlacedVolume> Placements;
    xml_det_t   x_det     = e;
    Material    air       = theDetector.air();
    int         det_id    = x_det.id();
    string      det_name  = x_det.nameStr();
    DetElement  sdet       (det_name,det_id);
    // Assembly    assembly   (det_name);
    map<string, Volume>    volumes;
    map<string, Placements>  sensitives;
    PlacedVolume pv;
    

    // for encoding
    std::string cellIDEncoding = sens.readout().idSpec().fieldDescription();
    UTIL::BitField64 encoder( cellIDEncoding );
    encoder.reset();
    encoder[lcio::LCTrackerCellID::subdet()] = det_id;
    encoder[lcio::LCTrackerCellID::side()] = lcio::ILDDetID::barrel;


    // --- create an envelope volume and position it into the world ---------------------
    
    Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector,  e , sdet ) ;
    dd4hep::xml::setDetectorTypeFlag( e, sdet ) ;
    
    if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
    
    //-----------------------------------------------------------------------------------
    ZPlanarData*  zPlanarData = new ZPlanarData() ;
    NeighbourSurfacesData*  neighbourSurfacesData = new NeighbourSurfacesData() ;
    
    sens.setType("tracker");
    
    //NOTE modules are what is defined in compact. Later we call a "module" as a "sensor".
    for(xml_coll_t mi(x_det,_U(module)); mi; ++mi)  {
        xml_comp_t x_mod  = mi;
        xml_comp_t m_env  = x_mod.child(_U(module_envelope));
        string     m_nam  = x_mod.nameStr();

        
        if ( volumes.find(m_nam) != volumes.end() )   {
            printout(ERROR,"TrackerBarrel","Logics error in building modules.");
            throw runtime_error("Logic error in building modules.");
        }

        double module_thickness = 0;
        for(xml_coll_t incl(x_mod,_U(include)); incl; ++incl) {
            dd4hep::xml::DocumentHolder doc(dd4hep::xml::DocumentHandler().load(incl, incl.attr_value(_U(ref))));
            xml_h includes = doc.root();
            xml_det_t incl_stack = includes;
            for (xml_coll_t ci(incl_stack, _U(module_component)); ci; ++ci) {
                xml_comp_t x_comp = ci;
                module_thickness = module_thickness + x_comp.thickness();
            }
        }

        Volume     m_vol(m_nam,Box(m_env.width()/2.,m_env.length()/2.,module_thickness/2.),air);
        volumes[m_nam] = m_vol;
        m_vol.setVisAttributes(theDetector.visAttributes(x_mod.visStr()));
        
        
        int        ncomponents = 0; 
        
        //First component on top of the list is the innermost one. 
        double position_z= -module_thickness/2.;
        for(xml_coll_t incl(x_mod,_U(include)); incl; ++incl) {
            dd4hep::xml::DocumentHolder doc(dd4hep::xml::DocumentHandler().load(incl, incl.attr_value(_U(ref))));
            xml_h includes = doc.root();
            xml_det_t incl_stack = includes;
            for (xml_coll_t ci(incl_stack, _U(module_component)); ci; ++ci, ++ncomponents) {
                xml_comp_t x_comp = ci;
                string c_nam = _toString(ncomponents, "component%d");
                Box c_box(m_env.width() / 2.0, m_env.length() / 2.0, x_comp.thickness() / 2.0);
                Volume c_vol(c_nam, c_box, theDetector.material(x_comp.materialStr()));


                pv = m_vol.placeVolume(c_vol, Position(0, 0, position_z + x_comp.thickness() / 2.0));

                c_vol.setRegion(theDetector, x_comp.regionStr());
                c_vol.setLimitSet(theDetector, x_comp.limitsStr());
                c_vol.setVisAttributes(theDetector, x_comp.visStr());
                if (x_comp.isSensitive()) {
                    //         pv.addPhysVolID("wafer",wafer_number++);
                    c_vol.setSensitiveDetector(sens);
                    sensitives[m_nam].push_back(pv);
                }

                position_z += x_comp.thickness();
            }
        }
    }
    for(xml_coll_t li(x_det,_U(layer)); li; ++li)  {
        xml_comp_t x_layer  = li;
        xml_comp_t x_layout = x_layer.child(_U(rphi_layout));
        xml_comp_t z_layout = x_layer.child(_U(z_layout));      // Get the <z_layout> element.
        int        lay_id   = x_layer.id();
        // int        type     = x_layer.type();
        string     m_nam    = x_layer.moduleStr();
        string     lay_nam  = _toString(x_layer.id(),"layer%d");
        Assembly   lay_vol   (lay_nam);         // Create the layer envelope volume.
        double     phi0     = x_layout.phi0();              // Starting phi of first sensor.
        double     phi_tilt = x_layout.phi_tilt();          // Phi tilt of a sensor.
        double     rc       = x_layout.rc();                // Radius of the sensor center.
        int        nphi     = x_layout.nphi();              // Number of sensors in phi.
        double     rphi_dr  = x_layout.dr();                // The delta radius of every other sensor.
        
        double     phi_incr = (M_PI * 2) / nphi;            // Phi increment for one sensor.
        double     phic     = phi0;                         // Phi of the sensor center.
        double     z0       = z_layout.z0();                // Z position of first sensor in phi.
        double     nz       = z_layout.nz();                // Number of sensors to place in z.
        double     z_dr     = z_layout.dr();                // Radial displacement parameter, of every other sensor.
        Volume     m_env    = volumes[m_nam];
        DetElement lay_elt(sdet,_toString(x_layer.id(),"layer%d"),lay_id);
        Placements& waferVols = sensitives[m_nam];
        
        // Z increment for sensor placement along Z axis.
        // Adjust for z0 at center of sensor rather than
        // the end of cylindrical envelope.
        double z_incr   = nz > 1 ? (2.0 * z0) / (nz - 1) : 0.0;
        // Starting z for sensor placement along Z axis.
        double sensor_z = -z0;
        int module_idx =0;
        
        
        ZPlanarData::LayerLayout thisLayer ;
        
       
        // Loop over the number of sensors in phi.
        for (int ii = 0; ii < nphi; ii++)        {
            double dx = z_dr * std::cos(phic + phi_tilt);        // Delta x of sensor position.
            double dy = z_dr * std::sin(phic + phi_tilt);        // Delta y of sensor position.
            double  x = rc * std::cos(phic);                     // Basic x sensor position.
            double  y = rc * std::sin(phic);                     // Basic y sensor position.
            
            // Loop over the number of sensors in z.
            //Create stave FIXME disable for now
            string module_name = _toString(module_idx,"module%d");
            //       DetElement module_elt(lay_elt,module_name,module_idx);
            int sensor_idx = 0;
            
            for (int j = 0; j < nz; j++)          {
                string sensor_name = _toString(sensor_idx,"sensor%d");

		///////////////////

		//get cellID and fill map< cellID of surface, vector of cellID of neighbouring surfaces >

		//encoding

		encoder[lcio::LCTrackerCellID::layer()] = lay_id;
		encoder[lcio::LCTrackerCellID::module()] = module_idx;
		encoder[lcio::LCTrackerCellID::sensor()] = sensor_idx;

		dd4hep::long64 cellID = encoder.lowWord(); // 32 bits

		//compute neighbours 

		int n_neighbours_module = 1; // 1 gives the adjacent modules (i do not think we would like to change this)
		int n_neighbours_sensor = 1;

		int newmodule=0, newsensor=0;

		for(int imodule=-n_neighbours_module; imodule<=n_neighbours_module; imodule++){ // neighbouring modules
		  for(int isensor=-n_neighbours_sensor; isensor<=n_neighbours_sensor; isensor++){ // neighbouring sensors
		    
		    if (imodule==0 && isensor==0) continue; // cellID we started with
		    newmodule = module_idx + imodule;
		    newsensor = sensor_idx + isensor;

		    //compute special case at the boundary  
		    //general computation to allow (if necessary) more then adjacent neighbours (ie: +-2)
		    
		    if (newmodule < 0) newmodule = nphi + newmodule;
		    if (newmodule >= nphi) newmodule = newmodule - nphi;

		    if (newsensor < 0 || newsensor >= nz) continue; //out of the stave

		    //encoding
		    encoder[lcio::LCTrackerCellID::module()] = newmodule;
		    encoder[lcio::LCTrackerCellID::sensor()] = newsensor;
		    
		    neighbourSurfacesData->sameLayer[cellID].push_back(encoder.lowWord());

		  }
		}

		///////////////////

                
                //FIXME
                sensor_name = module_name + sensor_name;
                
                DetElement sens_elt(lay_elt,sensor_name,sensor_idx);
                // Module PhysicalVolume.
                Transform3D tr(RotationZYX(0,((M_PI/2)-phic-phi_tilt),-M_PI/2),Position(x,y,sensor_z));
                
                //FIXME
                pv = lay_vol.placeVolume(m_env,tr);
                pv.addPhysVolID(_U(module), module_idx);
                pv.addPhysVolID(_U(sensor), sensor_idx);
                sens_elt.setPlacement(pv);
                for(size_t ic=0; ic<waferVols.size(); ++ic)  {
//                     std::cout<<"Layer: "<<lay_id<<" phiIdx: "<<ii<<" zidx: "<<j<<" wafer idx: "<<ic<<std::endl;
                    PlacedVolume wafer_pv = waferVols[ic];
                    DetElement comp_elt(sens_elt,wafer_pv.volume().name(),sensor_idx);
                    comp_elt.setPlacement(wafer_pv);
                    
                    ///GET GEAR INFORMATION FROM FIRST "MODULE" IN Z AND phi
                    ///NOTE WORKS ONLY FOR ONE WAFER
                    if (ii==0 && j==0 && ic==0){
                      
                      Box mod_shape(m_env.solid()), comp_shape(wafer_pv.volume().solid());
                      
                      const double* trans = comp_elt.placement()->GetMatrix()->GetTranslation();
                      double half_module_thickness = mod_shape->GetDZ();
                      double half_silicon_thickness = comp_shape->GetDZ();
                      
                      double sensitive_z_position  = trans[2];
                      
                      double inner_thickness = half_module_thickness - sensitive_z_position;
                      
                      thisLayer.distanceSupport  = rc  ;
                     
                      thisLayer.offsetSupport    =  0; 
                      thisLayer.thicknessSupport = inner_thickness- half_silicon_thickness;
                      thisLayer.zHalfSupport    = z0 + mod_shape->GetDY();
                      thisLayer.widthSupport     = 2*mod_shape->GetDX(); 
                      
                      thisLayer.distanceSensitive = rc+sensitive_z_position; 
                      thisLayer.offsetSensitive  = 0. ;
                      thisLayer.thicknessSensitive = 2*half_silicon_thickness;//Assembled along Z
                      //Changed by Thorben Quast (same applies to zHalfSupport)
                      //z0 = center of most right sensor, comp_shape-GetDY() = half length of one sensitive are of the module
                      thisLayer.zHalfSensitive    = z0 + comp_shape->GetDY();
                      thisLayer.widthSensitive = 2*comp_shape->GetDX();
                      thisLayer.ladderNumber = (int) nphi  ;
                      thisLayer.phi0 =  phic;
                    }
                    
                }
                

                /// Increase counters etc.
                sensor_idx++;
                // Adjust the x and y coordinates of the sensor.
                x += dx;
                y += dy;
                // Flip sign of x and y adjustments.
                dx *= -1;
                dy *= -1;
                // Add z increment to get next z placement pos.
                sensor_z += z_incr;
            }
            module_idx++;
            phic     += phi_incr;      // Increment the phi placement of sensor.
            rc       += rphi_dr;       // Increment the center radius according to dr parameter.
            rphi_dr  *= -1;            // Flip sign of dr parameter.
            sensor_z  = -z0;           // Reset the Z placement parameter for sensor.
        }
        // Create the PhysicalVolume for the layer.
        pv = envelope.placeVolume(lay_vol); // Place layer in mother
        pv.addPhysVolID("layer", lay_id);       // Set the layer ID.
        lay_elt.setAttributes(theDetector,lay_vol,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());
        lay_elt.setPlacement(pv);
        
        zPlanarData->layers.push_back( thisLayer ) ;
        
    }
    sdet.setAttributes(theDetector,envelope,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
    sdet.addExtension< ZPlanarData >( zPlanarData ) ;
    sdet.addExtension< NeighbourSurfacesData >( neighbourSurfacesData ) ;
    
    //envelope.setVisAttributes(theDetector.invisible());
    /*pv = theDetector.pickMotherVolume(sdet).placeVolume(assembly);
     pv.addPhysVolID("system", det_id);      // Set the subdetector system ID.
     pv.addPhysVolID("barrel", 0);           // Flag this as a barrel subdetector.
     sdet.setPlacement(pv);*/
    return sdet;
}
예제 #7
0
static Ref_t create_detector(Detector& theDetector,
                             xml_h element,
                             SensitiveDetector sens) {
    
    std::cout << __PRETTY_FUNCTION__  << std::endl;
    std::cout << "Here is my LumiCal"  << std::endl;
    std::cout << " and this is the sensitive detector: " << &sens  << std::endl;
    sens.setType("calorimeter");
    //Materials
    Material air = theDetector.air();
    
    //Access to the XML File
    xml_det_t     xmlLumiCal    = element;
    const std::string detName   = xmlLumiCal.nameStr();
    
    DetElement sdet ( detName, xmlLumiCal.id() );
    
    // --- create an envelope volume and position it into the world ---------------------
    
    Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector, element , sdet ) ;
    DetElement lumiCalDE_1(sdet,"Calorimeter1",1);
    DetElement lumiCalDE_2(sdet,"Calorimeter2",2);

    sdet.setTypeFlag( DetType::CALORIMETER |  DetType::ENDCAP  | DetType::ELECTROMAGNETIC |  DetType::FORWARD ) ;

    if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
    
    //-----------------------------------------------------------------------------------
    
    dd4hep::xml::Dimension dimensions =  xmlLumiCal.dimensions();
    
    //LumiCal Dimensions
    const double lcalInnerR = dimensions.inner_r();
    const double lcalOuterR = dimensions.outer_r();
    const double lcalInnerZ = dimensions.inner_z();
    const double lcalThickness = Layering(xmlLumiCal).totalThickness();
    const double lcalCentreZ = lcalInnerZ+lcalThickness*0.5;
    
    double LumiCal_cell_size      = theDetector.constant<double>("LumiCal_cell_size");
    //========== fill data for reconstruction ============================
    LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
    caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
    caloData->inner_symmetry = 0  ; // hardcoded tube
    caloData->outer_symmetry = 0  ; 
    caloData->phi0 = 0 ;
    
    /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
    caloData->extent[0] = lcalInnerR ;
    caloData->extent[1] = lcalOuterR ;
    caloData->extent[2] = lcalInnerZ ;
    caloData->extent[3] = lcalInnerZ + lcalThickness ;
    
    // counter for the current layer to be placed
    int thisLayerId = 0;
    
    //Parameters we have to know about
    dd4hep::xml::Component xmlParameter = xmlLumiCal.child(_Unicode(parameter));
    const double fullCrossingAngle  = xmlParameter.attr< double >(_Unicode(crossingangle));
    std::cout << " The crossing angle is: " << fullCrossingAngle << " radian"  << std::endl;
    
    
    //Envelope to place the layers in
    Tube envelopeTube (lcalInnerR, lcalOuterR, lcalThickness*0.5 );
    Volume     envelopeVol(detName+"_module",envelopeTube,air);
    envelopeVol.setVisAttributes(theDetector,xmlLumiCal.visStr());
    
    ////////////////////////////////////////////////////////////////////////////////
    // Create all the layers
    ////////////////////////////////////////////////////////////////////////////////
    
    //Loop over all the layer (repeat=NN) sections
    //This is the starting point to place all layers, we need this when we have more than one layer block
    double referencePosition = -lcalThickness*0.5;
    for(dd4hep::xml::Collection_t coll(xmlLumiCal,_U(layer)); coll; ++coll)  {
        dd4hep::xml::Component xmlLayer(coll); //we know this thing is a layer
        
        
        //This just calculates the total size of a single layer
        //Why no convenience function for this?
        double layerThickness = 0;
        for(dd4hep::xml::Collection_t l(xmlLayer,_U(slice)); l; ++l)
            layerThickness += xml_comp_t(l).thickness();
        
        std::cout << "Total Length "    << lcalThickness/dd4hep::cm  << " cm" << std::endl;
        std::cout << "Layer Thickness " << layerThickness/dd4hep::cm << " cm" << std::endl;
        
        //Loop for repeat=NN
        for(int i=0, repeat=xmlLayer.repeat(); i<repeat; ++i)  {
            
            std::string layer_name = detName + dd4hep::xml::_toString(thisLayerId,"_layer%d");
            Tube layer_base(lcalInnerR,lcalOuterR,layerThickness*0.5);
            
            Volume layer_vol(layer_name,layer_base,air);
            
            
            int sliceID=0;
            double inThisLayerPosition = -layerThickness*0.5;
            
            double nRadiationLengths=0.;
            double nInteractionLengths=0.;
            double thickness_sum=0;
            
            LayeredCalorimeterData::Layer caloLayer ;
            
            for(dd4hep::xml::Collection_t collSlice(xmlLayer,_U(slice)); collSlice; ++collSlice)  {
                dd4hep::xml::Component compSlice = collSlice;
                const double      slice_thickness = compSlice.thickness();
                const std::string sliceName = layer_name + dd4hep::xml::_toString(sliceID,"slice%d");
                Material   slice_material  = theDetector.material(compSlice.materialStr());
                
                Tube sliceBase(lcalInnerR,lcalOuterR,slice_thickness/2);
                
                Volume slice_vol (sliceName,sliceBase,slice_material);
                
                nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
                nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
                thickness_sum += slice_thickness/2;
                
                if ( compSlice.isSensitive() )  {

 #if DD4HEP_VERSION_GE( 0, 15 )
                   //Store "inner" quantities
                    caloLayer.inner_nRadiationLengths = nRadiationLengths;
                    caloLayer.inner_nInteractionLengths = nInteractionLengths;
                    caloLayer.inner_thickness = thickness_sum;
                    //Store scintillator thickness
                    caloLayer.sensitive_thickness = slice_thickness;
#endif                    
                    //Reset counters to measure "outside" quantitites
                    nRadiationLengths=0.;
                    nInteractionLengths=0.;
                    thickness_sum = 0.;
                    slice_vol.setSensitiveDetector(sens);
                }
                
                nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
                nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
                thickness_sum += slice_thickness/2;
                
                slice_vol.setAttributes(theDetector,compSlice.regionStr(),compSlice.limitsStr(),compSlice.visStr());
                layer_vol.placeVolume(slice_vol,Position(0,0,inThisLayerPosition+slice_thickness*0.5));
                    
                inThisLayerPosition += slice_thickness;
                ++sliceID;
            }//For all slices in this layer
            
            //-----------------------------------------------------------------------------------------
            
            ///Needs to be innermost face distance
            caloLayer.distance = lcalCentreZ + referencePosition;

#if DD4HEP_VERSION_GE( 0, 15 )
            caloLayer.outer_nRadiationLengths = nRadiationLengths;
            caloLayer.outer_nInteractionLengths = nInteractionLengths;
            caloLayer.outer_thickness = thickness_sum;
#endif            
            
            caloLayer.cellSize0 = LumiCal_cell_size ;
            caloLayer.cellSize1 = LumiCal_cell_size ;
            
            caloData->layers.push_back( caloLayer ) ;
            //-----------------------------------------------------------------------------------------
            
            //Why are we doing this for each layer, this just needs to be done once and then placed multiple times
            //Do we need unique IDs for each piece?
            layer_vol.setVisAttributes(theDetector,xmlLayer.visStr());
            
            Position layer_pos(0,0,referencePosition+0.5*layerThickness);
            referencePosition += layerThickness;
            PlacedVolume pv = envelopeVol.placeVolume(layer_vol,layer_pos);
            pv.addPhysVolID("layer",thisLayerId);
            
            ++thisLayerId;
            
        }//for all layers
        
    }// for all layer collections
    
    const Position bcForwardPos (std::tan(0.5*fullCrossingAngle)*lcalCentreZ,0.0, lcalCentreZ);
    const Position bcBackwardPos(std::tan(0.5*fullCrossingAngle)*lcalCentreZ,0.0,-lcalCentreZ);
    const Rotation3D bcForwardRot ( RotationY(fullCrossingAngle*0.5 ) );
    const Rotation3D bcBackwardRot( RotationZYX ( (M_PI), (M_PI-fullCrossingAngle*0.5), (0.0)));
    
    PlacedVolume pv =
    envelope.placeVolume(envelopeVol, Transform3D( bcForwardRot, bcForwardPos ) );
    pv.addPhysVolID("barrel", 1);
    lumiCalDE_1.setPlacement(pv);

    PlacedVolume pv2 =
    envelope.placeVolume(envelopeVol, Transform3D( bcBackwardRot, bcBackwardPos ) );
    pv2.addPhysVolID("barrel", 2);
    lumiCalDE_2.setPlacement(pv2);
    
    sdet.addExtension< LayeredCalorimeterData >( caloData ) ;
    
    return sdet;
}
예제 #8
0
static Ref_t create_detector(Detector& theDetector, xml_h element, SensitiveDetector sens)  {
  xml_det_t   x_det     = element;
  Layering    layering(x_det);
  xml_dim_t   dim         = x_det.dimensions();
  string      det_name    = x_det.nameStr();
  //unused: string      det_type    = x_det.typeStr();
  Material    air         = theDetector.air();
  Material    stavesMaterial    = theDetector.material(x_det.materialStr());
  int         numSides    = dim.numsides();

  int           det_id    = x_det.id();

  DetElement   sdet(det_name,det_id);

  PlacedVolume pVol;

  // --- create an envelope volume and position it into the world ---------------------

  Volume envelope = dd4hep::xml::createPlacedEnvelope( theDetector,  element , sdet ) ;
  
  sdet.setTypeFlag( DetType::CALORIMETER |  DetType::ENDCAP  | DetType::HADRONIC ) ;

  if( theDetector.buildType() == BUILD_ENVELOPE ) return sdet ;
  //-----------------------------------------------------------------------------------

  sens.setType("calorimeter");

  DetElement    stave_det("module0stave0",det_id);
 
  // The way to reaad constant from XML/Detector file.
  double      Hcal_radiator_thickness          = theDetector.constant<double>("Hcal_radiator_thickness");
  double      Hcal_endcap_lateral_structure_thickness = theDetector.constant<double>("Hcal_endcap_lateral_structure_thickness");
  double      Hcal_endcap_layer_air_gap        = theDetector.constant<double>("Hcal_endcap_layer_air_gap");

  //double      Hcal_cells_size                  = theDetector.constant<double>("Hcal_cells_size");
  double      HcalEndcap_inner_radius          = theDetector.constant<double>("HcalEndcap_inner_radius");
  double      HcalEndcap_outer_radius          = theDetector.constant<double>("HcalEndcap_outer_radius");
  double      HcalEndcap_min_z                 = theDetector.constant<double>("HcalEndcap_min_z");
  double      HcalEndcap_max_z                 = theDetector.constant<double>("HcalEndcap_max_z");

  double   Hcal_steel_cassette_thickness       = theDetector.constant<double>("Hcal_steel_cassette_thickness");
  double   HcalServices_outer_FR4_thickness    = theDetector.constant<double>("HcalServices_outer_FR4_thickness");
  double   HcalServices_outer_Cu_thickness     = theDetector.constant<double>("HcalServices_outer_Cu_thickness");
  double   Hcal_endcap_services_module_width   = theDetector.constant<double>("Hcal_endcap_services_module_width");

  Material  stainless_steel =  theDetector.material("stainless_steel");
  Material  PCB             =  theDetector.material("PCB");
  Material  copper          =  theDetector.material("Cu");

  std::cout <<"\n HcalEndcap_inner_radius = "
	    <<HcalEndcap_inner_radius/dd4hep::mm <<" mm"
	    <<"\n HcalEndcap_outer_radius = "
	    <<HcalEndcap_outer_radius/dd4hep::mm <<" mm"
	    <<"\n HcalEndcap_min_z = "
	    <<HcalEndcap_min_z/dd4hep::mm <<" mm"
	    <<"\n HcalEndcap_max_z = "
	    <<HcalEndcap_max_z/dd4hep::mm <<" mm"
	    <<std::endl;


  Readout readout = sens.readout();
  Segmentation seg = readout.segmentation();
  
  std::vector<double> cellSizeVector = seg.segmentation()->cellDimensions(0); //Assume uniform cell sizes, provide dummy cellID
  double cell_sizeX      = cellSizeVector[0];
  double cell_sizeY      = cellSizeVector[1];

  //========== fill data for reconstruction ============================
  LayeredCalorimeterData* caloData = new LayeredCalorimeterData ;
  caloData->layoutType = LayeredCalorimeterData::EndcapLayout ;
  caloData->inner_symmetry = 4  ; // hard code cernter box hole
  caloData->outer_symmetry = 0  ; // outer tube, or 8 for Octagun
  caloData->phi0 = 0 ;

  /// extent of the calorimeter in the r-z-plane [ rmin, rmax, zmin, zmax ] in mm.
  caloData->extent[0] = HcalEndcap_inner_radius ;
  caloData->extent[1] = HcalEndcap_outer_radius ;
  caloData->extent[2] = HcalEndcap_min_z ;
  caloData->extent[3] = HcalEndcap_max_z ;
  

  int endcapID = 0;
  for(xml_coll_t c(x_det.child(_U(dimensions)),_U(dimensions)); c; ++c) 
    {
      xml_comp_t l(c);
      
      double dim_x = l.attr<double>(_Unicode(dim_x));
      double dim_y = l.attr<double>(_Unicode(dim_y));
      double dim_z = l.attr<double>(_Unicode(dim_z));
      double pos_y = l.attr<double>(_Unicode(y_offset));
    
      // Hcal Endcap module shape
      double box_half_x= dim_x/2.0; // module width, all are same
      double box_half_y= dim_y/2.0; // total thickness, all are same
      double box_half_z= dim_z/2.0; // module length, changed, 
      
      double x_offset = box_half_x*numSides-box_half_x*endcapID*2.0-box_half_x;
      double y_offset = pos_y;
      
      Box    EndcapModule(box_half_x,box_half_y,box_half_z);
      
      // define the name of each endcap Module
      string envelopeVol_name   = det_name+_toString(endcapID,"_EndcapModule%d");
      
      Volume envelopeVol(envelopeVol_name,EndcapModule,stavesMaterial);
      
      // Set envelope volume attributes.
      envelopeVol.setAttributes(theDetector,x_det.regionStr(),x_det.limitsStr(),x_det.visStr());
      

      double FEE_half_x = box_half_x-Hcal_endcap_services_module_width/2.0;
      double FEE_half_y = box_half_y;
      double FEE_half_Z = Hcal_endcap_services_module_width/2.0;

      Box    FEEBox(FEE_half_x,FEE_half_y,FEE_half_Z);
      Volume FEEModule("Hcal_endcap_FEE",FEEBox,air);

      double FEELayer_thickness = Hcal_steel_cassette_thickness + HcalServices_outer_FR4_thickness + HcalServices_outer_Cu_thickness;
      Box    FEELayerBox(FEE_half_x,FEELayer_thickness/2.0,FEE_half_Z);
      Volume FEELayer("FEELayer",FEELayerBox,air);

      Box    FEELayerSteelBox(FEE_half_x,Hcal_steel_cassette_thickness/2.0,FEE_half_Z);
      Volume FEELayerSteel("FEELayerSteel",FEELayerSteelBox,stainless_steel);
      pVol = FEELayer.placeVolume(FEELayerSteel,
				  Position(0,
					   (-FEELayer_thickness/2.0
					    +Hcal_steel_cassette_thickness/2.0),
					   0));

      Box    FEELayerFR4Box(FEE_half_x,HcalServices_outer_FR4_thickness/2.0,FEE_half_Z);
      Volume FEELayerFR4("FEELayerFR4",FEELayerFR4Box,PCB);
      pVol = FEELayer.placeVolume(FEELayerFR4,
				  Position(0,
					   (-FEELayer_thickness/2.0+Hcal_steel_cassette_thickness
					    +HcalServices_outer_FR4_thickness/2.0),
					   0));

      Box    FEELayerCuBox(FEE_half_x,HcalServices_outer_Cu_thickness/2.0,FEE_half_Z);
      Volume FEELayerCu("FEELayerCu",FEELayerCuBox,copper);
      pVol = FEELayer.placeVolume(FEELayerCu,
				  Position(0,
					   (-FEELayer_thickness/2.0+Hcal_steel_cassette_thickness+HcalServices_outer_FR4_thickness
					    +HcalServices_outer_Cu_thickness/2.0),
					   0));


      // ========= Create Hcal Chamber (i.e. Layers) ==============================
      // It will be the sub volume for placing the slices.
      // Itself will be placed into the Hcal Endcap modules envelope.
      // ==========================================================================
      
      // create Layer (air) and place the slices (Polystyrene,Cu,FR4,air) into it. 
      // place the Layer into the Hcal Endcap Modules envelope (stavesMaterial).
      
      // First Hcal Chamber position, start after first radiator
      double layer_pos_y     = - box_half_y + Hcal_radiator_thickness;                      
      
      // Create Hcal Endcap Chamber without radiator
      // Place into the Hcal Encap module envelope, after each radiator 
      int layer_num = 1;
      for(xml_coll_t m(x_det,_U(layer)); m; ++m)  {
	xml_comp_t   x_layer = m;
	int          repeat = x_layer.repeat();          // Get number of layers.

	double layer_thickness = layering.layer(layer_num)->thickness();
	string layer_name      = envelopeVol_name+"_layer";
	DetElement  layer(stave_det,layer_name,det_id);
	
	// Active Layer box & volume
	double active_layer_dim_x = box_half_x - Hcal_endcap_lateral_structure_thickness - Hcal_endcap_layer_air_gap;
	double active_layer_dim_y = layer_thickness/2.0;
	double active_layer_dim_z = box_half_z;
	
	// Build chamber including air gap
	// The Layer will be filled with slices, 
	Volume layer_vol(layer_name, Box((active_layer_dim_x + Hcal_endcap_layer_air_gap),
					 active_layer_dim_y,active_layer_dim_z), air);

	LayeredCalorimeterData::Layer caloLayer ;
	caloLayer.cellSize0 = cell_sizeX;
	caloLayer.cellSize1 = cell_sizeY;
	
	// ========= Create sublayer slices =========================================
	// Create and place the slices into Layer
	// ==========================================================================
	
	// Create the slices (sublayers) within the Hcal Chamber.
	double slice_pos_y = -(layer_thickness / 2.0);
	int slice_number = 0;

	double nRadiationLengths=0.;
	double nInteractionLengths=0.;
	double thickness_sum=0;

	nRadiationLengths   = Hcal_radiator_thickness/(stavesMaterial.radLength());
	nInteractionLengths = Hcal_radiator_thickness/(stavesMaterial.intLength());
	thickness_sum       = Hcal_radiator_thickness;

	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  = theDetector.material(x_slice.materialStr());
	  DetElement slice(layer,_toString(slice_number,"slice%d"),det_id);
	  
	  slice_pos_y += slice_thickness / 2.0;
	  
	  // Slice volume & box
	  Volume slice_vol(slice_name,Box(active_layer_dim_x,slice_thickness/2.0,active_layer_dim_z),slice_material);
	  
	  nRadiationLengths   += slice_thickness/(2.*slice_material.radLength());
	  nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
	  thickness_sum       += slice_thickness/2;

	  if ( x_slice.isSensitive() ) {
	    sens.setType("calorimeter");
	    slice_vol.setSensitiveDetector(sens);

#if DD4HEP_VERSION_GE( 0, 15 )
	    //Store "inner" quantities
	    caloLayer.inner_nRadiationLengths = nRadiationLengths;
	    caloLayer.inner_nInteractionLengths = nInteractionLengths;
	    caloLayer.inner_thickness = thickness_sum;
	    //Store scintillator thickness
	    caloLayer.sensitive_thickness = slice_thickness;
#endif
	    //Reset counters to measure "outside" quantitites
	    nRadiationLengths=0.;
	    nInteractionLengths=0.;
	    thickness_sum = 0.;
	  }

	  nRadiationLengths += slice_thickness/(2.*slice_material.radLength());
	  nInteractionLengths += slice_thickness/(2.*slice_material.intLength());
	  thickness_sum += slice_thickness/2;

	  // Set region, limitset, and vis.
	  slice_vol.setAttributes(theDetector,x_slice.regionStr(),x_slice.limitsStr(),x_slice.visStr());
	  // slice PlacedVolume
	  PlacedVolume slice_phv = layer_vol.placeVolume(slice_vol,Position(0,slice_pos_y,0));
	  //slice_phv.addPhysVolID("slice",slice_number);
	  
	  slice.setPlacement(slice_phv);
	  // Increment Z position for next slice.
	  slice_pos_y += slice_thickness / 2.0;
	  // Increment slice number.
	  ++slice_number;             
	}
	// Set region, limitset, and vis.
	layer_vol.setAttributes(theDetector,x_layer.regionStr(),x_layer.limitsStr(),x_layer.visStr());

#if DD4HEP_VERSION_GE( 0, 15 )
	//Store "outer" quantities
	caloLayer.outer_nRadiationLengths = nRadiationLengths;
	caloLayer.outer_nInteractionLengths = nInteractionLengths;
	caloLayer.outer_thickness = thickness_sum;
#endif 	
	
	// ========= Place the Layer (i.e. Chamber) =================================
	// Place the Layer into the Hcal Endcap module envelope.
	// with the right position and rotation.
	// Registry the IDs (layer, stave, module).
	// Place the same layer 48 times into Endcap module
	// ==========================================================================
	
	for (int j = 0; j < repeat; j++)    {
	  
	  // Layer position in y within the Endcap Modules.
	  layer_pos_y += layer_thickness / 2.0;
	  
	  PlacedVolume layer_phv = envelopeVol.placeVolume(layer_vol,
							   Position(0,layer_pos_y,0));
	  // registry the ID of Layer, stave and module
	  layer_phv.addPhysVolID("layer",layer_num);

	  // then setPlacement for it.
	  layer.setPlacement(layer_phv);
	  
	  pVol = FEEModule.placeVolume(FEELayer,
				       Position(0,layer_pos_y,0));
	  //-----------------------------------------------------------------------------------------
	  if ( caloData->layers.size() < (unsigned int)repeat ) {

	    caloLayer.distance = HcalEndcap_min_z + box_half_y + layer_pos_y
	      - caloLayer.inner_thickness ; // Will be added later at "DDMarlinPandora/DDGeometryCreator.cc:226" to get center of sensitive element
	    caloLayer.absorberThickness = Hcal_radiator_thickness ;
	    
	    caloData->layers.push_back( caloLayer ) ;
	  }
	  //-----------------------------------------------------------------------------------------
	  
	  
	  // ===== Prepare for next layer (i.e. next Chamber) =========================
	  // Prepare the chamber placement position and the chamber dimension
	  // ==========================================================================
	  
	  // Increment the layer_pos_y
	  // Place Hcal Chamber after each radiator 
	  layer_pos_y += layer_thickness / 2.0;
	  layer_pos_y += Hcal_radiator_thickness;
	  ++layer_num;         
	}
	
	
      }
      
      
      // =========== Place Hcal Endcap envelope ===================================
      // Finally place the Hcal Endcap envelope into the world volume.
      // Registry the stave(up/down), module(left/right) and endcapID.
      // ==========================================================================
      
      // Acording to the number of staves and modules,
      // Place the same Hcal Endcap module volume into the world volume
      // with the right position and rotation.
      for(int stave_num=0;stave_num<2;stave_num++){
	
	double EndcapModule_pos_x = 0;
	double EndcapModule_pos_y = 0;
	double EndcapModule_pos_z = 0;
	double rot_EM = 0;

	double EndcapModule_center_pos_z = HcalEndcap_min_z + box_half_y;

	double FEEModule_pos_x = 0;
	double FEEModule_pos_y = 0;
	double FEEModule_pos_z = 0;
	double FEEModule_center_pos_z = HcalEndcap_min_z + box_half_y;
	
	switch (stave_num)
	  {
	  case 0 : 
	    EndcapModule_pos_x = x_offset;
	    EndcapModule_pos_y = y_offset;
	    FEEModule_pos_x = x_offset;
	    FEEModule_pos_y = y_offset + box_half_z + Hcal_endcap_services_module_width/2.0;
	    break;
	  case 1 : 
	    EndcapModule_pos_x = -x_offset;
	    EndcapModule_pos_y = -y_offset;
	    FEEModule_pos_x = -x_offset;
	    FEEModule_pos_y = -y_offset - box_half_z - Hcal_endcap_services_module_width/2.0;
	    break;
	  }
	
	for(int module_num=0;module_num<2;module_num++) {

	  int module_id = (module_num==0)? 0:6;
	  
	  rot_EM = (module_id==0)?(-M_PI/2.0):(M_PI/2.0);
	  
	  EndcapModule_pos_z = (module_id==0)? -EndcapModule_center_pos_z:EndcapModule_center_pos_z;

	  PlacedVolume env_phv = envelope.placeVolume(envelopeVol,
						      Transform3D(RotationX(rot_EM),
								  Translation3D(EndcapModule_pos_x,
										EndcapModule_pos_y,
										EndcapModule_pos_z)));
	  env_phv.addPhysVolID("tower",endcapID);	  
	  env_phv.addPhysVolID("stave",stave_num);   // y: up /down
	  env_phv.addPhysVolID("module",module_id); // z: -/+ 0/6
	  env_phv.addPhysVolID("system",det_id);


	  FEEModule_pos_z = (module_id==0)? -FEEModule_center_pos_z:FEEModule_center_pos_z;

	  if (!(endcapID==0))
	    env_phv = envelope.placeVolume(FEEModule,
					   Transform3D(RotationX(rot_EM),
						       Translation3D(FEEModule_pos_x,
								     FEEModule_pos_y,
								     FEEModule_pos_z)));


	  DetElement sd = (module_num==0&&stave_num==0) ? stave_det : stave_det.clone(_toString(module_id,"module%d")+_toString(stave_num,"stave%d"));	  
	  sd.setPlacement(env_phv);	  

	}
	
      }

    endcapID++;
      
    }
  
  sdet.addExtension< LayeredCalorimeterData >( caloData ) ;  
  
  return sdet;
}
예제 #9
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;
}