mirror of
https://github.com/sesps/SPS_SABRE_EventBuilder.git
synced 2024-11-26 19:38:50 -05:00
Updated Details (markdown)
parent
e4ac668478
commit
bfa80d73da
10
Details.md
10
Details.md
|
@ -2,15 +2,15 @@
|
||||||
The goal of this page is to outline some of the details of the SESPS-SABRE event builder so that modifications or improvements can be made to the code. As such, the contents of this page are subject to change and may be inaccurate depending on the specific branch that has been cloned. It is also _not_ intended to be comprehensive. Rather it is meant to highlight the important details of the program.
|
The goal of this page is to outline some of the details of the SESPS-SABRE event builder so that modifications or improvements can be made to the code. As such, the contents of this page are subject to change and may be inaccurate depending on the specific branch that has been cloned. It is also _not_ intended to be comprehensive. Rather it is meant to highlight the important details of the program.
|
||||||
|
|
||||||
## `CompassFile`
|
## `CompassFile`
|
||||||
`CompassFile` is a essentially a wrapper around a `std::shared_ptr<std::ifstream>` which directly interfaces with the actual binary file. The class contains the shared pointer (it must be a shared pointer to allow for movable and copyable data) as well a buffer for the file. It interfaces with a single CoMPASS binary file. When the file is opened, the file is checked for its length, to ensure that a) the file is not empty and b) that the file has _at least_ enough data to form a single CoMPASS datum. A CoMPASS datum consists of 24 bytes of data, assuming that it does _not_ contain waveform data. These checks need to be made as there are conditions where CoMPASS saves either a completely empty file (bad) or a file which does not contain a full datum (annoying). The class fills the data buffer from the file, and then places the next hit into a `CompassHit` structure, which can be retrieved from the class. It also has a boolean flag which can be switched on/off to indicate if the currently selected hit has been used and the next hit should be retrieved from the buffer.
|
`CompassFile` is a essentially a wrapper around a `std::shared_ptr<std::ifstream>` which directly interfaces with the actual binary file. The class contains the shared pointer (it must be a shared pointer to allow for movable and copyable data) as well a buffer for the file. It interfaces with a single CoMPASS binary file. When the file is opened, the file is checked for its length, to ensure that a) the file is not empty and b) that the file has _at least_ enough data to form a single CoMPASS hit. A CoMPASS hit varies in size depending on the options chosen in CoMPASS. To handle this, CoMPASS writes a header to each file indicating the type of data written. After asserting the file has a header, the header is read, and then the file is checked to make sure it contains at least one hit. These checks need to be made as there are conditions where CoMPASS saves either a completely empty file (bad) or a file which does not contain a full datum (annoying). The class fills the data buffer from the file, and then places the next hit into a `CompassHit` structure, which can be retrieved from the class. It also has a boolean flag which can be switched on/off to indicate if the currently selected hit has been used and the next hit should be retrieved from the buffer.
|
||||||
|
|
||||||
Most important for the performance of the code is the size of the data buffer. In an ideal world, one would buffer the entirety of the data file into active memory, as this would provide the best performance. In some experiments, this is actually possible. SPS only experiments tend to have small file sizes when the DAQ is properly optimized, so there is no issue with buffering data. But most SPS-SABRE experiments have a lot of data (and a lot of data files) so the buffer has to be restricted. For the SPS_SABRE_EventBuilder repository, CoMPASS file has a locked buffer size of 200,000 hits per file (4.8 Megabytes per file). This is to account for full experiments where there are 147 files, equating to about a Gigabyte of data. In principle one could expand this value and get increased performance, but there are some caveats. Obviously, if one expands the amount of total buffered data (across all files) beyond the amount of available memory, there will be large performance penalties or even crashing behavior. So be sure to keep the total buffered data (buffer size in hits times hit size [24 bytes] times number of files) less than the amount of available memory. Additionally, expanding the buffer beyond the size of the file incurs no benefit. Therefore, expanding the buffer beyond the size of the largest data file in the run is pointless. If the buffersize needs modified, it can be found in `include/CompassRun.h` and is stored as the variable `bufsize`. Note that if you modify this value it is recommended to rebuild the entire program from scratch. Also, functions exist for implementing the buffer size as an input in something like the input file, however, they currently are not used. In general, the size of SPS data fluctuates so little, that it hasn't been deemed useful.
|
Most important for the performance of the code is the size of the data buffer. In an ideal world, one would buffer the entirety of the data file into active memory, as this would provide the best performance. In some experiments, this is actually possible. SPS only experiments tend to have small file sizes when the DAQ is properly optimized, so there is no issue with buffering data. But most SPS-SABRE experiments have a lot of data (and a lot of data files) so the buffer has to be restricted. For the SPS_SABRE_EventBuilder repository, CoMPASS file has a locked buffer size of 200,000 hits per file (~4.8 Megabytes per file). This is to account for full experiments where there are 147 files, equating to about a Gigabyte of data. In principle one could expand this value and get increased performance, but there are some caveats. Obviously, if one expands the amount of total buffered data (across all files) beyond the amount of available memory, there will be large performance penalties or the program could crash. So be sure to keep the total buffered data (buffer size in hits times hit size [24 bytes] times number of files) less than the amount of available memory. Additionally, expanding the buffer beyond the size of the file incurs no benefit. Therefore, expanding the buffer beyond the size of the largest data file in the run is pointless. If the buffer size needs modified, it can be found in `src/evb/CompassRun.h` and is stored as the variable `m_bufsize`. Note that if you modify this value it is recommended to rebuild the entire program from scratch. Also, functions exist for implementing the buffer size as an input in something like the input file, however, they currently are not used. In general, the size of SPS data fluctuates so little, that it hasn't been deemed useful.
|
||||||
|
|
||||||
## `CompassRun`
|
## `CompassRun`
|
||||||
`CompassRun` is the main location of event building in the program. It serves as a hub for the separate event building operations and the collection of `CompassFiles` for the active run. `CompassRun` is given a list of filenames and loops over that list, generating either a `CompassFile` or passing the name along to the scaler analysis if it matches a name in the scaler list. Once the set of files has been created, `CompassRun` begins the event building operation of choice (fast, slow, etc.) by selecting the first hit in time from the collection of files. Once it identifies the earliest hit, it passes the hit along to the next stage, typically slow sorting. The `CompassFile` from which the hit was taken has it's flag flipped so that the next hit in the buffer is set to the active hit. This process continues until all files have been exhausted of data.
|
`CompassRun` is the main location of event building in the program. It serves as a hub for the separate event building operations and the collection of `CompassFiles` for the active run. `CompassRun` is given a path to a directory and it iterates over the elements of that directory, generating either a `CompassFile` or passing the name along to the scaler analysis if it matches a name in the scaler list. Once the set of files has been created, `CompassRun` begins the event building operation of choice (fast, slow, etc.) by selecting the first hit in time from the collection of files. Once it identifies the earliest hit, it passes the hit along to the next stage, typically slow sorting. The `CompassFile` from which the hit was taken has it's flag flipped so that the next hit in the buffer is set to the active hit. This process continues until all files have been exhausted of data.
|
||||||
|
|
||||||
## `EVBApp`
|
## `EVBApp`
|
||||||
This is the main API of the program. Think of this class as the application level class. It is the direct interface with the user input data, and properly generates and runs various `CompassRun` operations. If you want to add some new form of user input, it should be done through this class.
|
This is the application level class. It is the direct interface with the user input data, and properly generates and runs various `CompassRun` operations. If you want to add some new form of user input, it should be done through this class.
|
||||||
|
|
||||||
## `SlowSort, FastSort, SFPAnalyzer`
|
## `SlowSort, FastSort, SFPAnalyzer`
|
||||||
These classes are the implementation of the method described in the Home page. They typically receive a single hit from the `CompassRun` parent, perform some timing calculations, and then fill up a `std::vector` type structure. Once the window is exhausted, a flag is flipped, indicating to `CompassRun` that the built event is ready and should be passed to either the next analysis stage or written to disk.
|
These classes are the implementation of the method described in the Home page. They typically receive a single hit from the `CompassRun` parent, perform some timing calculations, and then fill up a `std::vector` type structure. Once the window is exhausted, a flag is flipped, indicating to `CompassRun` that the built event is ready and should be passed to either the next analysis stage or written to disk.
|
||||||
|
@ -19,6 +19,6 @@ These classes are the implementation of the method described in the Home page. T
|
||||||
As it is currently implemented, we map CoMPASS channel data to detector related data structures using the `ChannelMap` class in conjuction with `SlowSort`. `ChannelMap` reads in a map file, which essentially provides a conversion between a global channel number and a number specifically associated with a detector component (a detector id). The allowed values are specified by an `enum` list defined in `ChannelMap`. `SlowSort` then has a secondary map which converts this detector id into a pointer to the correct memory location in the data structure. The reason for this slightly complicated scheme is that it provides a performance boost over the alternative of a large `if` statement over hardcoded values, and also it is more stable against modifications. It also does a better job of encapsulating the idea of the mapping as well. However, it is slightly convoluted, and in a better implementation `SlowSort` would probably not have a map as well; the entire mapping process should be encapsulated within the `ChannelMap` class. Consider this an area of active development.
|
As it is currently implemented, we map CoMPASS channel data to detector related data structures using the `ChannelMap` class in conjuction with `SlowSort`. `ChannelMap` reads in a map file, which essentially provides a conversion between a global channel number and a number specifically associated with a detector component (a detector id). The allowed values are specified by an `enum` list defined in `ChannelMap`. `SlowSort` then has a secondary map which converts this detector id into a pointer to the correct memory location in the data structure. The reason for this slightly complicated scheme is that it provides a performance boost over the alternative of a large `if` statement over hardcoded values, and also it is more stable against modifications. It also does a better job of encapsulating the idea of the mapping as well. However, it is slightly convoluted, and in a better implementation `SlowSort` would probably not have a map as well; the entire mapping process should be encapsulated within the `ChannelMap` class. Consider this an area of active development.
|
||||||
|
|
||||||
## `SFPPlotter` and `CutHandler`
|
## `SFPPlotter` and `CutHandler`
|
||||||
`SFPPlotter` is the class responsible for handling a plot request. It takes in a ROOT file with a tree and generates a new file with histograms. It can also perform one layer of cuts. Cuts are methods for selecting specific data out of the entire set. This is done with ROOT's `TCutG` class. A list of ROOT files, each of which contains a `TCutG` object named "CUTG" (the default name), can be given to the plotter which then passes the list along to a `CutHandler`. The handler retrieves the cut, gives it the new name specified in the list file, and associates the names of the variables to be cut upon. A map of variable names to memory location is created at construction by the `CutHandler`. If the user wants to expand the possible cut variables, they will need to add a name to the map and specify the memory location in the data structure.
|
`SFPPlotter` is the class responsible for handling a plot request. It takes in a ROOT file with a tree of analyzed events and generates a new file with histograms. It can also perform one layer of cuts. Cuts are methods for selecting specific data out of the entire set. This is done with ROOT's `TCutG` class. A list of ROOT files, each of which contains a `TCutG` object named "CUTG" (the default name), can be given to the plotter which then passes the list along to a `CutHandler`. The handler retrieves the cut, gives it the new name specified in the list file, and associates the names of the variables to be cut upon. A map of variable names to memory location is created at construction by the `CutHandler`. If the user wants to expand the possible cut variables, they will need to add a name to the map and specify the memory location in the data structure.
|
||||||
|
|
||||||
The plotter has two overloaded methods named `MyFill`. These essentially handle the creation and filling of ROOT histograms. Using these type of patterns greatly reduce the code overhead of using the ROOT histograms. In general these methods should be used rather than individually constructing, filling, and writing histograms. There is some cost to using the `MyFill` style, but in general it is greatly outweighed by the reduction in code and increase in readability of the code.
|
The plotter has two overloaded methods named `MyFill`. These essentially handle the creation and filling of ROOT histograms. Using these type of patterns greatly reduce the code overhead of using the ROOT histograms. In general these methods should be used rather than individually constructing, filling, and writing histograms. There is some cost to using the `MyFill` style, but in general it is greatly outweighed by the reduction in code and increase in readability of the code.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user