Macro REST_Detector_CheckReadout: how to create a 128 bit mask

REST version : v2.3.5
REST commit : f83c73da

Hello,

I am trying to display random localized energy depositions in the readout, by using the macro REST_Detector_CheckReadout. Among the inputs required, there are the detector region and a 128 bit mask to select the channels of interest.
As region I used:

Double_t region[4];
region[0] = 0.0;  // Xmin starts at 0% of full area (?)
region[1] = 1.;   // Xmax ends at 100% of full area (?)
region[2] = 0.5;  // Ymin starts at 50% of full area (?)
region[3] = 1.0;  // Ymax ends at 100% of full area (?)

As mask, I used that one specified in the example contained in the macro ReadoutTest.C (at GitHub - rest-for-physics/basic-readouts: It contains very basic readout definitions to serve as a reference for more complex readout definitions.)

mask[0] = 0x80110110;  // Channels 4, 8 and 31 enabled
mask[1] = 0x000000FF;  // Channels from 32 to 47 enabled
mask[2] = 0x00;        // All channels disabled [From 64 to 95]
mask[3] = 0x00;        // All channels disabled [From 96 to 127

However I don’t understand how to generate a 128 bit mask in order to select the channels I want.
Moreover, how can I recognize the number of channels in the output graph of the macro (see attachment)?

For the test I used the readout generated with my REST version, following the instructions at
https://github.com/iaxo/detector-readouts

Thanks in advance for the help!

Hi Barbara, thanks for posting this issue.

Actually, what it does internally that macro is to call to a method that creates the object (i.e. the TRestReadoutPlane to be drawn with this MonteCarlo method.

TGraph* GetHittedStripMap(TRestDetectorReadoutPlane* p, Int_t mask[4], Double_t region[4], Int_t N);

The 128-bits mask is given through an 4-elements Int_t array. Each element of the array being 32-bits depth.

The key code selecting the channels is this one

    for (int n = 0; n < 128; n++) {
        Int_t bit = n % 32;
        Int_t level = n / 32;

        Int_t msk = 0x1 << bit;
        if (msk & mask[level]) {
            cout << "Adding channel : " << 32 * level + bit << endl;
            channelIds.push_back(32 * level + bit);
        }
    }

It does 128 iterations and checks if the corresponding bit mask is enabled.

Not 100% sure if that works, but in your screen output you should see the channels that are being added.

So, the mask is given in hexadecimal

mask[1] = 0x000000FF;

The last FF means the 8 less significative bits are enabled.

As the comment says //Channels from 32 to 47 enabled, then they should be enabled. Do they appear in your output?

From your image it is probably what you would expect.

If you get 64-channels for X-axis and 64-channels for Y-axis, then I would expect that Y-channels would be above 64, and then you should enable bits at mask[2] and mask[3].

For example, try mask[2] = 0x000000FF to enable channels from 64 to 72, or mask[2] = 0x0000FF00 to enable channels from 72 to 80.

The Montecarlo routine works in a way so that it will launch random positions inside the readout within the region defined.

Notice that you are testing only the top-half of the detector given the region[X] values. Because region[2] = 0.5; defines the Ymin of the region, i.e. half of the detector (the are is renormalized to 1). Thats why you don’t see black dots on the bottom half.

The region definition is used to increase statistics on a particular zone of the detector, and get results faster on that specific zone (or region).

Hi Javier,

Thanks for the explanations.
If I set the following for region and mask

root [1] mask[0] = mask[0] = 0x80110110;  // Channels 4, 8 and 31 enabled (Needs revision)
root [2] mask[1] = mask[1] = 0x000000FF;  // Channels from 32 to 47 enabled
root [3] mask[2] = mask[2] = 0x00;        // All channels disabled [From 64 to 95]
root [4] mask[3] = mask[3] = 0x00;        // All channels disabled [From 96 to 127]

root [6]  region[0] = 0.0
root [7] region[1] = 1.
root [8] region[2] = 0.0
root [9] region[3] = 1.0

I get as output in the screen something that doesn’t match with the comments in the macro ReadoutTest.C:

Xmax : 30.25 Xmin : -30
Ymax : 30.125 Ymin : -30
region 1 : 0
region 2 : 1
region 3 : 0
region 4 : 1
Xmax : 30.25 Xmin : -30
Ymax : 30.125 Ymin : -30
Adding channel : 4
Adding channel : 8
Adding channel : 16
Adding channel : 20
Adding channel : 31
Adding channel : 32
Adding channel : 33
Adding channel : 34
Adding channel : 35
Adding channel : 36
Adding channel : 37
Adding channel : 38
Adding channel : 39
Fri 02 Jul 2021 11:56:40 AM CEST
N: 0
(int) 0

Moreover, I am sorry but I did not understand how I could select (for exemple)
strip 50 in y direction
strips 115 in y direction
strips from 50-90 in x direction

Thanks for the help.

First thing is that the mask does not distinguish between X or Y strips. One needs to know in advance which channels, in principle, correspond to X, which to Y.

Then, looking into

https://github.com/iaxo/detector-readouts

I see that the readout has 120 channels in X and 120 channels in Y. Then, lets say 120 first channels are X and the next 120 channels are Y. So channels from 0-119 are X, from 120 to 239 are Y.

The present macro is not able to work with 240 channels, it only goes to 128. However, I just added an offset so that this could by bypassed.

Now, to answer this. Lets think only in the X-axis

When we write in hexadecimal, each character represents groups of 4-bits. Each bit is a channel.

Channels from 0 to 31 are defined at mask[0], channels from 32 to 63 are defined at mask[1], …

So, strip 50 in X direction is channel 50, and it is on mask[1]. Then, from the following symbol identified with the hexadecimal mask 0xJKLMNOPQ the Q corresponds with channels from 32 to 35, the P to channels from 36 to 39, the O from channels from 40 to 43, etc, etc. So the channel 50 is at character M. Now character M represents channels from 48 to 51. So it means it is the third bit, so 0100 would become 0x4 in hexadecimal. If it is 0xF then it is 1111 in binary, so you enable all channels from 48 to 51.

Therefore, you should write the following for channel 50.

mask[1] = 0x00040000

For strip 115 it is at mask[3] since it starts at 96, 100, 104, 108, 112, now is the forth bit at the fifth character 1000 is 0x8mask[3] = 0x00080000.

Now from channels from 50 to 90, this is at mask[1] from 32 to 63 and mask[2] from 64 to 96.

So, in 0xJKLMNOPQ the letter M should enable now bit-3 and bit-4 so it is 1100 in hexadecimal → 0xC. All channels to the left should be enabled. So mask[1] becomes

mask[1] = 0xFFC00000

For mask[2] channel 90 corresponds with letter K, and it should enable 3-bits 0111 → 0x7 (Channel 90 included).

So, it should be something like

mask[2] = 0x07FFFFFF`

I may be wrong in some numbers, but thats the general idea of the mask.

Now, to access the Y-axis, I added a new argument named offset so that you will be able to shift the mask by any value you want, at least, if we would have thousands of strips I would have the choice to go to a particular 128 channels range.

The new macro would be used this way in order to use the previous masks with the Y-axis channels.

Int_t REST_Detector_CheckReadout(rootFile, readout_name, region, mask, 120, 1E4, 0);

So that the first mask bit is identified with channel #120.

Thanks a lot! Now it is clear!

Just a small comment, I guess there is a typo. If I am not wrong, to enable channels from 50 to 90, mask[1] should be 0xFFFC0000.

The macro with the offset = 0 works.
If I try to enable Y channels (from 50 to 90), that translates to set an offset of 120, I get the following:

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
||                         TRestDetectorReadout content                          ||
||                       Config file : readouts_IAXOD0.rml                       ||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
||                            Name : iaxo_readout_15                             ||
||             Title : IAXO-D0 readout 0.5 mm-Pitch 120+120 channels             ||
||                             REST Version : 2.3.5                              ||
||                           REST Official release: No                           ||
||                                Clean state: No                                ||
||                            REST Commit : b8d9147b                             ||
||                          REST Library version : 1.1                           ||
-----------------------------------------------------------------------------------
||                         Number of readout planes : 1                          ||
||                          Decoding was defined : YES                           ||
-----------------------------------------------------------------------------------
||                             -- Readout plane : 0                              ||
-----------------------------------------------------------------------------------
||                 -- Position : X = 0 mm,  Y : 0 mm, Z : -15 mm                 ||
||                   -- Vector : X = 0 mm,  Y : 0 mm, Z : 1 mm                   ||
||             -- Cathode Position : X = 0 mm,  Y : 0 mm, Z : 15 mm              ||
||                        -- Total drift distance : 30 mm                        ||
||                           -- Charge collection : 1                            ||
||                             -- Total modules : 1                              ||
||                            -- Total channels : 240                            ||
-----------------------------------------------------------------------------------
***********************************************************************************

Error in <TRint::HandleTermInput()>: std::length_error caught: cannot create std::vector larger than max_size()

I am using the macro in attachment.

ReadoutTest.C (1.2 KB)

Hi Barbara, your macro works for me. I just had to fix a small typo on the calling arguments inside your macro.

Notice that the definition for the official macro is as follows:

 Int_t REST_Detector_CheckReadout(TString rootFile, TString name, Double_t region[4], Int_t stripsMask[4], Int_t offset = 0, Int_t N = 1E4, Int_t plane = 0) {

While at your macro you are calling

 25     REST_Detector_CheckReadout(readoutFile, readoutName, region, mask, N, offset);
 26     return 0;

where N and offset are reversed. You are launching few points at a large offset.

I get the following pictures with 0, 60 and 120 as offset.



Hello Javier,

I implemented the correction in the macro ReadoutTest.C (attached), and I installed the latest version of REST (v2.3.8, commit 4ff2821d). Apparently, I still have problems if I use any offset:

root [0] .x ReadoutTest.C("readouts.root", "iaxo_readout_15", 60)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
||                         TRestDetectorReadout content                          ||
||                       Config file : readouts_IAXOD0.rml                       ||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
||                            Name : iaxo_readout_15                             ||
||             Title : IAXO-D0 readout 0.5 mm-Pitch 120+120 channels             ||
||                             REST Version : 2.3.5                              ||
||                           REST Official release: No                           ||
||                                Clean state: No                                ||
||                            REST Commit : b8d9147b                             ||
||                          REST Library version : 1.1                           ||
-----------------------------------------------------------------------------------
||                         Number of readout planes : 1                          ||
||                          Decoding was defined : YES                           ||
-----------------------------------------------------------------------------------
||                             -- Readout plane : 0                              ||
-----------------------------------------------------------------------------------
||                 -- Position : X = 0 mm,  Y : 0 mm, Z : -15 mm                 ||
||                   -- Vector : X = 0 mm,  Y : 0 mm, Z : 1 mm                   ||
||             -- Cathode Position : X = 0 mm,  Y : 0 mm, Z : 15 mm              ||
||                        -- Total drift distance : 30 mm                        ||
||                           -- Charge collection : 1                            ||
||                             -- Total modules : 1                              ||
||                            -- Total channels : 240                            ||
-----------------------------------------------------------------------------------
***********************************************************************************

Error in <TRint::HandleTermInput()>: std::length_error caught: cannot create std::vector larger than max_size()

Sometimes the error changes, even if I try to lunch the same command (exiting and re-entering restRootMacros):

 root [0] .x ReadoutTest.C("readouts.root", "iaxo_readout_15", 10)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
||                         TRestDetectorReadout content                          ||
||                       Config file : readouts_IAXOD0.rml                       ||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
||                            Name : iaxo_readout_15                             ||
||             Title : IAXO-D0 readout 0.5 mm-Pitch 120+120 channels             ||
||                             REST Version : 2.3.5                              ||
||                           REST Official release: No                           ||
||                                Clean state: No                                ||
||                            REST Commit : b8d9147b                             ||
||                          REST Library version : 1.1                           ||
-----------------------------------------------------------------------------------
||                         Number of readout planes : 1                          ||
||                          Decoding was defined : YES                           ||
-----------------------------------------------------------------------------------
||                             -- Readout plane : 0                              ||
-----------------------------------------------------------------------------------
||                 -- Position : X = 0 mm,  Y : 0 mm, Z : -15 mm                 ||
||                   -- Vector : X = 0 mm,  Y : 0 mm, Z : 1 mm                   ||
||             -- Cathode Position : X = 0 mm,  Y : 0 mm, Z : 15 mm              ||
||                        -- Total drift distance : 30 mm                        ||
||                           -- Charge collection : 1                            ||
||                             -- Total modules : 1                              ||
||                            -- Total channels : 240                            ||
-----------------------------------------------------------------------------------
***********************************************************************************

#0  0x00007f1db086fc2a in __GI___wait4 (pid=20065, stat_loc=stat_loc
entry=0x7ffe73bb1888, options=options
entry=0, usage=usage
entry=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:27
#1  0x00007f1db086fbeb in __GI___waitpid (pid=<optimized out>, stat_loc=stat_loc
entry=0x7ffe73bb1888, options=options
entry=0) at waitpid.c:38
#2  0x00007f1db07df0e7 in do_system (line=<optimized out>) at ../sysdeps/posix/system.c:172
#3  0x00007f1db0ecd65e in TUnixSystem::StackTrace() () from /local/home/bb263328/install_root/lib/libCore.so
#4  0x00007f1daa0d7830 in cling::MultiplexInterpreterCallbacks::PrintStackTrace() () from /local/home/bb263328/install_root/lib/libCling.so
#5  0x00007f1daa0d7172 in cling_runtime_internal_throwIfInvalidPointer () from /local/home/bb263328/install_root/lib/libCling.so
#6  0x00007f1d9c59c492 in ?? ()
#7  0x0000000000000000 in ?? ()
Error in <HandleInterpreterException>: Trying to dereference null pointer or trying to call routine taking non-null arguments.
Execution of your code was aborted.
In file included from input_line_178:1:
/local/home/bb263328/REST_v2.3.8/rest-framework/install/macros/detector/REST_Detector_CheckReadout.C:64:29: warning: null passed to a callee that requires a non-null argument [-Wnonnull]
            Int_t nPixels = channel->GetNumberOfPixels();
                            ^~~~~~~

or “segmentation violation”, or “core dumped”.

ReadoutTest.C (1.2 KB)

If I check the changes you introduced to the script (using vimdiff command) I see that you have defined the planeId to be pId=1. However, that is the second plane, the first plane is pId=0.

Processing: screenshot.png…

Before, you were not providing the pId value, and the default value of the function was zero

Int_t REST_Detector_CheckReadout(TString rootFile, TString name, Double_t region[4], Int_t stripsMask[4],
                                 Int_t offset = 0, Int_t N = 1E4, Int_t plane = 0) {

The segmentation fault appears because when trying to retrieve the second plane, pId=1, the plane does not exist, and the pointer becomes null, when trying to access this null pointer it produces the seg.fault. This is 95% of the times the cause of seg.fault.

Thanks! Now it works.