Back to home page

EIC code displayed by LXR

 
 

    


Warning, /tutorial-geometry-development-using-dd4hep/_episodes/03-modifying-geometry.md is written in an unsupported language. File is not indexed.

0001 ---
0002 title: "Modifying geometry"
0003 teaching: 20
0004 exercises: 40
0005 questions:
0006 - "How do we modify or add geometry defined in DD4hep?"
0007 objectives:
0008 - "Understand the structure of a geometry plugin source file."
0009 keypoints:
0010 - "To add or modify geometry, we add geometry plugins written in C++."
0011 ---
0012 Until now we have interacted with the read-only geometry that is stored inside the container. We will now move on to modifying this geometry. That requires that we work in a local copy of the geometry.
0013 
0014 ## Checking out your local copy of the geometry
0015 
0016 We will start with a local copy of the `epic` repository:
0017 ```console
0018 $ cd ~/eic/
0019 $ git clone https://github.com/eic/epic
0020 $ cd epic
0021 $ ls
0022 bin    calibrations    compact         macro      reports           scripts  templates
0023 build  CMakeLists.txt  configurations  README.md  requirements.txt  src      views
0024 ```
0025 
0026 As you can tell, the content of the repository itself is quite different from the installed version (as is often the case for other software as well). You will recognize, however, the `compact` directory with the subsystem xml files.
0027 
0028 ### Important : To follow this tutorial we will need to checkout an older version of the geometry
0029 ```console
0030 $ git checkout 25.08.0
0031 ```
0032 
0033 In order to compile and install the local geometry repository into a local directory, we can use the following commands:
0034 ```console
0035 $ cd ~/eic/epic
0036 $ cmake -B build -S . -DCMAKE_INSTALL_PREFIX=install
0037 $ cmake --build build -- install
0038 ```
0039 
0040 > Note: To speed up compilation, you may add the options `-j4` to the last command, where `4` corresponds to the number of cores you can use.
0041 {: .callout}
0042 
0043 This will install the geometry into the directory `~/eic/epic/install/` (and subdirectories). You will notice that `~/eic/epic/install/share/epic` contains the same files that we explored earlier inside the `/opt/detector` directory.
0044 
0045 As before, we now need to load the environment for this geometry. We can again use the `bin/thisepic.sh` script for this, though now we must use the one installed in our local installation directory:
0046 ```console
0047 $ source install/bin/thisepic.sh
0048 $ env | grep DETECTOR
0049 ```
0050 
0051 You should now see that the $DETECTOR_PATH variable points to your local install path.
0052 
0053 When we run `dd_web_display --export $DETECTOR_PATH/$DETECTOR_CONFIG.xml` now, we will use the local geometry parametrization and the local geometry plugins. (Note: As before, downloads of fieldmaps and calibration files will be necessary.)
0054 
0055 > Quick Exercise:
0056 > - Ensure that you have a local copy of the geometry repository which you can compile and install in a local directory.
0057 > - Verify that, after sourcing the `bin/thisepic.sh` script, the `DETECTOR_PATH` points to the correct local install directory.
0058 > - Verify that `dd_web_display` can indeed export the geometry for the detector subsystem configuration you used before.
0059 {: .challenge}
0060 
0061 ## Anatomy of a detector plugin
0062 
0063 ### Introduction
0064 
0065 It may be clear at this point how to make modifications to the parametrization, commit them to a branch in the local repository, and submit a pull request on GitHub to include them in the main branch.
0066 
0067 For the remainder of this lesson we will focus on the vertex barrel detector using the much reduced geometry configuration `epic_vertex_only.xml` so that any change made are more evident.
0068 
0069 What we have not covered yet is the discussion of what goes into a detector plugin. Let's look at the `epic_VertexBarrel` plugin we encountered earlier. The names of the plugins may not agree with the source files in the `src/` directory. This allows us to support multiple detector types with the same source files. In this case, `epic_VertexBarrel` is defined in the file `src/BarrelTrackerWithFrame_geo.cpp`.
0070 
0071 If you are not sure what fine in the `src` directory builds the plugin you are looking for, find the `type` in the xml detector definition and use the `grep` shell command.
0072 
0073 ```console
0074 $ grep -r epic_VertexBarrel src/
0075 src/BarrelTrackerWithFrame_geo.cpp:DECLARE_DETELEMENT(epic_VertexBarrel,    create_BarrelTrackerWithFrame)
0076 ```
0077 
0078 The DECLARE_DETELEMENT line, at the bottom of the `src/BarrelTrackerWithFrame_geo.cpp` file provides dd4hep with the link which tells it to call the `create_BarrelTrackerWithFrame` function when an xml detector definition is given the `epic_VertexBarrel` type.
0079 
0080 We now know that changing the content of the `create_BarrelTrackerWithFrame` function should be called when the `epic_vertex_only.xml` is used when dd4hep loads a geometry.
0081 
0082 ### Passing parameters from xml
0083 
0084 Next we will take a deeper dive into the `create_BarrelTrackerWithFrame` function to pick out the key components and how it is configured by the xml file `compact/tracking/vertex_barrel.xml`
0085 
0086 ```shell
0087 static Ref_t create_BarrelTrackerWithFrame(Detector& description, xml_h e, SensitiveDetector sens)
0088 ```
0089 
0090 here `description` contains access to the full tree defined from the main detector xml file. `e` contains the specific information contained within the xml tree within the `<detector>` blocks.
0091 
0092 There are a few ways to access these xml configuration parameters. Some xml elements have methods provided by dd4hep which allow direct access to the values, such as:
0093 
0094 ```shell
0095 51  Material                     air      = description.air();
0096 52  int                          det_id   = x_det.id();
0097 53  string                       det_name = x_det.nameStr();
0098 ```
0099 
0100 A list of tags dd4hep provides a conventient conversion method for can be found [here](https://dd4hep.web.cern.ch/dd4hep/reference/UnicodeValues_8h_source.html), (**There is almost certainly a better link**).
0101 
0102 More often you may be wanting to define a parameter by a tag of your choice or if you're wanting to be certain how it's being handled. The following (abridged) code is an example of how to access parameters of any name.
0103 
0104 ```shell
0105   for (xml_coll_t su(x_det, _U(support)); su; ++su) {
0106     xml_comp_t  x_support         = su;
0107     double      support_thickness = getAttrOrDefault(x_support, _U(thickness), 2.0 * mm);
0108     double      support_length    = getAttrOrDefault(x_support, _U(length), 2.0 * mm);
0109     double      support_rmin      = getAttrOrDefault(x_support, _U(rmin), 2.0 * mm);
0110     double      support_zstart    = getAttrOrDefault(x_support, _U(zstart), 2.0 * mm);
0111     std::string support_name      = getAttrOrDefault<std::string>(x_support, _Unicode(name), "support_tube");
0112     std::string support_vis       = getAttrOrDefault<std::string>(x_support, _Unicode(vis), "AnlRed");
0113   }
0114 ```
0115 
0116 The code loops over all `<support>` elements inside the `<detector>` block, located using `_U(support)` which interprets content as unicode. Inside each support node the `getAttrOrDefault` method sets the variables to the values given by the unicode `thickness` etc, or if they are not present in the support node sets a default value. If you want to require the parameter be defined in the xml file you could simply use `x_support.child(thickness)`.
0117 
0118 > Note:
0119 > - No support blocks actually currently appear in the `compact/tracking/vertex_barrel.xml` file so this block of code won't be run.
0120 > - In the xml file, there must be no white space between the parameter, = sign and the value.
0121 {: .callout}
0122 
0123 A fuller description of how to access and use the xml parameters is given in section [2.4 of the dd4hep manual](https://dd4hep.web.cern.ch/dd4hep/usermanuals/DD4hepManual/DD4hepManualch2.html#x3-210002.4)
0124 
0125 
0126 > Exercise:
0127 > - Create and chackout a new branch forked from the 25.08.0 branch.
0128 > - Add a new configuration parameter into `compact/tracking/vertex_barrel.xml` 
0129 > - Add code to `src/BarrelTrackerWithFrame_geo.cpp` which will read the new parameter and a print statement to display its value to the terminal.
0130 > - Recompile and rerun the `dd_web_display` step using `epic_vertex_only.xml` to verify that the printout statement has been added.
0131 > - Change the values in the xml and rerun to verify the value is being read properly.
0132 {: .challenge}
0133 
0134 > Note: Changes to the xml files in `install/share/epic/`... can made without recompiling the code, however they will be overwritten when the code is recompiled. In order to test temporary changes a top level configuration file can be copied to a path outside of `install`. This then needs to be edited to internally point to the compact file you are editing rather than the path given by the install, `${DETECTOR_PATH}`.
0135 {: .callout}
0136 
0137 ### Building new components
0138 
0139 DD4hep geometries are built in a similar hierarchical way to Geant4 geometries.
0140 
0141 > - Shape - 3D shape of the component. Can be a simple shape, made from boolean combinations of simple shapes or imported from CAD.
0142 > - Volume - Adds physical properties to the shape such as its material and if its sensitive.
0143 > - Placement - Position(s) that the volume is located within your detector geometry, this can be a position nested within another volume, containing unique identifier.
0144 
0145 We will start by looking at the shapes anv volumes. The most common shapes you are likely to find yourself using are `Box` and `Tube`. In `src/BarrelTrackerWithFrame_geo.cpp` both are used, `module_component` is defined as `Box`, the volume of which takes its material from the xml description:
0146 
0147 ```shell
0148 172      Box          c_box(x_comp.width() / 2, x_comp.length() / 2, x_comp.thickness() / 2);
0149 173      Volume       c_vol(c_nam, c_box, description.material(x_comp.materialStr()));
0150 ```
0151 
0152 `layer` volumes into which `module_component`s are later placed are described as a `Tube` but this time the volume is directly given the air material:
0153 
0154 ```shell
0155 239    Tube       lay_tub(x_barrel.inner_r(), x_barrel.outer_r(), x_barrel.z_length() / 2.0);
0156 240    Volume     lay_vol(lay_nam, lay_tub, air); // Create the layer envelope volume.
0157 ```
0158 
0159 In DD4hep there is a type of volume called an Assembly which contains volumes placed within itself but doesn't have a shape of its own. This is very useful for arranging volumes without needing a container volume defined with might have overlaps of their own where none are really present.
0160 
0161 > Notes: 
0162 > - The [DD4hep shapes](https://dd4hep.web.cern.ch/dd4hep/usermanuals/DD4hepManual/DD4hepManualch2.html#x3-290002.9) are based directly off the [ROOT geometry shapes](https://root.cern.ch/root/htmldoc/guides/users-guide/Geometry.html#shapes). An useful, probably out of date table comparing the ROOT, DD4hep and Geant4 shape names can be found here:  [https://github.com/AIDASoft/DD4hep/issues/588](https://github.com/AIDASoft/DD4hep/issues/588)
0163 > - DD4hep provides some shape plugins directly, so very basic geometries can be described directly in the xml with no additional code.
0164 {: .callout}
0165 
0166 > Exercise:
0167 > - Create a new simple volume within the hierachy in `src/BarrelTrackerWithFrame_geo.cpp`.
0168 > - Recompile and rerun the `dd_web_display` step using `epic_vertex_only.xml` locating the new shape(s) you have added in the ROOTJS viewer.
0169 > - Build a new tube volume which contains tracking layers.
0170 {: .challenge}
0171 
0172 ### Testing overlaps
0173 
0174 It is important for running the Geant4 simulation that geometries do not overlap. When stepping through the geometry a particle cannot know which volume it is in. An overlap check is run by GitHub when you request that your changes are merged into the main branch of the epic code.
0175 
0176 ```shell
0177 python scripts/checkOverlaps.py -c ${DETECTOR_PATH}/epic_vertex_only.xml
0178 ```
0179 
0180 > Exercise:
0181 > - Run the overlap check on your geometry with the added component.
0182 > - Change some parameters to add/remove the overlap and compare the output.
0183 {: .challenge}
0184 
0185 ### Readout 
0186 
0187 Placed volumes can be made sensitive by setting e.g.
0188 
0189 ```shell
0190 194  c_vol.setSensitiveDetector(sens);
0191 ```
0192 
0193 The type of information that will be saved to the output is defined usually as either:
0194 
0195 ```shell
0196   sens.setType("tracker");
0197   sens.setType("calorimeter");
0198 ```
0199 
0200 In the xml file the readout for the detector is passed in the `readout` field of the `detector` definition
0201 
0202 ```shell
0203     <detector
0204       id="VertexBarrel_0_ID"
0205       name="VertexBarrel"
0206       type="epic_VertexBarrel"
0207       readout="VertexBarrelHits"
0208       insideTrackingVolume="true">
0209 ```
0210 
0211 Where the readout name references a `readout` block also defined in the xml description
0212 
0213 ```shell
0214   <readouts>
0215     <readout name="VertexBarrelHits">
0216       <segmentation type="CartesianGridXY" grid_size_x="0.020*mm" grid_size_y="0.020*mm" />
0217       <id>system:8,layer:4,module:12,sensor:2,x:32:-16,y:-16</id>
0218     </readout>
0219   </readouts>
0220 ```
0221 
0222 Here the name given will appear as the name of the branch containing the hits in the output edm4hep file. dd4hep provides very convenient segmentation to the readout which allows hits in a readout volume to be divided up to locations beyond its natural boundaries, this is configures by the `x` and `y` parameters as well as the `grid_size`.
0223 
0224 The readout branch contains the information on the hit energy deposited, time of arival etc. which is usually found in a simulation output but in addition it contains `CellID` which is a 64 bit field which uniquely identifies the detector segmentation. 
0225 
0226 In the case of `VertexBarrelHits`, 8 bits always required by the system, 4 bits locate a specific layer, 12 a module, 2 a sensor and 32 the remaining x-y segmentation. In the code, dd4hep requires a separate hierachy of the geometry detector elements which are given tags and numbers so they can be uniquely identified. This hieracy doesn't have to strictly follow the way the volumes are themselves constructed.
0227 
0228 ```shell
0229   DetElement mod_elt(lay_elt, module_name, module);
0230   pv = lay_vol.placeVolume(module_env, tr);
0231   pv.addPhysVolID("module", module);
0232   mod_elt.setPlacement(pv);
0233 ```
0234 
0235 Here `mod_elt` is give the parent element `layer_elt`, the name and module number. Then the element is attached to a placed volume which has been given the physical volume id `module`.
0236 
0237 To run the simulation and produce an output file containing the detector hits you can use `npsim`. I would suggest only using a small sample of events given by the `--numberOfEvents` flag.
0238 
0239 ```shell
0240 $ npsim --runType run --compactFile $DETECTOR_PATH/epic_vertex_only.xml --inputFiles root://dtn-eic.jlab.org//volatile/eic/EPIC/EVGEN/SIDIS/pythia6-eic/1.0.0/18x275/q2_0to1/pythia_ep_noradcor_18x275_q2_0.000000001_1.0_run9.ab.hepmc3.tree.root --numberOfEvents 100 --outputFile test.edm4hep.root
0241 ```
0242 
0243 Inside the output file `test.edm4hep.root` there should be 4 trees:
0244 
0245 ```shell
0246 events
0247 runs
0248 metadata
0249 podio_metadata
0250 ```
0251 
0252 The events tree contains the readout of your detectors, in this example it should contain only 7 branches,
0253 
0254 ```shell
0255 MCHeader
0256 MCParticles
0257 _MCParticles_parents
0258 _MCParticles_daughters
0259 VertexBarrelHits
0260 _VertexBarrelHits_MCParticle
0261 ```
0262 
0263 The `MCParticles` branch contains information on all of the particles described by your generator and any secondaries produced in the simulation. `VertexBarrelHits` contains the hit information of the vertex barrel and has the association branch `_VertexBarrelHits_MCParticle` which references the particle in the `MCParticles` branch which caused the hit.
0264 
0265 > Exercise:
0266 > - Run the simulation with a small dataset using
0267 > - Look at the output datafiles usig your favorate ROOT browser.
0268 > - Change the sensitive type of the `BarrelTrackerWithFrame_geo.cpp` and compare the output to what you first saw.
0269 > - Try to make your new tube volume sensitive by setting as sensitive and adding a `DetElement` and giving it the necessary `addPhysVolID` values not currently used by the tracker.
0270 > - Open ended - Move your new Tube detector into a separate src file (Or create a new simple detector) and include it separately in the xml definition and readout. 
0271 
0272 ### ACTS?
0273 
0274 ToDo