diff --git a/src/docs/part2/adding_detectors.md b/src/docs/part2/adding_detectors.md index 969f68813815872aa35db14be9214aea22d8e3c0..1529eba1bb87af69e5873df61afa189bed89ba81 100644 --- a/src/docs/part2/adding_detectors.md +++ b/src/docs/part2/adding_detectors.md @@ -16,24 +16,24 @@ title: 'Tutorial Part 2: Modifying and Adding Detectors ' + [Running the scripts](#running-the-scripts) + [To Do](#to-do) -Introduction ------------- +## Setup -To a newcomer it might not be immediately clear why a *generic detector -library* based on `dd4hep` is a good solution to the 'simulation and -reconstruction geometry problem'. However, with the following examples we -intend to show how generic detector libraries can be used to access the -geometry information in simulation and reconstruction. +Note all these commands assume you are in an `eic-shell` singularity session. -We try to emphasize in the following examples that dd4hep (plus a data model) -allows the software components to be only loosely decoupled. This allows for a -'no framework' framework approach where the emphasis is on the underlying -algorithms used (or being designed). Furthermore, using ROOT's TDataframe, the -details of each task are made manifest. +### Clone part2 repo -Furthermore, the 'no framework' framework allows for the each step to be -executed using any tool available, however, the IO and data model should be -fixed. +```bash +git clone https://eicweb.phy.anl.gov/EIC/tutorials/ip6_tutorial_2.git part2 +cd part2 +``` + +### Compile the detector library + +```bash +mkdir build +cmake ../. -DCMAKE_INSTALL_PREFIX=../../local +make -j4 install +``` How to build a detector from scratch @@ -48,38 +48,35 @@ make the following assumptions. ### Compiling a new detector -For this tutorial we will build a simplified Roman Pot detector. +For this tutorial we will build a more detailed GEM detector. We will discuss the detector built in the source file -`src/MyDetector.cpp`. -To compile this detector into the GenericDetectors library the detector needs -to be added to the list of sources in the cmake file -`CMakeLists.txt`. +`src/TrapEndcapTracker_geo.cpp`. +In the `CMakeLists.txt` it adds all cpp files, otherwise we would do ```bash dd4hep_add_plugin(${a_lib_name} SOURCES - src/BeamPipe_geo.cpp + src/TrapEndcapTracker_geo.cpp ... - src/SimpleRomanPot_geo.cpp # add this line ) ``` -### Building the geometry +### Building the geometry (cpp + xml) -The work of defining the detector is done in a function (here called -`build_detector`) that is registered using the DD4hep plugin macro +The work of constructing the detector is done in a static function (here called +`create_detector`) that is registered using the DD4hep plugin macro `DECLARE_DETELEMENT`. ```cpp -static Ref_t build_detector(Detector& dtor, xml_h e, SensitiveDetector sens) +static Ref_t create_detector(Detector& dtor, xml_h e, SensitiveDetector sens) { xml_det_t x_det = e; Material air = dtor.air(); ... } -DECLARE_DETELEMENT(SimpleRomanPot, build_detector) +DECLARE_DETELEMENT(MyGEMTrackerEndcap, build_detector) ``` -The argument signature of the `build_detector` is: +The argument signature of the `create_detector` is: - `Detector& dtor`: This handle provides the main hook to the detector tree (`dd4hep::Detector`). - `xml_h e`: Handle to the XML `<detector>` tag associated with the detector in the "compact" detector description file (more on this later). This provides @@ -87,24 +84,31 @@ The argument signature of the `build_detector` is: - `SensitiveDetector sens`: The sensitive detector to be assigned to the sensitive volumes/elements of the detector. -The DD4hep plugin macro `DECLARE_DETELEMENT(MyDetector, build_detector)` +The DD4hep plugin macro `DECLARE_DETELEMENT(MyGEMTrackerEndcap, build_detector)` stamps out the necessary boiler plate code to register a new detector called -`SimpleRomanPot` which is build by calling `build_detector`. +`MyGEMTrackerEndcap` which is build by calling `create_detector`. #### Compact detector description entry element The `<detector>` tag defines a new instance of a detector and requires the -attributes "id", "name", and "type". For example: +attributes "id", "name", and "type". For example from part 1: ```xml -<detector id="1" name="aNeatDetector" type="MyDetector" - vis="RedVis" readout="MyDetectorHits" zoffset="1.0*m"> -</detector> + <detector id="2" name="GEMTracker" vis="RedVis" type="my_GEMTracker" readout="GEMTrackerHits" > + <layer id="1" z="-100 *cm" inner_r="40*cm" outer_r="120*cm" phi0_offset="0.0*deg" /> + <layer id="2" z="-80 *cm" inner_r="30*cm" outer_r="90*cm" phi0_offset="0.0*deg" /> + <layer id="3" z="-60 *cm" inner_r="20*cm" outer_r="70*cm" phi0_offset="0.0*deg" /> + <layer id="4" z="-40 *cm" inner_r="10*cm" outer_r="20.0*cm" phi0_offset="0.0*deg" /> + <layer id="5" z=" 40 *cm" inner_r="10*cm" outer_r="20.0*cm" phi0_offset="0.0*deg" /> + <layer id="6" z=" 60 *cm" inner_r="25*cm" outer_r="70.0*cm" phi0_offset="0.0*deg" /> + <layer id="7" z=" 80 *cm" inner_r="30*cm" outer_r="90.0*cm" phi0_offset="0.0*deg" /> + <layer id="8" z="100 *cm" inner_r="40*cm" outer_r="100.0*cm" phi0_offset="0.0*deg" /> + </detector> ```` -This defines an instance of the detector named "aNeatDetector" of type -"MyDetector" (i.e. the type-name given in the first argument of the DD4hep -`DECLARE_DETELEMENT` macro) and with id=1. Each `<detector>` must have a unique id. +This defines an instance of the detector named "GEMTracker" of type +"my_GEMTracker" (i.e. the type-name given in the first argument of the DD4hep +`DECLARE_DETELEMENT` macro) and with id=2. Each `<detector>` must have a unique id. The additional attributes (vis, readout, zoffset) are optional. The detector tag is provided as the second argument in the `build_detector` @@ -135,6 +139,8 @@ default value. For example: ```cpp double radius = ( x_det.hasAttr(_Unicode(radius)) ) ? x_det.attr<double>(_Unicode(radius)) : 5.0*dd4hep::cm; +//or +double radius = dd4hep::getAttrOrDefault(x_det, _Unicode(radius), 5.0*dd4hep::cm) ``` This provides a default radius of 5 cm when `x_det` does not have a "radius" @@ -143,244 +149,170 @@ attribute defined. We will return to this later. #### Critical parts of build_detector -We will now look at parts of the source file `src/GenericDetectors/src/SimpleRomanPot_geo.cpp`. +We will now look at the function in `src/TrapEndcapTracker_geo.cpp`. +Note that **this is not a good example to copy**, rather it is a simple example to walk through. ```cpp -static Ref_t build_detector(Detector& dtor, xml_h e, SensitiveDetector sens) +static Ref_t create_detector(Detector& lcdd, xml_h e, SensitiveDetector sens) { - xml_det_t x_det = e; - Material air = dtor.air(); - Material carbon = dtor.material("CarbonFiber"); - Material silicon = dtor.material("SiliconOxide"); - Material aluminum = dtor.material("Aluminum"); - Material vacuum = dtor.material("Vacuum"); - Material supp_mat = carbon; - Material sens_mat = silicon; - int det_id = x_det.id(); // id=1 - string det_name = x_det.nameStr(); // "MyRomanPot" -``` - - -### What materials exist - -To browse the list of materials and elements (other than looking in the compact files), go to -[geo viewer](https://eic.phy.anl.gov/geoviewer/index.htm?file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/detector_geo_full.root?job=report) -and scroll through the materials. - - -Here we are grabbing the materials that are assumed to be already defined. Also -we are getting the detector id and name defined in the `detector` tag. - -Next we define an [Assembly -volume](http://test-dd4hep.web.cern.ch/test-dd4hep/doxygen/html/classdd4hep_1_1_assembly.html). -Here we also stumble upon the important class -[`dd4hep::DetElement`](http://test-dd4hep.web.cern.ch/test-dd4hep/doxygen/html/classdd4hep_1_1_det_element.html#details). -It is a means of providing the detector hierarchy/tree, but doesn't necessarily -have to map exactly to detector geometry. However, it typically will typically -parallel the geometry (and probably should). - -```cpp -string module_name = "RomanPot"; -Assembly assembly(det_name + "_assembly"); -DetElement sdet( det_name, det_id); -sens.setType("tracker"); -``` -The last line sets the `SensitiveDetector sens` argument to be the tracker type -(which is a DD4hep built-in). We will soon assign this to sensitive volumes. -`sdet` is associated with the mother detector element by the constructor which -looks up the detector name (here "MyRomanPot"). - -```cpp -double z_offset = (x_det.hasAttr(_Unicode(zoffset))) ? x_det.attr<double>(_Unicode(zoffset)) : 0.0; -double thickness = (x_det.hasAttr(_Unicode(thickness))) ? x_det.attr<double>(_Unicode(thickness)) : 0.01*dd4hep::cm; -``` -Here we grab attributes and provide default values. We continue with default -values that could also be define through attributes, however, we will want to -add child elements of the detector tag (so the attributes does not grow too -long). - -```cpp -double rp_chamber_thickness = 5.0*dd4hep::mm; -double rp_chamber_radius = 5.0*dd4hep::cm; -double rp_chamber_length = 50.0*dd4hep::cm; -Tube rp_beam_pipe_tube(rp_chamber_radius, rp_chamber_radius+rp_chamber_thickness, rp_chamber_length/2.0); -Tube rp_beam_vacuum_tube(0.0, rp_chamber_radius+rp_chamber_thickness, rp_chamber_length/2.0); -Tube rp_beam_vacuum_tube2(0.0, rp_chamber_radius, rp_chamber_length/2.0); - -double rp_detector_tube_radius = 2.5*dd4hep::cm; -double rp_detector_tube_length = 20.0*dd4hep::cm; -Tube rp_detector_tube(rp_detector_tube_radius, rp_detector_tube_radius+rp_chamber_thickness, rp_detector_tube_length/2.0); -Tube rp_detector_vacuum_tube(0.0, rp_detector_tube_radius+rp_chamber_thickness, rp_detector_tube_length/2.0); -Tube rp_detector_vacuum_tube2(0.0, rp_detector_tube_radius, rp_detector_tube_length/2.0); - -ROOT::Math::Rotation3D rot_X( ROOT::Math::RotationX(M_PI/2.0) ); -ROOT::Math::Rotation3D rot_Y( ROOT::Math::RotationY(M_PI/2.0) ); - -UnionSolid rp_chamber_tee1(rp_beam_vacuum_tube, rp_detector_vacuum_tube, rot_X); -UnionSolid rp_chamber_tee12(rp_chamber_tee1, rp_detector_vacuum_tube, rot_Y); - -UnionSolid rp_chamber_tee2(rp_beam_vacuum_tube2, rp_detector_vacuum_tube2, rot_X); -UnionSolid rp_chamber_tee22(rp_chamber_tee2, rp_detector_vacuum_tube2, rot_Y); - -SubtractionSolid sub1(rp_chamber_tee12,rp_chamber_tee22); -Volume rp_chamber_vol("rp_chamber_walls_vol", sub1, aluminum); -Volume rp_vacuum_vol("rp_chamber_vacuum_vol", rp_chamber_tee22, vacuum); -``` -The above code builds the up the two solids associated with 3 tubes -intersecting. One volume is the aluminum vacuum chamber walls and the other is -the vacuum contained within this envelope. - -Next we must place these two volumes in the assembly volume (which is just an -empty container-like volume. The PlacedVolume is then associated with a -BitFieldValue in the readout's BitField64 readout string. In this case the -"layer" BitFieldValue. The BitField64 is used to construct unique VolumeIDs and -CellIDs for PlacedVolumes and Segmentations respectively. + typedef vector<PlacedVolume> Placements; -```cpp - PlacedVolume pv; - pv = assembly.placeVolume( rp_chamber_vol ); - pv = assembly.placeVolume( rp_vacuum_vol ); - pv.addPhysVolID( "layer", 2 ); -``` + xml_det_t x_det = e; + Material air = lcdd.air(); + Material carbon = lcdd.material("CarbonFiber"); + Material silicon = lcdd.material("SiliconOxide"); + int det_id = x_det.id(); + string det_name = x_det.nameStr(); + PlacedVolume pv; -Set the PlacedVolume BitFieldValue ID. "2" in this case. + DetElement sdet(det_name, det_id); + Assembly assembly(det_name+"_assembly"); -```cpp - double supp_x_half = 1.0*dd4hep::cm; - double supp_y_half = 1.0*dd4hep::cm; - double supp_thickness = 1.0*dd4hep::mm; - double supp_gap_half_width = 1.0*dd4hep::mm; - double sens_thickness = 0.1*dd4hep::mm; + sens.setType("tracker"); + string module_name = "GEM"; - Box supp_box( supp_x_half, supp_y_half, supp_thickness/2.0 ); - Box sens_box( supp_x_half-supp_gap_half_width, supp_y_half-supp_gap_half_width, sens_thickness/2.0 ); + double thickness = 0.01*dd4hep::cm; -``` + int N_layers = 0; -Next we define vectors which are used to define a "surface" (which will later -generate simulation tracker hits). + for(xml_coll_t lay( x_det, _U(layer) ); lay; ++lay, ++N_layers) { + xml_comp_t x_layer = lay; + double inner_r = x_layer.attr<double>( _Unicode(inner_r) ) ; + double outer_r = x_layer.attr<double>( _Unicode(outer_r) ) ; + double phi0_offset = x_layer.attr<double>( _Unicode(phi0_offset) ) ; + double z = x_layer.attr<double>( _Unicode(z) ) ; + int layer_id = x_layer.id();//attr<double>( _Unicode(z) ) ; + string layer_name = std::string("gem_layer") + std::to_string(layer_id); + + Tube gem_layer(inner_r, outer_r, thickness / 2.0); + Volume gem_layer_vol("gem_layer_vol", gem_layer, carbon); -```cpp - // create a measurement plane for the tracking surface attched to the sensitive volume - Vector3D u( 1. , 0. , 0. ) ; - Vector3D v( 0. , 1. , 0. ) ; - Vector3D n( 0. , 0. , 1. ) ; - //Vector3D o( 0. , 0. , 0. ) ; - - // compute the inner and outer thicknesses that need to be assigned to the tracking surface - // depending on wether the support is above or below the sensor - // The tracking surface is used in reconstruction. It provides material thickness - // and radation lengths needed for various algorithms, routines, etc. - double inner_thickness = supp_thickness/2.0; - double outer_thickness = supp_thickness/2.0; - double z_shift = 5.0*dd4hep::mm; - double xy_shift = 15.0*dd4hep::mm; - - SurfaceType type( SurfaceType::Sensitive ) ; -``` + gem_layer_vol.setSensitiveDetector(sens); -We now define a simple rectangular pixel sensor. This will be the first of -four: two will come in along the x axis and two along the y axis. + DetElement layer_DE( sdet, _toString(layer_id,"layer%d"), layer_id ); -```cpp - // ------------- x1 - Volume support1_vol( "xsenseor_supp", supp_box, supp_mat ); - Volume sensor1_vol( "xsenseor_sens", sens_box, sens_mat ); - VolPlane surf1( sensor1_vol, type, inner_thickness , outer_thickness, u,v,n); - sensor1_vol.setSensitiveDetector(sens); -``` -The code above builds two volumes one which will contain the sensitive volume. -The sensitive volume is assigned to be a sensitive detector. + pv = assembly.placeVolume( gem_layer_vol, Transform3D(RotationZ(phi0_offset),Position(0.0,0.0,z)) ); + pv.addPhysVolID( "layer", layer_id ); + layer_DE.setPlacement(pv); -```cpp - DetElement layer1_DE( sdet, "layer1_DE", 1 ); - pv = rp_vacuum_vol.placeVolume( support1_vol, Position(xy_shift,0, -z_shift) ); - pv.addPhysVolID("layer", 1 ); - layer1_DE.setPlacement( pv ) ; -``` -The above creates a new DetElement, places the support volume in the vacuum, -sets this PlacedVolume to associate with the layer bitfield, and adds the PV to -the DetElement. Note the DetElement is constructed with the parent element -(sdet) being the first argument. In this way it is clear we are building, -(semi-)parallel to the geometry, a detector element hierarchy. - -```cpp - DetElement mod1( layer1_DE , "module_1", 1 ); - pv = support1_vol.placeVolume(sensor1_vol, Position(0,0,0)); - pv.addPhysVolID("module", 1 ); - mod1.setPlacement( pv ); -``` -This creates the module DetElement and places the sensitive volume in the -support volume (already placed). It also assocates the pv with the module -bitfield and then adds the PV to the DetElement. - -The above is repeated for the three remaining sensitive elements. + } -Finally we get the top level volume to place the assemble volume. Note we are -using the zoffset. This PV is then associated with the top level "system" -bitfieldvalue. + sdet.setAttributes(lcdd, assembly,x_det.regionStr(),x_det.limitsStr(),x_det.visStr()); -```cpp - pv = dtor.pickMotherVolume(sdet).placeVolume(assembly, Position(0,0,z_offset)); + pv = lcdd.pickMotherVolume(sdet).placeVolume(assembly); pv.addPhysVolID("system", det_id); // Set the subdetector system ID. sdet.setPlacement(pv); assembly->GetShape()->ComputeBBox() ; return sdet; } - ``` +Here is the XML again: +```xml + <detector id="2" name="GEMTracker" vis="RedVis" type="my_GEMTracker" readout="GEMTrackerHits" > + <layer id="1" z="-100 *cm" inner_r="40*cm" outer_r="120*cm" phi0_offset="0.0*deg" /> + <layer id="2" z="-80 *cm" inner_r="30*cm" outer_r="90*cm" phi0_offset="0.0*deg" /> + <layer id="3" z="-60 *cm" inner_r="20*cm" outer_r="70*cm" phi0_offset="0.0*deg" /> + <layer id="4" z="-40 *cm" inner_r="10*cm" outer_r="20.0*cm" phi0_offset="0.0*deg" /> + <layer id="5" z=" 40 *cm" inner_r="10*cm" outer_r="20.0*cm" phi0_offset="0.0*deg" /> + <layer id="6" z=" 60 *cm" inner_r="25*cm" outer_r="70.0*cm" phi0_offset="0.0*deg" /> + <layer id="7" z=" 80 *cm" inner_r="30*cm" outer_r="90.0*cm" phi0_offset="0.0*deg" /> + <layer id="8" z="100 *cm" inner_r="40*cm" outer_r="100.0*cm" phi0_offset="0.0*deg" /> + </detector> +```` -The Readout and Bit Fields --------------------------- +What problems do you see with this construction? +- rigid +- hard coded +- no defaults +- single material +- lots more... -Simple Reconstruction Overview of scripts ---------------------------------------- +### What materials exist? -In the examples here we use ROOT and the LCIO data model. -The following scripts should be executed in order: +To browse the list of materials and elements (other than looking in the compact files), go to +[geo viewer](https://eic.phy.anl.gov/geoviewer/index.htm?file=https://eicweb.phy.anl.gov/api/v4/projects/473/jobs/artifacts/master/raw/geo/detector_geo_full.root?job=report) +and scroll through the materials. + -1. `run_example` : bash script that runs `ddsim` with the Geant4 macro file - `gps.mac` and the input geometry defined in `gem_tracker_disc.xml`. -2. `scripts/example_hit_position.cxx` : ROOT script showing how to use both the - "segmentation" and "surface" geometry to get the hit position information. -3. `scripts/example_cell_size.cxx` : ROOT script showing how information about - the geometry beyond the position. -4. `scripts/example_digi.cxx` : ROOT script performing a crude digitization of - gem tracker hits. -5. `scripts/example_hit_recon.cxx` : ROOT script that shows how to to use - dd4hep to lookup a 'segment' (cell) position based on the unique cellID - attached to the hit object. -6. `scripts/example_tracking.cxx` : ROOT script showing how to use the - `GenFind` finding library along with `GenFit` to produce tracks. +Here we are grabbing the materials that are assumed to be already defined. Also +we are getting the detector id and name defined in the `detector` tag. -### Dependencies +Next we define an [Assembly +volume](http://test-dd4hep.web.cern.ch/test-dd4hep/doxygen/html/classdd4hep_1_1_assembly.html). +Here we also stumble upon the important class +[`dd4hep::DetElement`](http://test-dd4hep.web.cern.ch/test-dd4hep/doxygen/html/classdd4hep_1_1_det_element.html#details). +It is a means of providing the detector hierarchy/tree, but doesn't necessarily +have to map exactly to detector geometry. However, it typically will typically +parallel the geometry (and probably should). -There are some library dependencies: -- DD4hep -- lcgeo -- GenFind -- GenFit -- NPdet +## A more detailed GEM Tracker +Uncomment the include line in `gem_tracker.xml` -### Running the scripts +```xml + <include ref="compact/gem_tracker_endcap.xml"/> +``` +And have a look at the detector part of the compact file. -```bash -./run_example -root scripts/example_digi.cxx++ -root scripts/example_hit_position.cxx++ # no output -root scripts/example_cell_size.cxx++ # no output -root scripts/example_hit_recon.cxx++ -root scripts/example_tracking.cxx++ +```xml +<detector + id="GEMTrackerEndcap_ID" + name="GEMTrackerEndcap" + type="MyGEMTrackerEndcap" + readout="GEMTrackerEndcapHits" + vis="BlueVis" + reflect="false"> + <module name="GEMModule1" vis="GreenVis"> + <trd x1="GEMTrackerEndcapFoilX1/2.0" x2="GEMTrackerEndcapFoilX2/2.0" z="GEMTrackerEndcapFoilY/2"/> + <comment> Going from HV side to readout side</comment> + <module_component thickness="0.127 * mm" material="Mylar"/> + <module_component thickness="50.0*um" material="Kapton" name="entrance_window"/> + <module_component thickness=" 3.0*mm" material="Ar10CO2" name="entrance region" /> + <module_component thickness="50.0*um" material="Kapton"/> + <module_component thickness=" 3.0*um" material="Copper"/> + <module_component thickness=" 3.0*mm" material="Ar10CO2" name="drift region"/> + <module_component thickness="30.0*um" material="Kapton" name="gem_foil"/> + <module_component thickness=" 3.0*um" material="Copper" name="gem_foil_Cu"/> + <module_component thickness=" 2.0*mm" material="Ar10CO2" name="transfer region I"/> + <module_component thickness="30.0*um" material="Kapton" name="gem_foil"/> + <module_component thickness=" 3.0*um" material="Copper" name="gem_foil_Cu"/> + <module_component thickness=" 2.0*mm" material="Ar10CO2" name="transfer region II"/> + <module_component thickness="30.0*um" material="Kapton" name="gem_foil"/> + <module_component thickness=" 3.0*um" material="Copper" name="gem_foil_Cu"/> + <module_component thickness=" 2.0*mm" material="Ar10CO2" name="induction region"/> + <module_component thickness="30.0*um" material="Kapton" name="readout" sensitive="true"/> + <module_component thickness=" 3.0*um" material="Copper" name="readout_Cu"/> + <module_component thickness="127.0*um" material="Mylar"/> + <module_component thickness="200.0*um" material="Epoxy" sensitive="true" vis="GreenVis"/> + </module> + <module name="GEMSupportModule1" vis="OrangeVis"> + <trd x1="GEMTrackerEndcapFoilX2/2.0" x2="GEMTrackerEndcapFoilX1/2.0" z="GEMTrackerEndcapFrameBotEdge_width"/> + <module_component thickness="GEMTrackerEndcapFrame_thickness" material="Mylar"/> + </module> + <comment> + GEMSupportModule2 is the support in between gem foils. + </comment> + <module name="GEMSupportModule2" vis="OrangeVis"> + <trd x1="GEMTrackerEndcapFrameSideEdge_width" x2="GEMTrackerEndcapFrameSideEdge_width" z="GEMTrackerEndcapFoilY/2"/> + <module_component thickness="4.0*mm" material="Mylar"/> + </module> + <layer id="1" > + <ring vis="PurpleVis" + r="GEMTrackerEndcapFoil_rmin+GEMTrackerEndcapFoilY/2.0" + zstart="GEMTrackerEndcap_zmin + 0.5*GEMTrackerEndcapLayer_thickness" + nmodules="12" dz="10 * mm" module="GEMModule1" /> + <ring vis="PurpleVis" phi0="15.0*degree" + r="GEMTrackerEndcapFoil_rmin+GEMTrackerEndcapFoilY/2.0" + zstart="GEMTrackerEndcap_zmin + 0.5*GEMTrackerEndcapLayer_thickness" + nmodules="12" dz="0 * mm" module="GEMSupportModule2" /> + </layer> +</detector> ``` -### To Do +Here you see a different strategy: build a module, then build layers constructed from the module. -- Show how to build a detector -- Finish track fitting script. -- Create example for basic PFA usage