Commit 1af43b5d authored by Simon Spannagel's avatar Simon Spannagel
Browse files

Merge branch 'mupiuxDAQ' into 'master'

Refurbishing the EventLoaderMuPixTelescope to also read in data together with the mimosa

See merge request !378
parents 2ab3d9ae 86b6492a
Pipeline #2126453 passed with stages
in 22 minutes and 5 seconds
CORRYVRECKAN_ENABLE_DEFAULT(OFF)
# Define module and return the generated name as MODULE_NAME
CORRYVRECKAN_GLOBAL_MODULE(MODULE_NAME)
CORRYVRECKAN_DETECTOR_MODULE(MODULE_NAME)
FIND_PACKAGE(MUPIX8DAQ REQUIRED)
......
......@@ -9,117 +9,231 @@
*/
#include "EventLoaderMuPixTelescope.h"
#include <string>
#include "dirent.h"
#include "objects/Cluster.hpp"
#include "objects/Pixel.hpp"
#include "objects/Track.hpp"
using namespace corryvreckan;
// using namespace std;
EventLoaderMuPixTelescope::EventLoaderMuPixTelescope(Configuration& config, std::vector<std::shared_ptr<Detector>> detectors)
: Module(config, std::move(detectors)), m_blockFile(nullptr) {
EventLoaderMuPixTelescope::EventLoaderMuPixTelescope(Configuration& config, std::shared_ptr<Detector> detector)
: Module(config, detector), removed_(0), detector_(detector), blockFile_(nullptr) {
config_.setDefault<bool>("is_sorted", false);
config_.setDefault<bool>("ts2_is_gray", false);
m_inputDirectory = config_.getPath("input_directory");
m_runNumber = config_.get<int>("Run");
m_isSorted = config_.get<bool>("is_sorted");
m_ts2IsGray = config_.get<bool>("ts2_is_gray");
// We need to check for the config files in case of scans... TBI
config_.setDefault<unsigned>("buffer_depth", 1000);
config_.setDefault<double>("time_offset", 0.0);
inputDirectory_ = config_.getPath("input_directory");
buffer_depth_ = config.get<unsigned>("buffer_depth");
isSorted_ = config_.get<bool>("is_sorted");
timeOffset_ = config_.get<double>("time_offset");
if(config.count({"run", "input_file"}) > 1) {
throw InvalidCombinationError(config, {"run", "input_file"}, "run and input_file are mutually exclusive.");
} else if(config_.has("input_file")) {
input_file_ = config_.get<string>("input_file");
} else {
runNumber_ = config_.get<int>("run");
}
}
void EventLoaderMuPixTelescope::initialize() {
for(auto& detector : get_detectors()) {
LOG(DEBUG) << "Initialise for detector " + detector->getName();
// extract the tag from the detetcor name
string tag = detector_->getName();
if(tag.find("_") < tag.length())
tag = tag.substr(tag.find("_") + 1);
tag_ = uint(stoi(tag, nullptr, 16));
LOG(DEBUG) << detector_->getName() << " is using the fpga link tag " << hex << tag_;
if(typeString_to_typeID.find(detector_->getType()) == typeString_to_typeID.end()) {
throw KeyValueParseError("tag " + std::to_string(tag_), "Sensor tag not supported");
}
// Need to check if the files do exist
DIR* directory = opendir(m_inputDirectory.c_str());
if(directory == nullptr) {
LOG(ERROR) << "Directory " << m_inputDirectory << " does not exist";
return;
type_ = typeString_to_typeID.at(detector_->getType());
LOG(INFO) << "Detector " << detector_->getType() << "is assigned to type id " << type_;
std::stringstream ss;
if(input_file_.size() == 0) {
ss << std::setw(6) << std::setfill('0') << runNumber_;
std::string s = ss.str();
input_file_ = "telescope_run_" + s + ".blck";
}
// check the entries and if the correct file exists continue - seems to be inefficient
// check the if folder and file do exist
dirent* entry;
bool foundFile = false;
DIR* directory = opendir(inputDirectory_.c_str());
if(directory == nullptr) {
throw MissingDataError("Cannot open directory: " + inputDirectory_);
}
while((entry = readdir(directory))) {
if(entry->d_name == string("telescope_run_001020_mergedFrames.blck")) {
if(entry->d_name == input_file_) {
foundFile = true;
break;
}
}
if(!foundFile) {
LOG(ERROR) << "Requested run not existing ";
return;
throw MissingDataError("Cannot open data file: " + input_file_);
} else
LOG(INFO) << "File found" << endl;
string file = (m_inputDirectory + "/" + entry->d_name);
string file = (inputDirectory_ + "/" + entry->d_name);
LOG(INFO) << "reading " << file;
m_blockFile = new mudaq::BlockFile(file);
if(!m_blockFile->open_read()) {
LOG(ERROR) << "File cannot be read" << endl;
return;
} else
LOG(STATUS) << "Loaded Reader";
hHitMap = new TH2F("hitMap", "hitMap; column; row", 50, -0.5, 49.5, 202, -0.5, 201.5);
blockFile_ = new BlockFile(file);
if(!blockFile_->open_read()) {
throw MissingDataError("Cannot read data file: " + input_file_);
}
hHitMap = new TH2F("hitMap",
"hitMap; column; row",
detector_->nPixels().x(),
-.05,
detector_->nPixels().x() - .5,
detector_->nPixels().y(),
-.05,
detector_->nPixels().y() - .5);
hdiscardedHitmap = new TH2F("discardedhitMap",
"hitMap of out of event hits; column; row",
detector_->nPixels().x(),
-.05,
detector_->nPixels().x() - .5,
detector_->nPixels().y(),
-.05,
detector_->nPixels().y() - .5);
hPixelToT = new TH1F("pixelToT", "pixelToT; ToT in TS2 clock cycles.; ", 64, -0.5, 63.5);
hTimeStamp = new TH1F("pixelTS", "pixelTS; TS in clock cycles; ", 1024, -0.5, 1023.5);
hHitsEvent = new TH1F("hHitsEvent", "hHitsEvent; # hits per event; ", 300, -.5, 299.5);
hitsPerkEvent = new TH1F("hHitsPerkEvent", "hitsper1kevents; corry events /1k; hits per 1k events", 1000, -.5, 999.5);
}
StatusCode EventLoaderMuPixTelescope::run(const std::shared_ptr<Clipboard>& clipboard) {
// Loop over all detectors
vector<string> detectors;
for(auto& detector : get_detectors()) {
// Get the detector name
std::string detectorName = detector->getName();
detectors.push_back(detectorName);
LOG(DEBUG) << "Detector with name " << detectorName;
}
map<string, PixelVector> dataContainers;
mudaq::TelescopeFrame tf;
double frame_start = std::numeric_limits<double>::max();
double frame_end = std::numeric_limits<double>::min();
void EventLoaderMuPixTelescope::finalize(const std::shared_ptr<ReadonlyClipboard>&) {
LOG(INFO) << "Number of hits put to clipboard: " << stored_
<< " and number of removed (not fitting in an event) hits: " << removed_;
if(!isSorted_)
LOG(INFO) << "Increasing the buffer depth might reduce this number.";
}
if(!m_blockFile->read_next(tf))
StatusCode EventLoaderMuPixTelescope::read_sorted(const std::shared_ptr<Clipboard>& clipboard) {
PixelVector hits;
if(!blockFile_->read_next(tf_)) {
return StatusCode::EndRun;
else {
LOG(DEBUG) << "Found " << tf.num_hits() << " in event";
for(uint i = 0; i < tf.num_hits(); ++i) {
mudaq::RawHit h = tf.get_hit(i);
if(h.tag() == 0x4)
h = tf.get_hit(i, 66);
double px_timestamp = 8 * static_cast<double>(((tf.timestamp() >> 2) & 0xFFFFF700) + h.timestamp_raw());
auto p = std::make_shared<Pixel>(detectors.at(h.tag() / 4), h.column(), h.row(), 0, 0, px_timestamp);
// Select earliest and latest pixel:
frame_start = (px_timestamp < frame_start ? px_timestamp : frame_start);
frame_end = (px_timestamp > frame_end ? px_timestamp : frame_end);
dataContainers[detectors.at(h.tag() / 4)].push_back(p);
hHitMap->Fill(h.column(), h.row());
hTimeStamp->Fill(h.timestamp_raw());
}
}
for(uint i = 0; i < tf_.num_hits(); ++i) {
RawHit h = tf_.get_hit(i, type_);
if(((h.tag() & uint(~0x3)) == tag_))
continue;
// Convert time stamp to ns - i'd like to do this already on the mupix8_DAQ side, but have not found the time yet,
// assuming 10bit ts
double px_timestamp = 8 * static_cast<double>(((tf_.timestamp() >> 2) & 0xFFFFFFFFFFC00) + h.timestamp_raw());
// setting tot and charge to zero here - needs to be improved
pixels_.push_back(std::make_shared<Pixel>(detector_->getName(), h.column(), h.row(), 0, 0, px_timestamp));
}
// If no event is defined create one
if(clipboard->getEvent() == nullptr) {
// The readout FPGA creates frames with a length of 128 time stamps, each 8ns. The int division cuts of lowest bits
int begin = int(pixels_.front()->timestamp()) / 1024;
clipboard->putEvent(std::make_shared<Event>(double(begin * 1024), double((begin + 1) * 1024)));
}
return StatusCode::Success;
}
for(auto d : detectors) {
if(!dataContainers.count(d))
StatusCode EventLoaderMuPixTelescope::read_unsorted(const std::shared_ptr<Clipboard>& clipboard) {
if(!eof_)
fillBuffer();
while(true) {
if(pixelbuffer_.size() == 0)
break;
auto pixel = pixelbuffer_.top();
if((pixel->timestamp() < clipboard->getEvent()->start())) {
LOG(DEBUG) << " Old hit found: " << Units::display(pixel->timestamp(), "us") << " vs prev end (" << eventNo_ - 1
<< ")\t" << Units::display(prev_event_end_, "us") << " and current start \t"
<< Units::display(clipboard->getEvent()->start(), "us")
<< " and duration: " << clipboard->getEvent()->duration()
<< "and number of triggers: " << clipboard->getEvent()->triggerList().size();
removed_++;
hdiscardedHitmap->Fill(pixel->column(), pixel->row());
pixelbuffer_.pop(); // remove top element
continue;
try {
clipboard->putData(dataContainers[d], d);
} catch(ModuleError& e) {
LOG(ERROR) << "Unknown detector ";
}
if(pixelbuffer_.size() && (pixel->timestamp() < clipboard->getEvent()->end()) &&
(pixel->timestamp() > clipboard->getEvent()->start())) {
LOG(DEBUG) << " Adding pixel hit: " << Units::display(pixel->timestamp(), "us") << " vs prev end ("
<< eventNo_ - 1 << ")\t" << Units::display(prev_event_end_, "us") << " and current start \t"
<< Units::display(clipboard->getEvent()->start(), "us")
<< " and duration: " << Units::display(clipboard->getEvent()->duration(), "us");
pixels_.push_back(pixel);
hHitMap->Fill(pixel.get()->column(), pixel.get()->row());
hPixelToT->Fill(pixel.get()->raw());
// display the 10 bit timestamp distribution
hTimeStamp->Fill(fmod((pixel.get()->timestamp() / 8.), pow(2, 10)));
pixelbuffer_.pop();
} else {
break;
}
}
// Store current frame time and the length of the event:
LOG(DEBUG) << "Frame with " << tf.num_hits() << " hits, time: " << Units::display(frame_start, {"ns", "us", "s"})
<< ", length: " << Units::display((frame_end - frame_start), {"ns", "us", "s"});
clipboard->putEvent(std::make_shared<Event>(frame_start, frame_end));
if(pixelbuffer_.size() < buffer_depth_)
fillBuffer();
// Return value telling analysis to keep running
if(pixelbuffer_.size() == 0)
return StatusCode::NoData;
prev_event_end_ = clipboard->getEvent()->end();
return StatusCode::Success;
}
void EventLoaderMuPixTelescope::fillBuffer() {
// here we need to check quite a number of cases
while(pixelbuffer_.size() < buffer_depth_) {
if(blockFile_->read_next(tf_)) {
// no hits in data - can only happen if the zero suppression is switched off, skip the event
if(tf_.num_hits() == 0) {
continue;
}
// need to determine the sensor layer that is identified by the tag
RawHit h = tf_.get_hit(0);
// tag does not match - continue reading if data is not sorted
if(((h.tag() & uint(~0x3)) != tag_)) {
continue;
}
// all hits in one frame are from the same sensor. Copy them
for(uint i = 0; i < tf_.num_hits(); ++i) {
h = tf_.get_hit(i, type_);
// convert timestamp to ns - i'd like to do this already on the mupix8_DAQ side, but have not found the time
// yet, assuming 10bit ts
double px_timestamp =
8 * static_cast<double>(((tf_.timestamp() >> 2) & 0xFFFFFFFFFFC00) + h.timestamp_raw()) - timeOffset_;
LOG(TRACE) << "Pixel timestamp " << px_timestamp;
// setting tot and charge to zero here - needs to be improved
pixelbuffer_.push(std::make_shared<Pixel>(detector_->getName(), h.column(), h.row(), 0, 0, px_timestamp));
}
} else {
eof_ = true;
break;
}
}
}
std::map<std::string, int> EventLoaderMuPixTelescope::typeString_to_typeID = {{"mupix8", MP8_SORTED_TS2},
{"mupix9", MP10_SORTED_TS2},
{"mupix10", MP10_UNSORTED_GS1_GS2},
{"run2020v1", R20V1_UNSORTED_GS1_GS2_GS3},
{"run2020v2", R20V2_UNSORTED_GS1_GS2_GS3},
{"run2020v3", R20V3_UNSORTED_GS1_GS2_GS3},
{"run2020v4", R20V4_UNSORTED_GS1_GS2_GS3},
{"run2020v5", R20V5_UNSORTED_GS1_GS2_GS3},
{"run2020v6", R20V6_UNSORTED_GS1_GS2_GS3},
{"run2020v7", R20V7_UNSORTED_GS1_GS2_GS3},
{"run2020v8", R20V8_UNSORTED_GS1_GS2_GS3},
{"run2020v9", R20V9_UNSORTED_GS1_GS2_GS3}};
StatusCode EventLoaderMuPixTelescope::run(const std::shared_ptr<Clipboard>& clipboard) {
eventNo_++;
pixels_.clear();
// get the hits
StatusCode result = (isSorted_ ? read_sorted(clipboard) : read_unsorted(clipboard));
hHitsEvent->Fill(double(pixels_.size()));
counterHits_ += pixels_.size();
if(eventNo_ % 1000 == 0) {
int point = eventNo_ / 1000;
hitsPerkEvent->Fill(point, double(counterHits_));
counterHits_ = 0;
}
if(pixels_.size() > 0)
clipboard->putData(pixels_, detector_->getName());
stored_ += pixels_.size();
return result;
}
......@@ -8,12 +8,13 @@
* Intergovernmental Organization or submit itself to any jurisdiction.
*/
#include <TCanvas.h>
#include <TH1F.h>
#include <TH2F.h>
#include <iostream>
#include <queue>
#include "core/module/Module.hpp"
// mupix telescope includes
#include "blockfile.hpp"
#include "telescope_frame.hpp"
......@@ -31,12 +32,13 @@ namespace corryvreckan {
* @param config Configuration object for this module as retrieved from the steering file
* @param detectors Vector of pointers to the detectors
*/
EventLoaderMuPixTelescope(Configuration& config, std::vector<std::shared_ptr<Detector>> detectors);
EventLoaderMuPixTelescope(Configuration& config, std::shared_ptr<Detector> detector);
/**
* @brief [Initialise this module]
*/
void initialize() override;
void finalize(const std::shared_ptr<ReadonlyClipboard>&) override;
/**
* @brief [Run the function of this module]
......@@ -44,17 +46,43 @@ namespace corryvreckan {
StatusCode run(const std::shared_ptr<Clipboard>& clipboard) override;
private:
std::string m_inputDirectory;
bool m_isSorted;
bool m_ts2IsGray;
int m_runNumber;
mudaq::BlockFile* m_blockFile;
mudaq::TelescopeFrame m_tf;
StatusCode read_sorted(const std::shared_ptr<Clipboard>& clipboard);
StatusCode read_unsorted(const std::shared_ptr<Clipboard>& clipboard);
void fillBuffer();
uint tag_{};
double prev_event_end_{};
int type_{};
int eventNo_{};
long unsigned counterHits_{};
long unsigned removed_{}, stored_{};
uint64_t ts_prev_{0};
unsigned buffer_depth_{};
bool eof_{false};
double timeOffset_{};
std::string input_file_{};
std::shared_ptr<Detector> detector_;
struct CompareTimeGreater {
bool operator()(const std::shared_ptr<Pixel>& a, const std::shared_ptr<Pixel>& b) {
return a->timestamp() > b->timestamp();
}
};
// Buffer of timesorted pixel hits: (need to use greater here!)
std::priority_queue<std::shared_ptr<Pixel>, PixelVector, CompareTimeGreater> pixelbuffer_;
PixelVector pixels_{};
std::string inputDirectory_;
bool isSorted_;
int runNumber_;
BlockFile* blockFile_;
TelescopeFrame tf_;
// Histograms
TH2F* hHitMap;
TH1F* hPixelToT;
TH1F* hTimeStamp;
TH1F* hHitsEvent;
TH1F* hitsPerkEvent;
TH2F* hdiscardedHitmap;
TH2F* hHitMap;
static std::map<std::string, int> typeString_to_typeID;
};
} // namespace corryvreckan
# EventLoaderMuPixTelescope
**Maintainer**: Lennart Huth (<lennart.huth@desy.de>)
**Module Type**: *GLOBAL*
**Maintainer**: Lennart Huth (<lennart.huth@desy.de>)
**Module Type**: *DETECTOR*
**Status**: Work in progress
### Description
This module reads in and converts data taken with the MuPix telescope.
It requires one input file which contains the data of all planes in the telescope.
The data contains time-ordered readout frames.
For frame, the module loops over all hits and stores the row, column, timestamp, and ToT are stored on the clipboard.
This module reads in and converts data taken with the MuPix telescope or a single mupix plane.
It requires one input file which contains the data of all planes used.
The `EventLoaderMuPixTelescope` supports a list of sensors:
* MuPix8
* MuPix9
* MuPix10
* all Run2020 sensor
* (additional/ older sensors can be added on request)
It cannot be combined with other event loaders and does not require a `Metronome`.
The detector name in the geometry file is used to determine the tag which identifies the sensor in the datastream:
### Parameters
* `input_directory`: Defines the input file. No default
* `Run`: not in use. Defaults to `-1`
* `is_sorted`: Defines if data recorded is on FPGA timestamp sorted. Defaults to `false`
* `ts2_is_gray`: Defines if the timestamp is gray encoded or not. Defaults to `false`.
[mydetetcor_TAG]
Everything behind the first `_` is used as tag, if none found the tag is assumed to be the detector name.
The correct type is given by the `type` in the geometry.
It is assumed that the timestamp has 10bit and runs at a frequency of 125 MHz (8ns bins)
### Event definition:
* Sorted telescope data: The loader can define its own events as the full
information of all systems is stored in an telescope event.
* Unsorted telescope data: External event definition is required. This has to
be a `Metronome` (8192ns are recommended
to match the internal time structure) for standalone telescope data. Otherwise
any other event definition (`EventLoaderEUDAQ2` `EventDefinitionM26`) can be used.
### Dependencies
This module requires a installation of the mupix8_daq package that is used by the Mu3e pixel group to read out the sensors. This library is non-public. Authorized users can download it via https://bitbucket.org/mu3e/mupix8_daq.git
### Parameters
* `input_directory`: Defines the input file. No default.
* `run`: 6 digit run number, with leading zeros being automatically added, to
open the data file with the standard format `telescope_run_RUN.blck`.`run` and
`input_file` are mutually exclusive.
* `is_sorted`: Defines if data recorded is on FPGA timestamp sorted. Defaults to `false`.
* `time_offset`: Subtract an offset to correct for the expected delay between
issuing the synchronous reset and receiving it. Only used if
`is_sorted=false`. Defaults to `0`.
* `input_file`: Filename of the input file. `run` and `input_file` are mutually exclusive.
* `buffer_depth`: Depth of the pixel buffer that is used to sort the hits with
respect to time. Defaults to `1000`.
### Plots produced
For all detectors, the following plots are produced:
* 2D histogram of pixel hit positions
* 2D histogram of pixel read in but not added to an event
* 1D histogram of the pixel timestamps
* 1D histogram of the pixel ToT
* 1D histogram of number of pixels per event
* 1D histogram with the number of pixels averaged over 1k events as function of event number
### Usage
```toml
[EventLoaderMuPixTelescope]
input_directory = "/path/to/file"
Run = -1
is_sorted = false
Run = 1234
is_sorted = false
ts2_is_gray = false
```
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment