Skip to content
Snippets Groups Projects
Commit 1e4688d6 authored by Riccardo Maria Bianchi's avatar Riccardo Maria Bianchi :sunny:
Browse files

Merge remote-tracking branch 'origin/main' into improve-docs-chep

parents 39ce637b 569e5896
No related branches found
No related tags found
No related merge requests found
Pipeline #8426143 failed
Showing
with 311 additions and 70 deletions
......@@ -119,18 +119,35 @@ void SiliconSystemPlugin::create(GeoVPhysVol *world, bool /*publish*/) {
GeoLogVol *boxLog = new GeoLogVol("BoxLog",boxShape,Air);
GeoPhysVol *worldBOX = new GeoPhysVol(boxLog);
for (int k=0;k<3;k++) {
for (int j=0;j<3;j++) {
GeoBox *box = new GeoBox (0.1,(j+1)*1.7,20);
GeoLogVol *boxLog=new GeoLogVol("SiDet", box, Aluminium);
GeoBox *box1 = new GeoBox (0.1,1*1.7,20);
GeoLogVol *boxLog1 = new GeoLogVol("SiDet", box1, Aluminium);
GeoBox *box2 = new GeoBox (0.1,2*1.7,20);
GeoLogVol *boxLog2 = new GeoLogVol("SiDet", box2, Aluminium);
GeoRectSurface* rectSurface = new GeoRectSurface((j+1)*1.9, 20.2);
GeoVSurface* surf = new GeoVSurface(rectSurface);
GeoBox *box3 = new GeoBox (0.1,3*1.7,20);
GeoLogVol *boxLog3 = new GeoLogVol("SiDet", box3, Aluminium);
GeoRectSurface* rectSurface1 = new GeoRectSurface(1*1.9, 20.2);
GeoRectSurface* rectSurface2 = new GeoRectSurface(2*1.9, 20.2);
GeoRectSurface* rectSurface3 = new GeoRectSurface(3*1.9, 20.2);
for (int k=0;k<3;k++) {
for (int j=0;j<3;j++) {
GeoLogVol* boxLog;
if(j==0) boxLog = boxLog1;
else if(j==1) boxLog = boxLog2;
else boxLog = boxLog3;
GeoRectSurface* rectSurface;
if(j==0) rectSurface = rectSurface1;
else if(j==1) rectSurface = rectSurface2;
else rectSurface = rectSurface3;
for (int i=0;i<16;i++) {
double theta = i/16.0*2*M_PI;
GeoFullPhysVol *boxPhys=new GeoFullPhysVol(boxLog);
GeoVSurface* surf = new GeoVSurface(rectSurface);
// Initial transform is very tricky. Because the Virtual surface is always facing to Z axis initially.
GeoAlignableTransform* xf0 = new GeoAlignableTransform(GeoTrf::RotateZ3D(theta)*GeoTrf::TranslateX3D((j+1)*8.0+0.4*(i%2))*GeoTrf::TranslateX3D(0.5)*GeoTrf::TranslateZ3D((k-1)*44.0)*GeoTrf::RotateX3D(M_PI/2.0)*GeoTrf::RotateY3D(M_PI/2.0));
GeoAlignableTransform *xf = new GeoAlignableTransform(GeoTrf::RotateZ3D(theta)*GeoTrf::TranslateX3D((j+1)*8.0+0.4*(i%2)));
......@@ -163,14 +180,14 @@ void SiliconSystemPlugin::create(GeoVPhysVol *world, bool /*publish*/) {
}
}
double L=10.0;
GeoTrapezoidSurface* trapezoid = new GeoTrapezoidSurface(1.2, 5.2, L);
GeoTrd *trd=new GeoTrd(.2, .2, 1, 5, L);
GeoLogVol *trdLog=new GeoLogVol("SiDetEnd", trd,Aluminium);
for (int j=0;j<16;j++) {
for (int i=-1;i<2;i+=2) {
double L=10.0;
GeoTrapezoidSurface* trapezoid = new GeoTrapezoidSurface(1.2, 5.2, L);
GeoVSurface* surf = new GeoVSurface(trapezoid);
GeoTrd *trd=new GeoTrd(.2, .2, 1, 5, L);
GeoLogVol *trdLog=new GeoLogVol("SiDetEnd", trd,Aluminium);
GeoFullPhysVol *trdPhys=new GeoFullPhysVol(trdLog);
GeoTransform *sf0=new GeoTransform(GeoTrf::RotateY3D(j*2*M_PI/16.0)*GeoTrf::RotateX3D(M_PI/2.0)*GeoTrf::TranslateY3D(1.5*L));
......
......@@ -122,7 +122,7 @@ cmake -S "${SCRIPT_DIR}/.." -B geomodel-build \
-DCMAKE_MAKE_PROGRAM="$NINJA" \
-DCMAKE_CXX_FLAGS="$EXTRA_FLAGS" \
-DCMAKE_INSTALL_PREFIX=$gm_install_dir \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_BUILD_TYPE=Release \
-DGEOMODEL_BUILD_TOOLS=ON \
heading "Build GeoModel"
......@@ -196,6 +196,7 @@ cmake "$ATHENA_SOURCE/Projects/WorkDir" \
-DCMAKE_MAKE_PROGRAM="$NINJA" \
-DCMAKE_CXX_FLAGS="$EXTRA_FLAGS -isystem ${gm_install_dir}/include" \
-DATLAS_PACKAGE_FILTER_FILE="$package_filters" \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=$install_dir
popd
......
# GeoModelCat
GeoModelCat (`gmcat`) is a command line tool that allows to concatenate different geometry files into a single final SQLite file. It is possible to concatenate plugins (.dylib/.so) and/or SQLite (.db) files.
*gmcat* has the following parameters:
``` bash
-o [MANDATORY] Name of the output .db file
-v [OPTIONAL] Print verbose output to the screen (default: direct verbose output to /tmp)
-g [OPTIONAL] Path to the local GeoModelATLAS repository (default: .)
```
## Examples
In order to combine three different plugins into one single detector file one need to call gmcat in the following way:
```bash
./gmcat libPixelGeoPlugin.0.0.1.dylib libSCTGeoPlugin.0.0.1.dylib libTRTGeoPlugin.0.0.1.dylib -o InnerDetector.db
```
<!--To convert a GDML geometry and save it in SQLite format with *gdml2gm* :-->
<!--``` bash-->
<!--./gdml2gm -f myGeometry.gdml -o myGeometry.db-->
<!--``` -->
<!---->
<!--To visualize a GDML geometry with *gmex*, the user has to set the following environment variable: GDML_FILE_NAME. It has to point to the GDML file that the user wants to plug into *gmex*. Then it is sufficient to call gmex together with the *libGDMLtoGM.dylib/so* library:-->
<!---->
<!--``` bash-->
<!--export GDML_FILE_NAME=<path-to-my-geometry-file>/myGeometry.gdml-->
<!--./gmex ../lib/libGDMLtoGM.dylib -->
<!--``` -->
# GeoModelStatistics
GeoModelStatistics (`gmstatistics`) is a command line tool that allows to extract information on the memory footprint of your detector description code. It takes one or more plugins (.dylib/.so) as input.
*gmstatistics* has the following parameters:
``` bash
./gmstatistics [-p] [plugin1.dylib] [plugin2.dylib]
```
## Examples
If you want to analyse the memory occupancy of your plugin (i.e. PixelGeoPlugin) you can type:
```bash
./gmstatistics ../lib/libPixelGeoPlugin.0.dylib
```
This is the output retrieved by gmstatistics:
```bash
GeoLogVol 9998 instances 2239552 bytes
GeoTransform 9856 instances 1419264 bytes
GeoBox 9835 instances 472080 bytes
GeoPhysVol 7941 instances 1905840 bytes
GeoNameTag 4904 instances 235392 bytes
GeoIdentifierTag 4293 instances 68688 bytes
GeoFullPhysVol 4088 instances 1896832 bytes
GeoAlignableTransform 2059 instances 494160 bytes
GeoAlignableTransform[216] 2058 instances 32928 bytes
GeoShapeShift 1914 instances 306240 bytes
GeoShapeSubtraction 1190 instances 57120 bytes
GeoMaterial 812 instances 116928 bytes
GeoMaterial[56] 794 instances 48752 bytes
GeoTube 746 instances 35808 bytes
GeoMaterial[120] 571 instances 25408 bytes
GeoShapeUnion 492 instances 23616 bytes
GeoMaterial[72] 447 instances 35904 bytes
GeoTubs 190 instances 12160 bytes
GeoMaterial[64] 167 instances 5280 bytes
GeoLogVol[32] 132 instances 4544 bytes
GeoElement 97 instances 7760 bytes
GeoMaterial[128] 87 instances 2080 bytes
GeoPhysVol[48] 71 instances 2720 bytes
GeoMaterial[32] 60 instances 1920 bytes
GeoPhysVol[40] 49 instances 3392 bytes
GeoSimplePolygonBrep 45 instances 3600 bytes
GeoTrap 44 instances 4928 bytes
GeoMaterial[136] 36 instances 2144 bytes
GeoSimplePolygonBrep[40] 29 instances 960 bytes
GeoSimplePolygonBrep[64] 29 instances 960 bytes
GeoPhysVol[56] 22 instances 2560 bytes
GeoTrd 20 instances 1280 bytes
GeoSimplePolygonBrep[32] 16 instances 1120 bytes
GeoCons 15 instances 1200 bytes
GeoSimplePolygonBrep[48] 11 instances 832 bytes
GeoFullPhysVol[56] 10 instances 17408 bytes
GeoPgon 10 instances 1280 bytes
GeoSimplePolygonBrep[56] 9 instances 576 bytes
GeoPgon[48] 9 instances 144 bytes
GeoPgon[56] 9 instances 144 bytes
GeoPara 8 instances 640 bytes
GeoFullPhysVol[40] 7 instances 20992 bytes
GeoPgon[104] 7 instances 112 bytes
GeoSimplePolygonBrep[72] 3 instances 192 bytes
GeoPgon[72] 2 instances 32 bytes
GeoPgon[80] 2 instances 32 bytes
GeoNameTag[32] 1 instances 32 bytes
GeoElement[56] 1 instances 16 bytes
GeoPgon[96] 1 instances 16 bytes
Total GeoModel object allocation: 9.51557MB
```
<!--To analyse a GDML geometry and save it in SQLite format with *gdml2gm* :-->
<!--``` bash-->
<!--./gdml2gm -f myGeometry.gdml -o myGeometry.db-->
<!--``` -->
<!---->
<!--To visualize a GDML geometry with *gmex*, the user has to set the following environment variable: GDML_FILE_NAME. It has to point to the GDML file that the user wants to plug into *gmex*. Then it is sufficient to call gmex together with the *libGDMLtoGM.dylib/so* library:-->
<!---->
<!--``` bash-->
<!--export GDML_FILE_NAME=<path-to-my-geometry-file>/myGeometry.gdml-->
<!--./gmex ../lib/libGDMLtoGM.dylib -->
<!--``` -->
documentation/docs/components/geomodelvisualization/gmex/Fig 1.png

388 KiB

documentation/docs/components/geomodelvisualization/gmex/Fig 2.png

358 KiB

documentation/docs/components/geomodelvisualization/gmex/Fig 3.png

493 KiB

documentation/docs/components/geomodelvisualization/gmex/Fig 4.png

628 KiB

documentation/docs/components/geomodelvisualization/gmex/Fig 4a.png

554 KiB

documentation/docs/components/geomodelvisualization/gmex/Fig 5.png

424 KiB

documentation/docs/components/geomodelvisualization/gmex/Fig 6.png

501 KiB

# GeoModelVisualization
GeoModelVisualization (gmex)
GeoModelVisualization (gmex) is a 3D interactive visualization tool that allows you to display, navigate and debug complex detector geometries as the HEP experiments ones.
## Examples
In order to launch gmex you could simply type:
``` bash
./gmex
```
This will open a dialogue window where you will be able to select a SQLite (.db) file that you want to display (see Figure 1).
## Examples
{{ imgutils_image_caption('Fig 1.png',
alt='GmexGui',
cap='Figure 1: Gmex GUI with dialogue window to select the geometry to be visualized.',
urlFix=False)
}}
Alternatively you can feed the geometry to `gmex` directly via the command line. For example:
``` bash
./gmex myGeometry.db
```
Once the geometry is selected, by clicking on the `Geo`tab on the left, gmex will diplay a list of all the subdetectors present in the loaded geometry, as shown in Figure 2
{{ imgutils_image_caption('Fig 2.png',
alt='Subdetectors',
cap='Figure 2: List of all the subdetectors present in the loaded geometry.',
urlFix=False)
}}
In order to visualize all or some of them you have to click on the respective checkbox and click on the `eye icon` on the right (3rd icon from the top, in the right panel).
{{ imgutils_image_caption('Fig 3.png',
alt='SelectedGeometry',
cap='Figure 3: Visualization of the selected geometry.',
urlFix=False)
}}
Now that you have loaded your geometry you can start investigating it. A good way to improve the visualization experience is to apply Phi sector cutouts. To do that you have to click on the `Display` tab under `Geo` (Figure 4), unselect a few of the `phi sector cutaways` (Fig 4a) and then click `Close`.
{{ imgutils_image_caption('Fig 4.png',
alt='DisplayTab',
cap='Figure 4: `Display` tab under `Geo`.',
urlFix=False)
}}
{{ imgutils_image_caption('Fig 4a.png',
alt='PhiSector',
cap='Figure 4a: Select/unselect the `phi sector cutaways`.',
urlFix=False)
}}
At this point you have a cutaway view of your detector (Fig 5) and you can start investigating it by "opening" it.
{{ imgutils_image_caption('Fig 5.png',
alt='Cutaway',
cap='Figure 5: Cutaway view of the ATLAS detector.',
urlFix=False)
}}
In order to do so you can follow the instructions written on the bottom part of the left panel. For instance, if you want to expand to child volumes you will have to use the following combination 'Ctrl/Cmd'+click. In this way you will remove the first layer of your geometry and be able to inspect its content (see Fig. 6).
To run *gmex*
{{ imgutils_image_caption('Fig 6.png',
alt='TrackDisplay',
cap='Figure 6: Cutaway view of the ATLAS detector without the first mother volume layer.',
urlFix=False)
}}
......@@ -21,20 +21,15 @@ Material classes, as well as all other classes, use the units defined in `GeoMod
#include "GeoModelKernel/Units.h"
#define SYSTEM_OF_UNITS GeoModelKernelUnits
...
GeoMaterial *water = new GeoMaterial(H20, 1.0*SYSTEM_OF_UNITS::gram/SYSTEM_OF_UNITS::cm3);
GeoIntrusivePtr<GeoMaterial> water{new GeoMaterial(H20, 1.0*SYSTEM_OF_UNITS::gram/SYSTEM_OF_UNITS::cm3)};
```
To finish constructing this material, water, one needs to follow the constructor with the following lines
```cpp
GeoElement *hydrogen = new GeoElement("Hydrogen",
"H",
1.0,
1.010);
GeoElement *oxygen = new GeoElement("Oxygen",
"O",
8.0,
16.0);
GeoIntrusivePtr<GeoElement> hydrogen{new GeoElement("Hydrogen", "H", 1.0, 1.010)};
GeoIntrusivePtr<GeoElement> oxygen{new GeoElement("Oxygen", "O", 8.0, 16.0)};
water->add(hydrogen,0.11);
water->add(oxygen,0.89);
water->lock();
......@@ -44,7 +39,7 @@ The materials are then used to together with shapes to form logical volumes, dis
### Shapes
Shapes are created using the new operator. Essentially, shapes within this system are required to store and provide access to the geometrical constants that describe their geometrical form. This data is, insofar as possible, to be specified on the constructor.
Essentially, shapes within this system are required to store and provide access to the geometrical constants that describe their geometrical form. This data is, insofar as possible, to be specified on the constructor.
Shapes are extensible and custom shapes can be built.
......@@ -55,7 +50,7 @@ double length = 100*SYSTEM_OF_UNITS::cm;
double width = 200*SYSTEM_OF_UNITS::cm;
double depth = 33*SYSTEM_OF_UNITS::cm;
GeoBox* box = new GeoBox(length, width, depth);
GeoIntrusivePtr<GeoBox> box{new GeoBox(length, width, depth)};
```
Most objects can be constructed along similar lines; exceptions are objects with multiple planes such as polycones and polygons; their interface allows one to add planes successively. For the polycone, for example, the shape is built as follows:
......@@ -65,7 +60,7 @@ double dphi = 10*SYSTEM_OF_UNITS::deg;
double sphi = 40*SYSTEM_OF_UNITS::deg;
// Create polycone object
GeoPcon* polycone = new GeoPcon(dphi,sphi);
GeoIntrusivePtr<GeoPcon> polycone{new GeoPcon(dphi,sphi)};
// Add planes successively
double z0 = 0.;
......@@ -89,9 +84,11 @@ This creates a polycone whose projection subtends an angle of 10 degrees between
The shapes can provide their data to a client through their accessors, and in addition support several other operations. Boolean operations on shapes are possible. They can be accomplished through Boolean operators in class [GeoShape](../reference/#introduction_1):
```cpp
GeoShape * donut = new GeoTube();
GeoShape * hole = new GeoTube();
const GeoShape & result = (donut->subtract(*hole));
#include "GeoModelKernel/GeoShapeSubtraction.h"
...
GeoIntrusivePtr<GeoShape> donut{new GeoTube(.....)};
GeoIntrusivePtr<GeoShape> hole{new GeoTube(.....)};
const GeoShape & result = donut->subtract(*hole);
```
The result of a Boolean operation is a shape in a boolean expression tree that can, for example, be decoded when the geometry is declared to GEANT4.
......@@ -114,9 +111,7 @@ The methods `typeId()` and `classTypeId()` return unsigned integers, making the
Logical volumes represent, conceptually, a specific manufactured piece that can be placed in one or more locations around the detector. A logical volume is created by specifying a name tag for the volume, a shape, and a material:
```cpp
const GeoLogVol *myLog = new GeoLogVol("MyLogVol",
myShape,
gNitrogen);
GeoIntrusivePtr<const GeoLogVol> myLog{GeoLogVol("MyLogVol", myShape, myMaterial)};
```
### Physical Volumes and the Geometry Graph
......@@ -126,17 +121,17 @@ Having created elements, materials, shapes, and logical volumes, you are now rea
* Regular Physical Volumes, designed to be small.
* Full Physical Volumes, designed to hold in cache complete information about how the volume is located with respect to the world volume, its formatted name string and other important information.
There is a common abstract [base class](#geomodel-kernel-overview) for all of these: `GeoVPhysVol`. In addition both the full physical volumes have another layer of abstraction, `GeoVFullPhysVol`. All physical volumes allow access to their children.
There is a common abstract [base class](#geomodel-kernel-overview) for all of these: `GeoVPhysVol`. In addition the full physical volumes have another layer of abstraction, `GeoVFullPhysVol`. All physical volumes allow access to their children.
The concrete subclasses that you have at your disposition for detector description are called [GeoPhysVol](../reference/#geophysvol) and [GeoFullPhysVol](../reference/#geofullphysvol). Both of these have a method to add either volumes or volume properties:
```cpp
GeoPhysVol* myVol;
GeoIntrusivePtr<GeoPhysVol> myVol{new GeoPhysVol(myLog)};
myVol->add(aTransformation);
myVol->add(anotherVolume);
```
When you add a transformation, you change the position of the subsequent volume with respect to the parent. If you add no transformation, you will not shift the daughter relative to the parent and commonly will create a daughter which is centered directly in the parent. If you add more than one transformation to the volume before adding a parent, they will be multiplied. The last transformation to be added is applied first to the child. Transformations are discussed next. Like logical volumes, they may be shared.
When you add a transformation, you change the position of the subsequent volume with respect to the parent. If you add no transformation, you will not shift the daughter relative to the parent and commonly will create a daughter which is centered directly in the parent. If you add more than one transformation to the volume before adding a child volume, they will be multiplied. The last transformation to be added is applied first to the child. Transformations are discussed next. Like logical volumes, they may be shared.
Like physical volumes, transformations come in two types:
......@@ -145,7 +140,7 @@ Like physical volumes, transformations come in two types:
When you create a transformation, you must choose the type.
The model of the raw geometry is a tree of nodes, property nodes and volume nodes. The tree can be thought of as a tree of volumes, each one “having” a set of properties (inherited from property nodes throughout the tree). The subsystem engineer judiciously chooses which of the volumes are to contain full, cached, position information – usually, these first-class volumes are to be associated with a detector. He or she also judiciously decides which of the transformations are to be alignable—usually these are the transformations which position something that ultimately has a detector bolted, glued, riveted or otherwise clamped onto a sensitive piece. Then, the developer can apply several techniques for keeping track of these pointers so that the important volumes can later be connected to detector elements, and the alignable transformations can be connected to the alignment database for periodic updating.
The model of the raw geometry is a tree of nodes, property nodes and volume nodes. The tree can be thought of as a tree of volumes, each one “having” a set of properties (inherited from property nodes throughout the tree). The subsystem engineer judiciously chooses which of the volumes are to contain full, cached, position information – usually, these first-class volumes are to be associated with a detector. The subsystem engineer also judiciously decides which of the transformations are to be alignable—usually these are the transformations which position something that ultimately has a detector bolted, glued, riveted or otherwise clamped onto a sensitive piece. Then, the developer can apply several techniques for keeping track of these pointers so that the important volumes can later be connected to detector elements, and the alignable transformations can be connected to the alignment database for periodic updating.
Finally, we provide three mechanisms for giving names to volumes:
......@@ -157,19 +152,19 @@ In effect this last method can be thought of as a way of parametrizing the name
### Actions
There are two ways of getting raw geometry information out of the model. Suppose that one has access to a particular physical volume (it could be the “World” physical volume). One can access its children, there names, and their transformations with respect to the parent in the following way:
There are two ways of getting raw geometry information out of the model. Suppose that one has access to a particular physical volume (it could be the “World” physical volume). One can access its children, their names, and their transformations with respect to the parent in the following way:
```cpp
PVConstLink myVol;
PVConstLink myVol; // PVConstLink is a typedef to GeoIntrusivePtr<const GeoVPhysVol>
for(int c=0; c<myVol->getNChildVols(); ++c) {
PVConstLink child = myVol->getChildVol(c);
GeoTrf::Transform3D xf = getXToChildVol(c);
}
```
One could then iterate in a similar way over the grand children, by using a double loop. Ultimately one would probably to visit all the volumes, whatever their depth in the tree, so probably this would call on some form of recursion. An easy way would be to embed the small sample of code shown above in a recursive subroutine or method. That would be fine and is conceptually simple. However, within the geometry model’s kernel, we have provided an alternate, probably better way to visit the entire tree.
One could then iterate in a similar way over the grand children, by using a double loop. Ultimately one would probably want to visit all the volumes, whatever their depth in the tree, so probably this would call on some form of recursion. An easy way would be to embed the small sample of code shown above in a recursive subroutine or method. That would be fine and is conceptually simple. However, within the geometry model’s kernel, we have provided an alternate, probably better way to visit the entire tree.
That mechanism involves a `GeoVolumeAction`. A `GeoVolumeAction` is a way (for applications programmers) to obtain recursive behavior without writing any recursive routines. It’s a class with a handler routine (`handleVPhysVol()`) which is called for each node before (or after) it is called on its children. This can descend to an arbitrary depth in the tree. The `GeoVolumeAction` is an abstract base class and should be subclassed by programmers to suit their needs. Another class `TemplateVolAction` is provided as a template that one can take and modify. To run it, one does this:
That mechanism involves a `GeoVolumeAction`. A `GeoVolumeAction` is a way (for applications programmers) to obtain recursive behavior without writing any recursive routines. It’s a class with a handler routine (`handleVPhysVol()`) which is called for each node before (or after) it is called on its children. This can descend to an arbitrary depth in the tree. The `GeoVolumeAction` is a base class and should be subclassed by programmers to suit their needs. Another class `TemplateVolAction` is provided as a template that one can take and modify. To run it, one does this:
```cpp
PVConstLink myVol;
......@@ -184,8 +179,8 @@ Incidentally, there is another kind of action in the library called `GeoNodeActi
```cpp
PVConstLink myVol;
for(int c=0; c<myVol->getNChildVols(); ++c) {
GeoAccessVolumeAction av(c);
myVol->exec(&ac);
GeoAccessVolumeAction av(c,nullptr);
myVol->exec(&av);
PVConstLink child = av.getVolume();
GeoTrf::Transform3D xf = av.getTransform();
}
......@@ -197,7 +192,7 @@ This, it turns out, will execute faster than the loop shown above, which (intern
We now come to the important topic of how objects in this system are created and destroyed. The geometry kernel uses a technique called reference counting. Reference counting, shortly stated, is a way to perform an automatic garbage collection of nodes that are no longer in use. This is important when describing a large tree of information, much of which is ideally to be shared — used again and again in many places.
You may have noticed, in several code examples used throughout the GeoModel Kernel Overview section many of the objects have been created using operator `new`. You may have also noticed, if you’ve tried to play around with the kernel classes, that statements which allocate most kernel classes on the stack, such as
You may have noticed, in several code examples used throughout the GeoModel Kernel Overview section many of the objects have been created using operator `new`, and the resulting pointers were never used directly. Instead they have always been wrapped into objects of a special smart pointer class `GeoIntrusivePtr`. You may have also noticed, if you’ve tried to play around with the kernel classes, that statements which allocate most kernel classes on the stack, such as
```cpp
GeoBox box(100*SYSTEM_OF_UNITS::cm
......@@ -210,13 +205,13 @@ are not allowed. Who is going to clean up the memory after all these `new `opera
Let's consider this example:
```cpp
const GeoBox* worldBox = new GeoBox(100*SYSTEM_OF_UNITS::cm
, 100*SYSTEM_OF_UNITS::cm
, 100*SYSTEM_OF_UNITS::cm);
const GeoLogVol* worldLog = new GeoLogVol("WorldLog"
, worldBox
, worldMaterial);
GeoPhysVol* worldPhys = new GeoPhysVol(worldLog);
GeoIntrusivePtr<const GeoBox> worldBox{new GeoBox(100*SYSTEM_OF_UNITS::cm
, 100*SYSTEM_OF_UNITS::cm
, 100*SYSTEM_OF_UNITS::cm)};
GeoIntrusivePtr<const GeoLogVol> worldLog{new GeoLogVol("WorldLog"
, worldBox
, worldMaterial)};
GeoIntrusivePtr<GeoPhysVol> worldPhys{new GeoPhysVol(worldLog)};
```
Each of the three objects (`worldBox`, `worldLog`, and `worldPhys`) are created with a reference count. `worldBox`’s is initially zero, at the time it is created. `worldLog`’s is also zero when it is created. However, when `worldLog` is created, the reference count of `worldBox` increases to one, since now it is referenced somewhere — namely by the logcal volume `worldLog`. Now, when the physical volume `worldPhys` is created, the reference count of the logical volume will increase to one — since it is used once by a single physical volume.
......@@ -225,22 +220,6 @@ Each time a physical volume is positioned within another physical volume, its re
When the very last node referencing the physical volume is destroyed, this means that the physical volume itself has outlived its usefulness and *should disappear*. And that is what happens. The destruction of objects is carried out automatically when the reference count falls to zero. And in fact, the only way to delete an object is to arrange for all of its references to disappear. This is because the destructor of all reference counted objects is private.
This scheme applies to elements, materials, shapes, logical volumes, physical volumes, full physical volumes, and instances of all other classes which also inherit from the `RCBase` class.
So far, we have described what happens to an object when it is no longer used by any other node in the tree. However, what about the top of the tree, which has no nodes that refer to it? Since the destructors of our physical volumes are private, how do you arrange to get it to go away?
Reference counts can also be manipulated manually, by using the methods `ref()` and `unref()`. The physical volume at the head of the tree, often known as the “world” physical volume, can be referenced manually using this call:
```cpp
worldPhys->ref(); // increments reference count by one
```
Later, you can destroy the world volume and trigger a global collection of garbage by using this call:
```cpp
worldPhys->unref() // decrements reference count by one
```
When the reference count becomes 0, the world physical volume deletes itself, decreasing the reference counts of its logical volume and any children. These will then begin dereferencing and possibly deleting their own children, until all the memory has been freed.
This scheme applies to elements, materials, shapes, logical volumes, physical volumes, full physical volumes, and instances of all other classes which also inherit from the `RCBase` class. The reference counting machanism described above is implemented automatically by the smart pointer class `GeoIntrusivePtr` (which works similarly to [Boost intrusive_ptr](https://www.boost.org/doc/libs/1_86_0/libs/smart_ptr/doc/html/smart_ptr.html#intrusive_ptr)). While in theory it is possible to operate GeoModel objects by using bare pointers and manual handling of reference counting (by calling `ref()` and `unref()` methods of the `RCBase` base class), it is *not recommended* to do that as this approach is error-prone, and it can easily lead to memory leaks and other memory access problems.
Suppose now that you want to arrange for a node to not be deleted automatically in this fashion — even when nobody references it any more. In order to do this, simply call the `ref()` method on this object. That way, the reference counts starts at 1 and will not fall to zero until you call `unref()`, manually.
So far, we have described what happens to an object when it is no longer used by any other node in the tree. However, what about the top of the tree, which has no nodes that refer to it? How do you arrange to get it to go away? Well, the answer on this question is pretty simple: it is enough for all corresponding instances of the `GeoIntrusivePtr` to go out of scope. This will bring the embedded reference count of the tree top object to 0 and the object will delete itself, decreasing the reference counts of its logical volume and any children. These will then begin dereferencing and possibly deleting their own children, until all the memory has been freed.
documentation/docs/components/kernel/reference/RCBase/GeoVSurfaceShape/Annulus.png

40.5 KiB

documentation/docs/components/kernel/reference/RCBase/GeoVSurfaceShape/AnnulusDemo.png

5.29 KiB

documentation/docs/components/kernel/reference/RCBase/GeoVSurfaceShape/AnnulusDemo2.png

7.43 KiB

documentation/docs/components/kernel/reference/RCBase/GeoVSurfaceShape/Diamond.png

10.9 KiB

documentation/docs/components/kernel/reference/RCBase/GeoVSurfaceShape/DiamondDemo.png

4.98 KiB

### GeoAnnulusSurface
```cpp
// === GeoAnnulusSurface ===
// Constructor:
// The default position of the cylinder center is at (0,0,0)
// Ox, Oy: the deviation of the focusing point from the default position
// radius_in: the inner radius of the annulus
// radius_out: the outer radius of the annulus
// phi: the span angle of the deviated circular sector, when phi = 2*PI, it is an annulus
GeoAnnulusSurface(double Ox, double Oy, double radius_in, double radius_out, double phi);
// Public Methods:
double getOx() const;
double getOy() const;
double getRadiusIn() const;
double getRadiusOut() const;
double getPhi() const;
void exec (GeoShapeAction *action) const override final;
virtual bool isOnSurface (const double Px, const double Py, const double Pz, const GeoTrf::Transform3D & trans) const override final;
```
A `GeoAnnulusSurface` represents an annulus (or circular sector) virtual surface initialized at XOY plane. It is specified by *Ox (X-position of deviated center)*, *Oy (Y-position of deviated center)*, *Inner Radius*, *Outer Radius*, and *Span Angle $\Phi$*, all input parameters of the constructor. The methods `getOx()`, `getOy()`, `getRadiusIn()`, `getRadiusOut()`, and `getPhi()` return the shape boundaries of the surface. When $\phi = 2\pi$, the circular section returns to an annulus.
{{ imgutils_image_caption('RCBase/GeoVSurfaceShape/Annulus.png',
alt='The GeoAnnulusSurface shape',
cap='Figure: Shape boundaries of annulus surface.',
urlFix=False)
}}
### GeoDiamondSurface
```cpp
// === GeoDiamondSurface ===
// Constructor:
GeoDiamondSurface (double X_bottom_half, double X_mid_half, double X_top_half, double Y_bottom_half, double Y_top_half);
// Public Methods:
double area() const;
double getXbottomHalf () const;
double getXmidHalf () const;
double getXtopHalf () const;
double getYbottomHalf () const;
double getYtopHalf () const;
void exec (GeoShapeAction *action) const override final;
virtual bool isOnSurface (const double Px, const double Py, const double Pz, const GeoTrf::Transform3D & trans) const override final;
```
A `GeoDiamondSurface` represents a diamond virtual surface initialized at XOY plane. It is specified by *X half-length bottom*, *X half-length middle*, *X half-length top* in X-direction and *Y half-length bottom*, *Y half-length top* in Y-direction, which are input parameters of the constructor. The public methods `exec` and `isOnSurface` inherits methods from `GeoVSurfaceShape`, methods `getXbottomHalf()`, `getXmidHalf()`, `getXtopHalf()`, `getYbottomHalf()`, and `getYtopHalf()` return the shape boundaries of the surface. `area()` returns the area of the diamond.
{{ imgutils_image_caption('RCBase/GeoVSurfaceShape/Diamond.png',
alt='The GeoDiamondSurface shape',
cap='Figure: Shape boundaries of diamond surface.',
urlFix=False)
}}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment