diff --git a/EventVisualisation/DataConverter/CMakeLists.txt b/EventVisualisation/DataConverter/CMakeLists.txt index 778a3b6182aaf..b0198000c3dbe 100644 --- a/EventVisualisation/DataConverter/CMakeLists.txt +++ b/EventVisualisation/DataConverter/CMakeLists.txt @@ -18,6 +18,7 @@ o2_add_library(EventVisualisationDataConverter src/VisualisationEventJSONSerializer.cxx src/VisualisationEventROOTSerializer.cxx src/VisualisationEventOpenGLSerializer.cxx + src/Location.cxx PUBLIC_LINK_LIBRARIES RapidJSON::RapidJSON O2::ReconstructionDataFormats O2::DataFormatsParameters @@ -33,6 +34,7 @@ o2_add_executable(eve-convert src/VisualisationTrack.cxx src/VisualisationCluster.cxx src/VisualisationCalo.cxx + src/Location.cxx PUBLIC_LINK_LIBRARIES O2::EventVisualisationView RapidJSON::RapidJSON diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/Location.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/Location.h new file mode 100644 index 0000000000000..72ebc36b1dd31 --- /dev/null +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/Location.h @@ -0,0 +1,70 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Location.h +/// \author Julian Myrcha +/// + +#ifndef O2EVE_LOCATION_H +#define O2EVE_LOCATION_H + +#include +#include +#include + +namespace o2::event_visualisation +{ +struct LocationParams { + std::string fileName; + int port = -1; + int timeout = 100; + std::string host = "localhost"; + bool toFile = true; + bool toSocket = true; +}; +class Location +{ + std::ofstream* mOut; + int mClientSocket; + bool mToFile; + bool mToSocket; + std::string mFileName; + int mPort; + int mTimeout; + std::string mHostName; + + public: + explicit Location(const LocationParams& params) + { + this->mFileName = params.fileName; + this->mToFile = !params.fileName.empty() && params.toFile; + this->mToSocket = params.port != -1 && params.toSocket; + this->mOut = nullptr; + this->mPort = params.port; + this->mHostName = params.host; + this->mClientSocket = -1; + this->mTimeout = params.timeout; + } + ~Location() + { + close(); + } + void open(); + void close(); + void write(char* buf, std::streamsize size); + [[nodiscard]] std::string fileName() const { return this->mFileName; } + [[nodiscard]] std::string hostName() const { return this->mHostName; } + [[nodiscard]] int port() const { return this->mPort; } +}; +} // namespace o2::event_visualisation + +#endif // O2EVE_LOCATION_H diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventJSONSerializer.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventJSONSerializer.h index c08009215d9fe..8f4b0d2bd8375 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventJSONSerializer.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventJSONSerializer.h @@ -56,7 +56,7 @@ class VisualisationEventJSONSerializer : public VisualisationEventSerializer public: bool fromFile(VisualisationEvent& event, std::string fileName) override; - void toFile(const VisualisationEvent& event, std::string fileName) override; + void toFile(const VisualisationEvent& event, Location& location) override; ~VisualisationEventJSONSerializer() override = default; }; diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventOpenGLSerializer.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventOpenGLSerializer.h index 3e6d3809cb709..8af91d6964a46 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventOpenGLSerializer.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventOpenGLSerializer.h @@ -38,7 +38,7 @@ class VisualisationEventOpenGLSerializer : public VisualisationEventSerializer public: const std::string serializerName() const override { return std::string("VisualisationEventOpenGLSerializer"); } bool fromFile(VisualisationEvent& event, std::string fileName) override; - void toFile(const VisualisationEvent& event, std::string fileName) override; + void toFile(const VisualisationEvent& event, Location& location) override; ~VisualisationEventOpenGLSerializer() override = default; }; diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventROOTSerializer.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventROOTSerializer.h index e6408fb1c6c3f..3a5cf245f4816 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventROOTSerializer.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventROOTSerializer.h @@ -44,7 +44,7 @@ class VisualisationEventROOTSerializer : public VisualisationEventSerializer public: [[nodiscard]] const std::string serializerName() const override { return std::string("VisualisationEventROOTSerializer"); } bool fromFile(VisualisationEvent& event, std::string fileName) override; - void toFile(const VisualisationEvent& event, std::string fileName) override; + void toFile(const VisualisationEvent& event, Location& location) override; ~VisualisationEventROOTSerializer() override = default; }; diff --git a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventSerializer.h b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventSerializer.h index 5a6d902084ebf..80cb3c0b131a0 100644 --- a/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventSerializer.h +++ b/EventVisualisation/DataConverter/include/EventVisualisationDataConverter/VisualisationEventSerializer.h @@ -17,6 +17,7 @@ #define O2EVE_VISUALISATIONEVENTSERIALIZER_H #include "EventVisualisationDataConverter/VisualisationEvent.h" +#include "EventVisualisationDataConverter/Location.h" #include #include @@ -45,7 +46,7 @@ class VisualisationEventSerializer static o2::dataformats::GlobalTrackID deserialize(unsigned source, unsigned index, unsigned flags); static VisualisationEventSerializer* getInstance(std::string ext) { return instances[ext]; } virtual bool fromFile(VisualisationEvent& event, std::string fileName) = 0; - virtual void toFile(const VisualisationEvent& event, std::string fileName) = 0; + virtual void toFile(const VisualisationEvent& event, Location& location) = 0; virtual const std::string serializerName() const = 0; virtual ~VisualisationEventSerializer() = default; }; diff --git a/EventVisualisation/DataConverter/src/Location.cxx b/EventVisualisation/DataConverter/src/Location.cxx new file mode 100644 index 0000000000000..416412c742252 --- /dev/null +++ b/EventVisualisation/DataConverter/src/Location.cxx @@ -0,0 +1,182 @@ +// Copyright 2019-2020 CERN and copyright holders of ALICE O2. +// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders. +// All rights not expressly granted are reserved. +// +// This software is distributed under the terms of the GNU General Public +// License v3 (GPL Version 3), copied verbatim in the file "COPYING". +// +// In applying this license CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +/// +/// \file Location.cxx +/// \author Julian Myrcha +/// + +#include "EventVisualisationDataConverter/Location.h" +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace o2::event_visualisation +{ + +int connect_with_timeout(const int socket, const struct sockaddr* addr, socklen_t addrlen, const unsigned int timeout_ms) +{ + int connection = 0; + // Setting O_NONBLOCK + int socket_flags_before; + if ((socket_flags_before = fcntl(socket, F_GETFL, 0) < 0)) { + return -1; + } + if (fcntl(socket, F_SETFL, socket_flags_before | O_NONBLOCK) < 0) { + return -1; + } + do { + if (connect(socket, addr, addrlen) < 0) { + if ((errno != EWOULDBLOCK) && (errno != EINPROGRESS)) { + connection = -1; // error + } else { // wait for complete + // deadline 'timeout' ms from now + timespec now; // NOLINT(*-pro-type-member-init) + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) { + connection = -1; + break; + } + const timespec deadline = {.tv_sec = now.tv_sec, + .tv_nsec = now.tv_nsec + timeout_ms * 1000000l}; + do { + if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) { + connection = -1; + break; + } + // compute remaining deadline + const int ms_until_deadline = static_cast((deadline.tv_sec - now.tv_sec) * 1000l + (deadline.tv_nsec - now.tv_nsec) / 1000000l); + if (ms_until_deadline < 0) { + connection = 0; + break; + } + pollfd connectionPool[] = {{.fd = socket, .events = POLLOUT}}; + connection = poll(connectionPool, 1, ms_until_deadline); + + if (connection > 0) { // confirm the success + int error = 0; + socklen_t len = sizeof(error); + if (getsockopt(socket, SOL_SOCKET, SO_ERROR, &error, &len) == 0) { + errno = error; + } + if (error != 0) { + connection = -1; + } + } + } while (connection == -1 && errno == EINTR); // If interrupted, try again. + if (connection == 0) { + errno = ETIMEDOUT; + connection = -1; + } + } + } + } while (false); + // Restore socket state + if (fcntl(socket, F_SETFL, socket_flags_before) < 0) { + return -1; + } + return connection; +} + +void Location::open() +{ + if (this->mToFile) { + this->mOut = new std::ofstream(mFileName, std::ios::out | std::ios::binary); + } + if (this->mToSocket) { + // resolve host name + sockaddr_in serverAddress; // NOLINT(*-pro-type-member-init) + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(this->mPort); // Port number + + // ask once + static auto server = gethostbyname(this->mHostName.c_str()); + if (server == nullptr) { + LOGF(info, "Error no such host %s", this->mHostName.c_str()); + return; + }; + + bcopy((char*)server->h_addr, + (char*)&serverAddress.sin_addr.s_addr, + server->h_length); + + // Connect to the server + this->mClientSocket = socket(AF_INET, SOCK_STREAM, 0); + if (this->mClientSocket == -1) { + LOGF(info, "Error creating socket"); + return; + } + + if (connect_with_timeout(this->mClientSocket, (sockaddr*)&serverAddress, + sizeof(serverAddress), this->mTimeout) == -1) { + LOGF(info, "Error connecting to %s:%d", this->mHostName.c_str(), this->mPort); + ::close(this->mClientSocket); + this->mClientSocket = -1; + return; + } + try { + char buf[256] = "SEND:"; + strncpy(buf + 6, this->mFileName.c_str(), sizeof(buf) - 7); + strncpy(buf + sizeof(buf) - 6, "ALICE", 6); + auto real = send(this->mClientSocket, buf, sizeof(buf), 0); + if (real != sizeof(buf)) { + throw real; + } + } catch (...) { + ::close(this->mClientSocket); + this->mClientSocket = -1; + LOGF(info, "Error sending file name to %s:%d", this->mHostName.c_str(), this->mPort); + } + } +} + +void Location::close() +{ + if (this->mToFile && this->mOut) { + this->mOut->close(); + delete this->mOut; + this->mOut = nullptr; + } + if (this->mToSocket && this->mClientSocket != -1) { + ::close(this->mClientSocket); + this->mClientSocket = -1; + } +} + +void Location::write(char* buf, std::streamsize size) +{ + if (size == 0) { + return; + } + if (this->mToFile && this->mOut) { + this->mOut->write(buf, size); + } + if (this->mToSocket && this->mClientSocket != -1) { + LOGF(info, "Location::write() socket %s ++++++++++++++++++++++", fileName()); + try { + auto real = send(this->mClientSocket, buf, size, 0); + if (real != size) { + throw real; + } + } catch (...) { + ::close(this->mClientSocket); + this->mClientSocket = -1; + LOGF(info, "Error sending data to %s:%d", this->mHostName.c_str(), this->mPort); + } + } +} + +} // namespace o2::event_visualisation \ No newline at end of file diff --git a/EventVisualisation/DataConverter/src/VisualisationEventJSONSerializer.cxx b/EventVisualisation/DataConverter/src/VisualisationEventJSONSerializer.cxx index 612ddaf8717f4..cce3e6b4a2c58 100644 --- a/EventVisualisation/DataConverter/src/VisualisationEventJSONSerializer.cxx +++ b/EventVisualisation/DataConverter/src/VisualisationEventJSONSerializer.cxx @@ -29,8 +29,9 @@ using namespace rapidjson; namespace o2::event_visualisation { -void VisualisationEventJSONSerializer::toFile(const VisualisationEvent& event, std::string fileName) +void VisualisationEventJSONSerializer::toFile(const VisualisationEvent& event, Location& location) { + std::string fileName = location.fileName(); std::string json = toJson(event); std::ofstream out(fileName); out << json; diff --git a/EventVisualisation/DataConverter/src/VisualisationEventOpenGLSerializer.cxx b/EventVisualisation/DataConverter/src/VisualisationEventOpenGLSerializer.cxx index 4c907eeda0291..1d22a02df61af 100644 --- a/EventVisualisation/DataConverter/src/VisualisationEventOpenGLSerializer.cxx +++ b/EventVisualisation/DataConverter/src/VisualisationEventOpenGLSerializer.cxx @@ -20,6 +20,7 @@ #include #include #include +#include "EventVisualisationDataConverter/Location.h" namespace o2::event_visualisation { @@ -82,8 +83,9 @@ const auto CALT = "CALT"; // calo PID const auto FINE = "FINE"; // -void VisualisationEventOpenGLSerializer::toFile(const VisualisationEvent& event, std::string fileName) +void VisualisationEventOpenGLSerializer::toFile(const VisualisationEvent& event, Location& location) { + std::string fileName = location.fileName(); static const std::vector det_coma = { "ITS", "TPC", "TRD", "TOF", "PHS", "CPV", "EMC", "HMP", "MFT", "MCH", "MID", "ZDC", "FT0", "FV0", "FDD", "ITS-TPC", "TPC-TOF", "TPC-TRD", "MFT-MCH", "ITS-TPC-TRD", "ITS-TPC-TOF", "TPC-TRD-TOF", "MFT-MCH-MID", "ITS-TPC-TRD-TOF", "ITS-AB", "CTP", @@ -91,7 +93,9 @@ void VisualisationEventOpenGLSerializer::toFile(const VisualisationEvent& event, std::ostringstream buf; constexpr auto SIGSIZE = 512; unsigned char data[SIGSIZE]; - std::ofstream out(fileName, std::ios::out | std::ios::binary); + // std::ofstream out(fileName, std::ios::out | std::ios::binary); + + location.open(); // head --bytes 512 fileName.eve buf << "eve" << std::endl; buf << "version=1.00" << std::endl; @@ -104,7 +108,7 @@ void VisualisationEventOpenGLSerializer::toFile(const VisualisationEvent& event, memcpy((char*)&data[0], buf.str().c_str(), SIGSIZE); data[SIGSIZE - 2] = '\n'; data[SIGSIZE - 1] = 0; - out.write((char*)&data[0], SIGSIZE); // <----0 SIGN + location.write((char*)&data[0], SIGSIZE); // <----0 SIGN const auto trackNo = event.getTracksSpan().size(); int phsCount = 0; @@ -140,7 +144,7 @@ void VisualisationEventOpenGLSerializer::toFile(const VisualisationEvent& event, head[Header::emcCount] = emcCount; head[Header::primaryVertex] = event.getPrimaryVertex(); head[Header::tfCounter] = event.getTfCounter(); - out.write(static_cast(chunkHEAD), chunkSize(chunkHEAD)); // <----1 HEAD + location.write(static_cast(chunkHEAD), chunkSize(chunkHEAD)); // <----1 HEAD free(chunkHEAD); } @@ -171,15 +175,15 @@ void VisualisationEventOpenGLSerializer::toFile(const VisualisationEvent& event, celm[index] = track.getClusterCount(); index++; } - out.write(static_cast(chunkTTYP), chunkSize(chunkTTYP)); // <----2 TTYP + location.write(static_cast(chunkTTYP), chunkSize(chunkTTYP)); // <----2 TTYP free(chunkTTYP); - out.write(static_cast(chunkTELM), chunkSize(chunkTELM)); // <----3 TELM + location.write(static_cast(chunkTELM), chunkSize(chunkTELM)); // <----3 TELM free(chunkTELM); - out.write(static_cast(chunkCELM), chunkSize(chunkCELM)); // <----3 CELM + location.write(static_cast(chunkCELM), chunkSize(chunkCELM)); // <----3 CELM free(chunkCELM); - out.write(static_cast(chunkTGID), chunkSize(chunkTGID)); // <----3 GIND + location.write(static_cast(chunkTGID), chunkSize(chunkTGID)); // <----3 GIND free(chunkTGID); - out.write(static_cast(chunkTPID), chunkSize(chunkTPID)); // <----3 TPID (tracks pid) + location.write(static_cast(chunkTPID), chunkSize(chunkTPID)); // <----3 TPID (tracks pid) free(chunkTPID); } @@ -230,17 +234,17 @@ void VisualisationEventOpenGLSerializer::toFile(const VisualisationEvent& event, cxyz[cidx++] = track.getClustersSpan()[i].Z(); } } - out.write(static_cast(chunkTXYZ), chunkSize(chunkTXYZ)); // <----4 TXYZ + location.write(static_cast(chunkTXYZ), chunkSize(chunkTXYZ)); // <----4 TXYZ free(chunkTXYZ); - out.write(static_cast(chunkCXYZ), chunkSize(chunkCXYZ)); // <----4 CXYZ + location.write(static_cast(chunkCXYZ), chunkSize(chunkCXYZ)); // <----4 CXYZ free(chunkCXYZ); - out.write(static_cast(chunkTIME), chunkSize(chunkTIME)); // <----4 TIME + location.write(static_cast(chunkTIME), chunkSize(chunkTIME)); // <----4 TIME free(chunkTIME); - out.write(static_cast(chunkSXYZ), chunkSize(chunkSXYZ)); // <----4 SXYZ + location.write(static_cast(chunkSXYZ), chunkSize(chunkSXYZ)); // <----4 SXYZ free(chunkSXYZ); - out.write(static_cast(chunkCRGE), chunkSize(chunkCRGE)); // <----4 CRGE + location.write(static_cast(chunkCRGE), chunkSize(chunkCRGE)); // <----4 CRGE free(chunkCRGE); - out.write(static_cast(chunkATPE), chunkSize(chunkATPE)); // <----4 CRGE + location.write(static_cast(chunkATPE), chunkSize(chunkATPE)); // <----4 CRGE free(chunkATPE); } @@ -260,11 +264,11 @@ void VisualisationEventOpenGLSerializer::toFile(const VisualisationEvent& event, uxyz[idx++] = c.Y(); uxyz[idx++] = c.Z(); } - out.write(static_cast(chunkUGID), chunkSize(chunkUGID)); // + location.write(static_cast(chunkUGID), chunkSize(chunkUGID)); // free(chunkUGID); - out.write(static_cast(chunkUTIM), chunkSize(chunkUTIM)); // + location.write(static_cast(chunkUTIM), chunkSize(chunkUTIM)); // free(chunkUTIM); - out.write(static_cast(chunkUXYZ), chunkSize(chunkUXYZ)); // + location.write(static_cast(chunkUXYZ), chunkSize(chunkUXYZ)); // free(chunkUXYZ); } @@ -300,22 +304,22 @@ void VisualisationEventOpenGLSerializer::toFile(const VisualisationEvent& event, } } - out.write((char*)chunkCALO, chunkSize(chunkCALO)); // + location.write((char*)chunkCALO, chunkSize(chunkCALO)); // free(chunkCALO); - out.write((char*)chunkCALP, chunkSize(chunkCALP)); // + location.write((char*)chunkCALP, chunkSize(chunkCALP)); // free(chunkCALP); - out.write((char*)chunkCALG, chunkSize(chunkCALG)); // + location.write((char*)chunkCALG, chunkSize(chunkCALG)); // free(chunkCALG); - out.write((char*)chunkCALT, chunkSize(chunkCALT)); // + location.write((char*)chunkCALT, chunkSize(chunkCALT)); // free(chunkCALT); } { const auto chunkFINE = createChunk(FINE, 0); - out.write(static_cast(chunkFINE), chunkSize(chunkFINE)); // <----5 FINE + location.write(static_cast(chunkFINE), chunkSize(chunkFINE)); // <----5 FINE free(chunkFINE); } - out.close(); + location.close(); } void* VisualisationEventOpenGLSerializer::createChunk(const char* lbl, unsigned size) diff --git a/EventVisualisation/DataConverter/src/VisualisationEventROOTSerializer.cxx b/EventVisualisation/DataConverter/src/VisualisationEventROOTSerializer.cxx index 730af08b5fd61..8c1a84c1bf85e 100644 --- a/EventVisualisation/DataConverter/src/VisualisationEventROOTSerializer.cxx +++ b/EventVisualisation/DataConverter/src/VisualisationEventROOTSerializer.cxx @@ -93,8 +93,9 @@ bool VisualisationEventROOTSerializer::existUInt64(TFile& f, const char* name) return true; } -void VisualisationEventROOTSerializer::toFile(const VisualisationEvent& event, std::string fileName) +void VisualisationEventROOTSerializer::toFile(const VisualisationEvent& event, Location& location) { + std::string fileName = location.fileName(); TFile f(fileName.c_str(), "recreate"); saveInt("runNumber", event.mRunNumber); diff --git a/EventVisualisation/DataConverter/src/converter.cxx b/EventVisualisation/DataConverter/src/converter.cxx index a0820d2e6feef..7bbada4bbb5e9 100644 --- a/EventVisualisation/DataConverter/src/converter.cxx +++ b/EventVisualisation/DataConverter/src/converter.cxx @@ -16,31 +16,40 @@ #include "EventVisualisationDataConverter/VisualisationEvent.h" #include "EventVisualisationView/Initializer.h" #include "EventVisualisationView/Options.h" +#include #include #include #include #include -#include #include -#include #include #include #include #include #include +#include +#include +#include + using namespace std::chrono_literals; // source file name, destination (not existing) file name, if limit > 0 then limit EACH type of data -int singleFileConversion(const std::string& src, const std::string& dst, const int limit = -1) +int singleFileConversion(const std::string& src, o2::event_visualisation::Location& dst, const int limit = -1) { - LOGF(info, "Translate: %s -> %s", src, dst); + LOGF(info, "Translate: %s -> %s", src, dst.fileName()); o2::event_visualisation::VisualisationEvent vEvent; auto srcSerializer = o2::event_visualisation::VisualisationEventSerializer::getInstance( std::filesystem::path(src).extension()); + auto dstExtension = std::filesystem::path( + src) + .extension(); // if there is no destination, there will be no extension change + if (!dst.fileName().empty()) { + dstExtension = std::filesystem::path(dst.fileName()).extension(); + } auto dstSerializer = o2::event_visualisation::VisualisationEventSerializer::getInstance( - std::filesystem::path(dst).extension()); + dstExtension); std::chrono::time_point currentTime = std::chrono::high_resolution_clock::now(); std::chrono::time_point endTime = std::chrono::high_resolution_clock::now(); @@ -61,8 +70,9 @@ int singleFileConversion(const std::string& src, const std::string& dst, const i // reads source folder files, find missing files in destination folder and convert them // source folder (/path-to-folder/.ext1) , destination folder (/path-to-folder/.ext2) -int folderConversion(const std::string& srcFolder, const std::string& dstFolder) +int folderConversion(const std::string& srcFolder, const o2::event_visualisation::Location& dstFolderLocation) { + const std::string dstFolder = dstFolderLocation.fileName(); std::vector supported = {".json", ".root", ".eve"}; auto ext1 = srcFolder.substr(srcFolder.rfind('.')); auto ext2 = dstFolder.substr(dstFolder.rfind('.')); @@ -109,7 +119,13 @@ int folderConversion(const std::string& srcFolder, const std::string& dstFolder) auto match = e.substr(0, e.size() - ext1.size()) + ext2; if (destinationList.end() == std::find(destinationList.begin(), destinationList.end(), match)) { // LOGF(info, "translate %s ->%s", src+e, dst+match); - singleFileConversion(src + e, dst + match); + o2::event_visualisation::Location location({.fileName = dst + match, + .port = dstFolderLocation.port(), + .host = dstFolderLocation.hostName()}); + singleFileConversion(src + e, location); + ; + singleFileConversion(src + e, location); + ; } } @@ -122,6 +138,10 @@ void my_handler(int s) exit(1); } +namespace po = boost::program_options; + +using namespace std; + int main(int argc, char** argv) { struct sigaction sigIntHandler { @@ -133,25 +153,59 @@ int main(int argc, char** argv) sigaction(SIGINT, &sigIntHandler, nullptr); LOGF(info, "Welcome in O2 event conversion tool"); - if (argc == 3) { - singleFileConversion(argv[1], argv[2]); // std::quick_exit(... - return 0; - } - if (argc == 4 and std::string(argv[1]) == std::string("-l")) { - singleFileConversion(argv[2], argv[3], 3); // std::quick_exit(... - return 0; - } - if (argc == 4 and std::string(argv[1]) == std::string("-f")) { - folderConversion(argv[2], argv[3]); // std::quick_exit(... - return 0; - } - if (argc == 4 and std::string(argv[1]) == std::string("-c")) { - while (true) { - std::this_thread::sleep_for(2000ms); - folderConversion(argv[2], argv[3]); + try { + int port; + string host; + int limit; + bool folderMode; + bool continuousMode; + vector sources; + po::options_description desc("Allowed options"); + desc.add_options()("help,h", "produce help message")("port", po::value(&port)->default_value(-1), "port number")("host", po::value(&host)->default_value("localhost"), "host name")("sources", po::value(&sources), "sources")("limit,l", po::value(&limit)->default_value(-1), "limit number of elements")("folder,f", po::bool_switch(&folderMode)->default_value(false), "convert folders")("continuous,c", po::bool_switch(&continuousMode)->default_value(false), "continuous folder mode"); + + po::positional_options_description p; + p.add("sources", 2); + + po::variables_map vm; + po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm); + po::notify(vm); + + if (vm.count("help")) { + cout << desc << "\n"; + return 0; + } + + if (vm.count("sources")) { + if (vm["sources"].as>().size() != 2) { + cout << "two positional parameters expected" << "\n"; + return 0; + } } - return 0; + o2::event_visualisation::LocationParams locationParams; + locationParams.fileName = sources[1]; + locationParams.port = port; + locationParams.host = host; + + o2::event_visualisation::Location location(locationParams); + + if (folderMode) { + folderConversion(sources[0], location); + } else if (continuousMode) { + while (true) { + std::this_thread::sleep_for(2000ms); + folderConversion(sources[0], location); + } + } else { + singleFileConversion(sources[0], location, limit); + return 0; + } + } + + catch (exception& e) { + cerr << "error: " << e.what() << "\n"; + return 1; + } catch (...) { + cerr << "Exception of unknown type!\n"; } - LOGF(error, "two filename required, second should point to not existent file"); return -1; // std::quick_exit(-1); } diff --git a/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h b/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h index 1043ed5c303e0..6b3ec653c5350 100644 --- a/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h +++ b/EventVisualisation/Workflow/include/EveWorkflow/EveWorkflowHelper.h @@ -183,7 +183,7 @@ class EveWorkflowHelper bool isInsideITSROF(float t); bool isInsideTimeBracket(float t); - void save(const std::string& jsonPath, const std::string& ext, int numberOfFiles); + void save(const std::string& jsonPath, const std::string& ext, int numberOfFiles, const std::string& receiverHostname, int receiverPort, int receiverTimeout, bool useOnlyFiles, bool useOnlySockets); bool mUseTimeBracket = false; bool mUseEtaBracketTPC = false; diff --git a/EventVisualisation/Workflow/include/EveWorkflow/FileProducer.h b/EventVisualisation/Workflow/include/EveWorkflow/FileProducer.h index d35ddcaa78711..e7203baceba2a 100644 --- a/EventVisualisation/Workflow/include/EveWorkflow/FileProducer.h +++ b/EventVisualisation/Workflow/include/EveWorkflow/FileProducer.h @@ -26,16 +26,15 @@ namespace event_visualisation class FileProducer { private: - size_t mFilesInFolder; std::string mPath; std::string mName; std::string mExt; public: - explicit FileProducer(const std::string& path, const std::string& ext, int filesInFolder = -1, - const std::string& name = "tracks_{timestamp}_{hostname}_{pid}{ext}"); + explicit FileProducer(const std::string& path, const std::string& ext, const std::string& name = "tracks_{timestamp}_{hostname}_{pid}{ext}"); [[nodiscard]] std::string newFileName() const; + void reduceNumberOfFiles(size_t filesInFolder) const; }; } // namespace event_visualisation diff --git a/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h b/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h index 1156d31d190ea..37d4155803e85 100644 --- a/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h +++ b/EventVisualisation/Workflow/include/EveWorkflow/O2DPLDisplay.h @@ -50,7 +50,8 @@ class TPCFastTransform; class O2DPLDisplaySpec : public o2::framework::Task { public: - static constexpr auto allowedTracks = "ITS,TPC,MFT,MCH,MID,ITS-TPC,TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD,ITS-TPC-TRD-TOF,MCH-MID,MFT-MCH,MFT-MCH-MID,PHS,EMC,HMP"; + static constexpr auto allowedTracks = + "ITS,TPC,MFT,MCH,MID,ITS-TPC,TPC-TRD,ITS-TPC-TOF,ITS-TPC-TRD,ITS-TPC-TRD-TOF,MCH-MID,MFT-MCH,MFT-MCH-MID,PHS,EMC,HMP"; static constexpr auto allowedClusters = "ITS,TPC,TRD,TOF,MFT,MCH,MID,PHS,EMC,HMP"; O2DPLDisplaySpec(bool disableWrite, bool useMC, o2::dataformats::GlobalTrackID::mask_t trkMask, @@ -60,12 +61,33 @@ class O2DPLDisplaySpec : public o2::framework::Task std::shared_ptr emcCalibLoader, const std::string& jsonPath, const std::string& ext, std::chrono::milliseconds timeInterval, - bool eveHostNameMatch) - : mDisableWrite(disableWrite), mUseMC(useMC), mTrkMask(trkMask), mClMask(clMask), mDataRequest(dataRequest), mGGCCDBRequest(gr), mEMCALCalibLoader(emcCalibLoader), mJsonPath(jsonPath), mExt(ext), mTimeInterval(timeInterval), mEveHostNameMatch(eveHostNameMatch), mRunType(o2::parameters::GRPECS::NONE) - + bool eveHostNameMatch, + const std::string& receiverHostname, + int receiverPort, + int receiverTimeout, + bool useOnlyFiles, + bool useOnlySockets) + : mDisableWrite(disableWrite), + mUseMC(useMC), + mTrkMask(trkMask), + mClMask(clMask), + mDataRequest(dataRequest), + mGGCCDBRequest(gr), + mEMCALCalibLoader(emcCalibLoader), + mJsonPath(jsonPath), + mExt(ext), + mTimeInterval(timeInterval), + mEveHostNameMatch(eveHostNameMatch), + mRunType(o2::parameters::GRPECS::NONE), + mReceiverHostname(receiverHostname), + mReceiverPort(receiverPort), + mReceiverTimeout(receiverTimeout), + mUseOnlyFiles(useOnlyFiles), + mUseOnlySockets(useOnlySockets) { this->mTimeStamp = std::chrono::high_resolution_clock::now() - timeInterval; // first run meets condition } + ~O2DPLDisplaySpec() override = default; void init(o2::framework::InitContext& ic) final; void run(o2::framework::ProcessingContext& pc) final; @@ -81,7 +103,8 @@ class O2DPLDisplaySpec : public o2::framework::Task std::string mJsonPath; // folder where files are stored std::string mExt; // extension of created files (".json" or ".root") std::chrono::milliseconds mTimeInterval; // minimal interval between files in milliseconds - bool mPrimaryVertexTriggers; // instead of drawing vertices with tracks (and maybe calorimeter triggers), draw vertices with calorimeter triggers (and maybe tracks) + bool mPrimaryVertexTriggers; + // instead of drawing vertices with tracks (and maybe calorimeter triggers), draw vertices with calorimeter triggers (and maybe tracks) int mEventCounter = 0; std::chrono::time_point mTimeStamp; @@ -94,8 +117,13 @@ class O2DPLDisplaySpec : public o2::framework::Task std::shared_ptr mEMCALCalibLoader; std::unique_ptr mEMCALCalibrator; o2::tpc::VDriftHelper mTPCVDriftHelper{}; -}; + std::string mReceiverHostname; + int mReceiverPort; + int mReceiverTimeout; + bool mUseOnlyFiles; + bool mUseOnlySockets; +}; } // namespace o2::event_visualisation -#endif +#endif \ No newline at end of file diff --git a/EventVisualisation/Workflow/src/AO2DConverter.cxx b/EventVisualisation/Workflow/src/AO2DConverter.cxx index d339b150265de..f54907c20d260 100644 --- a/EventVisualisation/Workflow/src/AO2DConverter.cxx +++ b/EventVisualisation/Workflow/src/AO2DConverter.cxx @@ -74,8 +74,8 @@ struct AO2DConverter { mHelper->mEvent.setTfCounter(mTfCounter); mHelper->mEvent.setFirstTForbit(mTfOrbit); mHelper->mEvent.setCreationTime(collision.collisionTime()); - - mHelper->save(jsonPath, ".root", -1); + const std::string hostname("localhost"); + mHelper->save(jsonPath, ".root", -1, hostname, -1, 100, true, true); mHelper->clear(); } }; diff --git a/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx b/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx index 8c795dd01c79f..2bb3c220d67a0 100644 --- a/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx +++ b/EventVisualisation/Workflow/src/EveWorkflowHelper.cxx @@ -23,6 +23,7 @@ #include "ITStracking/IOUtils.h" #include "MFTTracking/IOUtils.h" #include "DataFormatsGlobalTracking/RecoContainerCreateTracksVariadic.h" +#include "DataFormatsMID/Track.h" #include "ReconstructionDataFormats/PrimaryVertex.h" #include "DetectorsBase/GRPGeomHelper.h" #include "DetectorsBase/Propagator.h" @@ -120,7 +121,8 @@ double EveWorkflowHelper::bcDiffToTFTimeMUS(const o2::InteractionRecord& ir) auto bcd = ir.differenceInBC(startIR); if (uint64_t(bcd) > o2::constants::lhc::LHCMaxBunches * 256 && BCDiffErrCount < MAXBCDiffErrCount) { - LOGP(alarm, "ATTENTION: wrong bunches diff. {} for current IR {} wrt 1st TF orbit {}", bcd, ir.asString(), startIR.asString()); + LOGP(alarm, "ATTENTION: wrong bunches diff. {} for current IR {} wrt 1st TF orbit {}", bcd, ir.asString(), + startIR.asString()); BCDiffErrCount++; } @@ -162,12 +164,14 @@ void EveWorkflowHelper::selectTracks(const CalibObjectsConst* calib, t0 *= this->mTPCBin2MUS; terr *= this->mTPCBin2MUS; } else if constexpr (isITSTrack()) { - t0 += 0.5f * this->mITSROFrameLengthMUS; // ITS time is supplied in \mus as beginning of ROF - terr *= this->mITSROFrameLengthMUS; // error is supplied as a half-ROF duration, convert to \mus - } else if constexpr (isMFTTrack()) { // Same for MFT + t0 += 0.5f * this->mITSROFrameLengthMUS; // ITS time is supplied in \mus as beginning of ROF + terr *= this->mITSROFrameLengthMUS; // error is supplied as a half-ROF duration, convert to \mus + } else if constexpr (isMFTTrack()) { + // Same for MFT t0 += 0.5f * this->mMFTROFrameLengthMUS; terr *= this->mMFTROFrameLengthMUS; - } else if constexpr (!(isMCHTrack() || isMIDTrack() || isGlobalFwdTrack())) { + } else if constexpr (!(isMCHTrack() || isMIDTrack() || + isGlobalFwdTrack())) { // for all other tracks the time is in \mus with gaussian error terr *= mPVParams->nSigmaTimeTrack; // gaussian errors must be scaled by requested n-sigma } @@ -197,7 +201,8 @@ void EveWorkflowHelper::selectTracks(const CalibObjectsConst* calib, } } }; - auto creator = [&conf, maskTrk, this, &correctTrackTime, &flagTime, &fixMFTMCHMIDLabel](auto& trk, GID gid, float time, float terr) { + auto creator = [&conf, maskTrk, this, &correctTrackTime, &flagTime, &fixMFTMCHMIDLabel](auto& trk, GID gid, + float time, float terr) { fixMFTMCHMIDLabel(gid); const auto src = gid.getSource(); @@ -234,7 +239,8 @@ void EveWorkflowHelper::selectTracks(const CalibObjectsConst* calib, bool checkTPCDCA = conf.TPCOnlyMaxDCARZ[0] > 0.f || conf.TPCOnlyMaxDCARZ[1] > 0.f; const auto trackIndex = mRecoCont->getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks const auto vtxRefs = mRecoCont->getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs - const auto totalPrimaryVertices = vtxRefs.size() - 1; // The last entry is for unassigned tracks, ignore them + const auto totalPrimaryVertices = + vtxRefs.size() - 1; // The last entry is for unassigned tracks, ignore them for (std::size_t iv = 0; iv < totalPrimaryVertices; iv++) { const auto& pv = mRecoCont->getPrimaryVertex(iv); @@ -259,15 +265,19 @@ void EveWorkflowHelper::selectTracks(const CalibObjectsConst* calib, if (gid.getSource() == o2::dataformats::GlobalTrackID::TPC && checkTPCDCA) { const auto& tpcTr = mRecoCont->getTPCTrack(gid); o2::track::TrackPar trc{tpcTr}; - if (!tpcTr.hasBothSidesClusters()) { // need to correct track Z with this vertex time - float dz = (tpcTr.getTime0() * mTPCTimeBins2MUS - (pv.getTimeStamp().getTimeStamp() + mTPCVDrift->getTimeOffset())) * mTPCVDrift->getVDrift(); + if (!tpcTr.hasBothSidesClusters()) { + // need to correct track Z with this vertex time + float dz = (tpcTr.getTime0() * mTPCTimeBins2MUS - + (pv.getTimeStamp().getTimeStamp() + mTPCVDrift->getTimeOffset())) * + mTPCVDrift->getVDrift(); if (tpcTr.hasCSideClustersOnly()) { dz = -dz; } trc.setZ(trc.getZ() + dz); } std::array dca; - if (!prop->propagateToDCA(pvXYZ, trc, prop->getNominalBz(), 10., o2::base::PropagatorF::MatCorrType::USEMatCorrNONE, &dca) || + if (!prop->propagateToDCA(pvXYZ, trc, prop->getNominalBz(), 10., + o2::base::PropagatorF::MatCorrType::USEMatCorrNONE, &dca) || (conf.TPCOnlyMaxDCARZ[1] > 0. && std::abs(dca[1]) > conf.TPCOnlyMaxDCARZ[1]) || (conf.TPCOnlyMaxDCARZ[0] > 0. && std::abs(dca[0]) > conf.TPCOnlyMaxDCARZ[0])) { continue; @@ -303,7 +313,8 @@ void EveWorkflowHelper::selectTowers() if (conf.PVMode) { const auto trackIndex = mRecoCont->getPrimaryVertexMatchedTracks(); // Global ID's for associated tracks const auto vtxRefs = mRecoCont->getPrimaryVertexMatchedTrackRefs(); // references from vertex to these track IDs - const auto totalPrimaryVertices = vtxRefs.size() - 1; // The last entry is for unassigned tracks, ignore them + const auto totalPrimaryVertices = + vtxRefs.size() - 1; // The last entry is for unassigned tracks, ignore them for (std::size_t iv = 0; iv < totalPrimaryVertices; iv++) { const auto& vtref = vtxRefs[iv]; @@ -315,7 +326,8 @@ void EveWorkflowHelper::selectTowers() mPrimaryVertexTriggerGIDs[iv].emplace_back(GID{static_cast(i), GID::HMP}); } - const auto triggersPHOS = gsl::span(trackIndex.data() + vtref.getFirstEntryOfSource(GID::PHS), vtref.getEntriesOfSource(GID::PHS)); + const auto triggersPHOS = gsl::span(trackIndex.data() + vtref.getFirstEntryOfSource(GID::PHS), + vtref.getEntriesOfSource(GID::PHS)); for (const auto& tvid : triggersPHOS) { mTotalDataTypes[GID::PHS]++; @@ -327,7 +339,8 @@ void EveWorkflowHelper::selectTowers() } } - const auto triggersEMCAL = gsl::span(trackIndex.data() + vtref.getFirstEntryOfSource(GID::EMC), vtref.getEntriesOfSource(GID::EMC)); + const auto triggersEMCAL = gsl::span(trackIndex.data() + vtref.getFirstEntryOfSource(GID::EMC), + vtref.getEntriesOfSource(GID::EMC)); for (const auto& tvid : triggersEMCAL) { mTotalDataTypes[GID::EMC]++; @@ -416,11 +429,14 @@ void EveWorkflowHelper::draw(std::size_t primaryVertexIdx, bool sortTracks) break; case GID::TPC: { float dz = 0.f; - if (conf.PVMode) { // for TPC the nominal time (center of the bracket) is stored but in the PVMode we correct it by the PV time + if (conf.PVMode) { + // for TPC the nominal time (center of the bracket) is stored but in the PVMode we correct it by the PV time tim = pvTime; const auto& tpcTr = mRecoCont->getTPCTrack(gid); - if (!tpcTr.hasBothSidesClusters()) { // need to correct track Z with this vertex time - float dz = (tpcTr.getTime0() * mTPCTimeBins2MUS - (pvTime + mTPCVDrift->getTimeOffset())) * mTPCVDrift->getVDrift(); + if (!tpcTr.hasBothSidesClusters()) { + // need to correct track Z with this vertex time + float dz = (tpcTr.getTime0() * mTPCTimeBins2MUS - (pvTime + mTPCVDrift->getTimeOffset())) * + mTPCVDrift->getVDrift(); if (tpcTr.hasCSideClustersOnly()) { dz = -dz; } @@ -500,14 +516,25 @@ void EveWorkflowHelper::draw(std::size_t primaryVertexIdx, bool sortTracks) } } -void EveWorkflowHelper::save(const std::string& jsonPath, const std::string& ext, int numberOfFiles) +void EveWorkflowHelper::save(const std::string& jsonPath, const std::string& ext, int numberOfFiles, + const std::string& receiverHostname, int receiverPort, int receiverTimeout, bool useOnlyFiles, + bool useOnlySockets) { mEvent.setEveVersion(o2_eve_version); - FileProducer producer(jsonPath, ext, numberOfFiles); - VisualisationEventSerializer::getInstance(ext)->toFile(mEvent, producer.newFileName()); + FileProducer producer(jsonPath, ext); + producer.reduceNumberOfFiles(numberOfFiles); + Location location({.fileName = producer.newFileName(), + .port = receiverPort, + .timeout = receiverTimeout, + .host = receiverHostname, + .toFile = !useOnlySockets, + .toSocket = !useOnlyFiles}); + VisualisationEventSerializer::getInstance(ext)->toFile(mEvent, location); } -std::vector EveWorkflowHelper::getTrackPoints(const o2::track::TrackPar& trc, float minR, float maxR, float maxStep, float minZ, float maxZ) +std::vector + EveWorkflowHelper::getTrackPoints(const o2::track::TrackPar& trc, float minR, float maxR, float maxStep, float minZ, + float maxZ) { // adjust minR according to real track start from track starting point auto maxR2 = maxR * maxR; @@ -528,7 +555,8 @@ std::vector EveWorkflowHelper::getTrackPoints(const o2::track::TrackPar& tr auto tp = trc; float dxmin = std::abs(xMin - tp.getX()), dxmax = std::abs(xMax - tp.getX()); - if (dxmin > dxmax) { // start from closest end + if (dxmin > dxmax) { + // start from closest end std::swap(xMin, xMax); dx = -dx; } @@ -556,7 +584,8 @@ std::vector EveWorkflowHelper::getTrackPoints(const o2::track::TrackPar& tr return pnts; } -void EveWorkflowHelper::addTrackToEvent(const o2::track::TrackPar& tr, GID gid, float trackTime, float dz, GID::Source source, float maxStep) +void EveWorkflowHelper::addTrackToEvent(const o2::track::TrackPar& tr, GID gid, float trackTime, float dz, + GID::Source source, float maxStep) { if (source == GID::NSources) { source = (o2::dataformats::GlobalTrackID::Source)gid.getSource(); @@ -599,7 +628,8 @@ void EveWorkflowHelper::prepareITSClusters(const o2::itsmft::TopologyDictionary* } } -void EveWorkflowHelper::prepareMFTClusters(const o2::itsmft::TopologyDictionary* dict) // do we also have something as ITS...dict? +void EveWorkflowHelper::prepareMFTClusters( + const o2::itsmft::TopologyDictionary* dict) // do we also have something as ITS...dict? { const auto& MFTClusterROFRec = this->mRecoCont->getMFTClustersROFRecords(); const auto& clusMFT = this->mRecoCont->getMFTClusters(); @@ -669,7 +699,8 @@ void EveWorkflowHelper::drawEMC(GID gid) const auto& conf = EveConfParam::Instance(); for (const auto& cell : cellsForTrigger) { - if (!(cell.getType() == o2::emcal::ChannelType_t::HIGH_GAIN || cell.getType() == o2::emcal::ChannelType_t::LOW_GAIN)) { + if (!(cell.getType() == o2::emcal::ChannelType_t::HIGH_GAIN || + cell.getType() == o2::emcal::ChannelType_t::LOW_GAIN)) { // Select FEE cells (excluding LEDMON or TRU cells) continue; } @@ -738,7 +769,7 @@ void EveWorkflowHelper::drawTPCTRD(GID gid, float trackTime, GID::Source source) const auto& tpcTrdTrack = mRecoCont->getTPCTRDTrack(gid); addTrackToEvent(tpcTrdTrack, gid, trackTime, 0., source); drawTPCClusters(tpcTrdTrack.getRefGlobalTrackId(), trackTime * mMUS2TPCTimeBins); - drawTRDClusters(tpcTrdTrack); // tracktime + drawTRDClusters(tpcTrdTrack); // tracktime } void EveWorkflowHelper::drawITSTPCTRD(GID gid, float trackTime, GID::Source source) @@ -774,7 +805,7 @@ void EveWorkflowHelper::drawTPCTOF(GID gid, float trackTime) const auto& match = mRecoCont->getTPCTOFMatch(gid.getIndex()); addTrackToEvent(trTPCTOF, gid, trackTime, 0); drawTPCClusters(match.getTrackRef(), trackTime * mMUS2TPCTimeBins); - drawTOFClusters(gid); // trackTime + drawTOFClusters(gid); // trackTime } void EveWorkflowHelper::drawMFTMCH(GID gid, float trackTime) @@ -832,8 +863,9 @@ void EveWorkflowHelper::drawMCHMID(GID gid, float trackTime) void EveWorkflowHelper::drawAODBarrel(EveWorkflowHelper::AODBarrelTrack const& track, float trackTime) { - const std::array arraypar = {track.y(), track.z(), track.snp(), - track.tgl(), track.signed1Pt()}; + const std::array arraypar = { + track.y(), track.z(), track.snp(), + track.tgl(), track.signed1Pt()}; const auto tr = o2::track::TrackPar(track.x(), track.alpha(), arraypar); @@ -907,7 +939,9 @@ void EveWorkflowHelper::drawForwardTrack(GID gid, mch::TrackParam track, float s auto vTrack = mEvent.addTrack({.time = static_cast(trackTime), .charge = 0, .PID = o2::track::PID::Muon, - .startXYZ = {(float)track.getNonBendingCoor(), (float)track.getBendingCoor(), (float)track.getZ()}, + .startXYZ = { + (float)track.getNonBendingCoor(), (float)track.getBendingCoor(), + (float)track.getZ()}, .phi = (float)0, .theta = (float)0, .eta = (float)0, @@ -950,7 +984,8 @@ void EveWorkflowHelper::drawTOFClusters(GID gid) void EveWorkflowHelper::drawITSClusters(GID gid) // float trackTime { - if (gid.getSource() == GID::ITS) { // this is for for full standalone tracks + if (gid.getSource() == GID::ITS) { + // this is for for full standalone tracks const auto& trc = mRecoCont->getITSTrack(gid); auto refs = mRecoCont->getITSTracksClusterRefs(); int ncl = trc.getNumberOfClusters(); @@ -961,7 +996,8 @@ void EveWorkflowHelper::drawITSClusters(GID gid) // float trackTime float xyz[] = {glo.X(), glo.Y(), glo.Z()}; drawPoint(xyz); // trackTime; } - } else if (gid.getSource() == GID::ITSAB) { // this is for ITS tracklets from ITS-TPC afterburner + } else if (gid.getSource() == GID::ITSAB) { + // this is for ITS tracklets from ITS-TPC afterburner const auto& trc = mRecoCont->getITSABRef(gid); const auto& refs = mRecoCont->getITSABClusterRefs(); int ncl = trc.getNClusters(); @@ -990,9 +1026,12 @@ void EveWorkflowHelper::drawTPCClusters(GID gid, float trackTimeTB) const auto& clTPC = trc.getCluster(mTPCTracksClusIdx, iCl, *mTPCClusterIdxStruct, sector, row); std::array xyz; - this->mTPCFastTransform->TransformIdeal(sector, row, clTPC.getPad(), clTPC.getTime(), xyz[0], xyz[1], xyz[2], trackTimeTB); // in sector coordinate - o2::math_utils::rotateZ(xyz, o2::math_utils::sector2Angle(sector % o2::tpc::SECTORSPERSIDE)); // lab coordinate (global) - mEvent.addCluster(xyz.data()); // trackTimeTB / mMUS2TPCTimeBins + this->mTPCFastTransform->TransformIdeal(sector, row, clTPC.getPad(), clTPC.getTime(), xyz[0], xyz[1], xyz[2], + trackTimeTB); // in sector coordinate + o2::math_utils::rotateZ(xyz, o2::math_utils::sector2Angle( + sector % o2::tpc::SECTORSPERSIDE)); // lab coordinate (global) + mEvent.addCluster( + xyz.data()); // trackTimeTB / mMUS2TPCTimeBins } } @@ -1018,8 +1057,10 @@ void EveWorkflowHelper::drawTPC(GID gid, float trackTime, float dz) } addTrackToEvent(tr, gid, trackTime, dz, GID::TPC); - float clTime0 = EveConfParam::Instance().PVMode ? trackTime * mMUS2TPCTimeBins : -2e9; // in PVMode use supplied real time converted to TB, otherwise pass dummy time to use tpcTrack.getTime0 - drawTPCClusters(gid, clTime0); // trackTime + float clTime0 = EveConfParam::Instance().PVMode + ? trackTime * mMUS2TPCTimeBins + : -2e9; // in PVMode use supplied real time converted to TB, otherwise pass dummy time to use tpcTrack.getTime0 + drawTPCClusters(gid, clTime0); // trackTime } void EveWorkflowHelper::drawITS(GID gid, float trackTime) @@ -1074,7 +1115,9 @@ void EveWorkflowHelper::drawMID(GID gid, float trackTime) auto vTrack = mEvent.addTrack({.time = static_cast(trackTime), .charge = (int)0, .PID = o2::track::PID::Muon, - .startXYZ = {(float)midTrack.getPositionX(), (float)midTrack.getPositionY(), (float)midTrack.getPositionZ()}, + .startXYZ = { + (float)midTrack.getPositionX(), (float)midTrack.getPositionY(), + (float)midTrack.getPositionZ()}, .phi = (float)0, .theta = (float)0, .eta = (float)0, @@ -1149,9 +1192,12 @@ EveWorkflowHelper::EveWorkflowHelper() } o2::mch::TrackExtrap::setField(); this->mMFTGeom = o2::mft::GeometryTGeo::Instance(); - this->mMFTGeom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); + this->mMFTGeom->fillMatrixCache( + o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::L2G)); this->mITSGeom = o2::its::GeometryTGeo::Instance(); - this->mITSGeom->fillMatrixCache(o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, o2::math_utils::TransformType::L2G)); + this->mITSGeom->fillMatrixCache( + o2::math_utils::bit2Mask(o2::math_utils::TransformType::T2L, o2::math_utils::TransformType::T2GRot, + o2::math_utils::TransformType::L2G)); this->mEMCALGeom = o2::emcal::Geometry::GetInstance(""); this->mPHOSGeom = o2::phos::Geometry::GetInstance(""); this->mTPCFastTransform = (o2::tpc::TPCFastTransformHelperO2::instance()->create(0)); @@ -1161,10 +1207,18 @@ EveWorkflowHelper::EveWorkflowHelper() mTPCBin2MUS = elParams.ZbinWidth; const auto grp = o2::base::GRPGeomHelper::instance().getGRPECS(); const auto& alpParamsITS = o2::itsmft::DPLAlpideParam::Instance(); - mITSROFrameLengthMUS = grp->isDetContinuousReadOut(o2::detectors::DetID::ITS) ? alpParamsITS.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingMUS : alpParamsITS.roFrameLengthTrig * 1.e-3; + mITSROFrameLengthMUS = grp->isDetContinuousReadOut(o2::detectors::DetID::ITS) + ? alpParamsITS.roFrameLengthInBC * + o2::constants::lhc::LHCBunchSpacingMUS + : alpParamsITS.roFrameLengthTrig * + 1.e-3; const auto& alpParamsMFT = o2::itsmft::DPLAlpideParam::Instance(); - mMFTROFrameLengthMUS = grp->isDetContinuousReadOut(o2::detectors::DetID::MFT) ? alpParamsMFT.roFrameLengthInBC * o2::constants::lhc::LHCBunchSpacingMUS : alpParamsMFT.roFrameLengthTrig * 1.e-3; + mMFTROFrameLengthMUS = grp->isDetContinuousReadOut(o2::detectors::DetID::MFT) + ? alpParamsMFT.roFrameLengthInBC * + o2::constants::lhc::LHCBunchSpacingMUS + : alpParamsMFT.roFrameLengthTrig * + 1.e-3; mPVParams = &o2::vertexing::PVertexerParams::Instance(); @@ -1177,7 +1231,8 @@ void EveWorkflowHelper::setTPCVDrift(const o2::tpc::VDriftCorrFact* v) { mTPCVDrift = v; if (v) { - o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mTPCFastTransform.get(), 0, v->corrFact, v->refVDrift, v->getTimeOffset()); + o2::tpc::TPCFastTransformHelperO2::instance()->updateCalibration(*mTPCFastTransform.get(), 0, v->corrFact, + v->refVDrift, v->getTimeOffset()); } } @@ -1198,11 +1253,14 @@ GID::Source EveWorkflowHelper::detectorMapToGIDSource(uint8_t dm) return GID::TPCTOF; case static_cast(o2::aod::track::TPC) | static_cast(o2::aod::track::TRD): return GID::TPCTRD; - case static_cast(o2::aod::track::ITS) | static_cast(o2::aod::track::TPC) | static_cast(o2::aod::track::TRD): + case static_cast(o2::aod::track::ITS) | static_cast(o2::aod::track::TPC) | + static_cast(o2::aod::track::TRD): return GID::ITSTPCTRD; - case static_cast(o2::aod::track::ITS) | static_cast(o2::aod::track::TPC) | static_cast(o2::aod::track::TOF): + case static_cast(o2::aod::track::ITS) | static_cast(o2::aod::track::TPC) | + static_cast(o2::aod::track::TOF): return GID::ITSTPCTOF; - case static_cast(o2::aod::track::TPC) | static_cast(o2::aod::track::TRD) | static_cast(o2::aod::track::TOF): + case static_cast(o2::aod::track::TPC) | static_cast(o2::aod::track::TRD) | + static_cast(o2::aod::track::TOF): return GID::TPCTRDTOF; default: return GID::ITSTPCTRDTOF; diff --git a/EventVisualisation/Workflow/src/FileProducer.cxx b/EventVisualisation/Workflow/src/FileProducer.cxx index c50dcb8fad135..01e68240bfe6a 100644 --- a/EventVisualisation/Workflow/src/FileProducer.cxx +++ b/EventVisualisation/Workflow/src/FileProducer.cxx @@ -30,13 +30,18 @@ using std::chrono::duration_cast; using std::chrono::milliseconds; using std::chrono::system_clock; -FileProducer::FileProducer(const std::string& path, const std::string& ext, int filesInFolder, const std::string& name) +FileProducer::FileProducer(const std::string& path, const std::string& ext, const std::string& name) { - this->mFilesInFolder = filesInFolder; this->mPath = path; this->mName = name; this->mExt = ext; - o2::utils::createDirectoriesIfAbsent(path); // create folder if not exists (fails if no rights) + o2::utils::createDirectoriesIfAbsent(path); // create a folder if not exists (fails if no rights) +} + +void FileProducer::reduceNumberOfFiles(size_t filesInFolder) const +{ + const std::vector ext = {".json", ".root", ".eve"}; + DirectoryLoader::reduceNumberOfFiles(this->mPath, DirectoryLoader::load(this->mPath, "_", ext), filesInFolder); } std::string FileProducer::newFileName() const @@ -52,8 +57,5 @@ std::string FileProducer::newFileName() const fmt::arg("pid", pid), fmt::arg("timestamp", millisec_since_epoch), fmt::arg("ext", this->mExt)); - const std::vector ext = {".json", ".root", ".eve"}; - DirectoryLoader::reduceNumberOfFiles(this->mPath, DirectoryLoader::load(this->mPath, "_", ext), this->mFilesInFolder); - return this->mPath + "/" + result; } diff --git a/EventVisualisation/Workflow/src/O2DPLDisplay.cxx b/EventVisualisation/Workflow/src/O2DPLDisplay.cxx index e02e1ee20ce58..bd8ab5a664d99 100644 --- a/EventVisualisation/Workflow/src/O2DPLDisplay.cxx +++ b/EventVisualisation/Workflow/src/O2DPLDisplay.cxx @@ -60,6 +60,11 @@ void customize(std::vector& workflowOptions) { std::vector options{ {"jsons-folder", VariantType::String, "jsons", {"name of the folder to store json files"}}, + {"receiver-hostname", VariantType::String, "arcbs04.cern.ch", {"name of the host where visualisation data is transmitted (only eve format)"}}, + {"receiver-port", VariantType::Int, 8001, {"port number of the host where visualisation data is transmitted (only eve format)"}}, + {"receiver-timeout", VariantType::Int, 300, {"socket connection timeout (ms)"}}, + {"use-only-files", VariantType::Bool, false, {"do not transmit visualisation data using sockets (only eve format)"}}, + {"use-only-sockets", VariantType::Bool, false, {"do not store visualisation data using filesystem"}}, {"use-json-format", VariantType::Bool, false, {"instead of eve format (default) use json format"}}, {"use-root-format", VariantType::Bool, false, {"instead of eve format (default) use root format"}}, {"eve-hostname", VariantType::String, "", {"name of the host allowed to produce files (empty means no limit)"}}, @@ -186,7 +191,7 @@ void O2DPLDisplaySpec::run(ProcessingContext& pc) helper.mEvent.setRunType(this->mRunType); helper.mEvent.setPrimaryVertex(pv); helper.mEvent.setCreationTime(tinfo.creation); - helper.save(this->mJsonPath, this->mExt, conf.maxFiles); + helper.save(this->mJsonPath, this->mExt, conf.maxFiles, this->mReceiverHostname, this->mReceiverPort, this->mReceiverTimeout, this->mUseOnlyFiles, this->mUseOnlySockets); filesSaved++; currentTime = std::chrono::high_resolution_clock::now(); // time AFTER save this->mTimeStamp = currentTime; // next run AFTER period counted from last save @@ -302,6 +307,12 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) bool useMC = !cfgc.options().get("disable-mc"); bool disableWrite = cfgc.options().get("disable-write"); + auto receiverHostname = cfgc.options().get("receiver-hostname"); + auto receiverPort = cfgc.options().get("receiver-port"); + auto receiverTimeout = cfgc.options().get("receiver-timeout"); + auto useOnlyFiles = cfgc.options().get("use-only-files"); + auto useOnlySockets = cfgc.options().get("use-only-sockets"); + char hostname[_POSIX_HOST_NAME_MAX]; gethostname(hostname, _POSIX_HOST_NAME_MAX); bool eveHostNameMatch = eveHostName.empty() || eveHostName == hostname; @@ -398,7 +409,9 @@ WorkflowSpec defineDataProcessing(ConfigContext const& cfgc) "o2-eve-export", dataRequest->inputs, {}, - AlgorithmSpec{adaptFromTask(disableWrite, useMC, srcTrk, srcCl, dataRequest, ggRequest, emcalCalibLoader, jsonFolder, ext, timeInterval, eveHostNameMatch)}}); + AlgorithmSpec{adaptFromTask(disableWrite, useMC, srcTrk, srcCl, dataRequest, ggRequest, + emcalCalibLoader, jsonFolder, ext, timeInterval, eveHostNameMatch, + receiverHostname, receiverPort, receiverTimeout, useOnlyFiles, useOnlySockets)}}); // configure dpl timer to inject correct firstTForbit: start from the 1st orbit of TF containing 1st sampled orbit o2::raw::HBFUtilsInitializer hbfIni(cfgc, specs);