#ifndef __JDETECTOR__JDETECTOR__ #define __JDETECTOR__JDETECTOR__ #include #include #include #include #include #include "JLang/JMultiEquals.hh" #include "JLang/JException.hh" #include "JLang/JManip.hh" #include "Jeep/JComment.hh" #include "JDetector/JDetectorID.hh" #include "JDetector/JDetectorVersion.hh" #include "JDetector/JDetectorHeader.hh" #include "JDetector/JPMT.hh" #include "JDetector/JModule.hh" #include "JDetector/JPMTAddress.hh" #include "JDetector/JModuleAddress.hh" #include "JGeometry3D/JVector3D.hh" #include "JIO/JSerialisable.hh" #include "JIO/JByteArrayIO.hh" #include "JIO/JSTDIO.hh" /** * \file * * Data structure for detector geometry and calibration. * \author mdejong */ namespace JDETECTOR {} namespace JPP { using namespace JDETECTOR; } namespace JDETECTOR { using JLANG::JMultiEquals; using JLANG::JTYPELIST; using JLANG::JIndexOutOfRange; using JLANG::JIOException; using JEEP::JComment; using JIO::JSerialisable; using JIO::JReader; using JIO::JWriter; using JGEOMETRY3D::JVector3D; /** * Detector data structure. * * A detector consists of a header and a list of modules, each of which consists of a list of PMTs. * Each PMT comprises position, orientation and time calibration data. * Note that the index of the PMT in the module data structure corresponds to the readout channel (TDC). * * The following formats and file name extension are supported: * * * * * * * *
extension format function
".detx" ASCII I/O
".gz" gzipped ASCII I/O
".dat" binary I/O
".det" ASCII I
* * The different formats can transparently be read and written using the methods: *
   *    inline void load(const JString& file_name, JDetector& detector);
   *    inline void store(const JString& file_name, const JDetector& detector);
   * 
* respectively. * These methods are available in the include file JDetectorToolkit.hh. * * The JDETECTOR::JModuleRouter and JDETECTOR::JPMTRouter classes provide for fast look-up * methods of module and PMT calibration data for real data and Monte Carlo data, respectively.\n * Note that the (not) equal operator strictly applies to the detector identifier and version. * For quantitative comparisons, use JCompareDetector.cc.\n * The official detector description document is available on the google drive for anyone with a %KM3NeT account.\n * It can directly be found at this link. * * For a given detector, * the module identifier (JModule::getID) and * the PMT identifier (JPMT::getID) * are unique.\n * The serial number in the %UPI of a PMT is equal to its identifier in the detector description.\n * For more information on the %PBS (product breakdown structure) and %UPI (universal product identifier), * see this link. */ class JDetector : public JDetectorID, public JDetectorVersion, public JDetectorHeader, public std::vector, public JMultiEquals::typelist>, public JSerialisable { public: /** * Default constructor. */ JDetector() : JDetectorID(), JDetectorVersion(), JDetectorHeader (), std::vector(), JSerialisable() {} /** * Constructor. * * \param id detector identifier * \param version version * \param header header */ JDetector(const JDetectorID& id, const JVersion& version, const JDetectorHeader& header) : JDetectorID(id), JDetectorVersion(version), JDetectorHeader (header), std::vector(), JSerialisable() { setVersion(); } /** * Set version. * * \param version version */ void setVersion(const JVersion& version) { static_cast(*this).setVersion(version.getVersion()); setVersion(); } /** * Set version. * * Note that the version is only set to a higher version or when forced to set it. * * \param version version * \param force force setting of version * \return true if set; else false */ bool setVersion(const JDetectorVersion::JVersion_t& version, const bool force = false) { if (this->getVersion() == JDetectorVersion() || version > getDetectorVersion(this->getVersion()) || force) { setVersion(putDetectorVersion(version)); return true; } return false; } /** * Set to latest version. * * \return true if set; else false */ bool setToLatestVersion() { return setVersion(getLatestDetectorVersion()); } /** * Set status of all modules. * * \param bit bit */ void setModuleStatus(const int bit) { for (iterator module = this->begin(); module != this->end(); ++module) { module->getStatus().set(bit); } } /** * Reset status of all modules. * * \param bit bit */ void resetModuleStatus(const int bit) { for (iterator module = this->begin(); module != this->end(); ++module) { module->getStatus().reset(bit); } } /** * Set status of all PMTs. * * \param bit bit */ void setPMTStatus(const int bit) { for (iterator module = this->begin(); module != this->end(); ++module) { for (JModule::iterator pmt = module->begin(); pmt != module->end(); ++pmt) { pmt->getStatus().set(bit); } } } /** * Reset status of all PMTs. * * \param bit bit */ void resetPMTStatus(const int bit) { for (iterator module = this->begin(); module != this->end(); ++module) { for (JModule::iterator pmt = module->begin(); pmt != module->end(); ++pmt) { pmt->getStatus().reset(bit); } } } /** * Move detector elements. * * \param pos offset position * \return this JDetector */ JDetector& operator+=(const JVector3D& pos) { for (iterator i = begin(); i != end(); ++i) { i->add(pos); } return *this; } /** * Move detector elements. * * \param pos offset position * \return this JDetector */ JDetector& operator-=(const JVector3D& pos) { for (iterator i = begin(); i != end(); ++i) { i->sub(pos); } return *this; } /** * Get module parameters. * * \param address module address * \return module parameters */ const JModule& getModule(const JModuleAddress& address) const { return at(address.first); } /** * Get module parameters. * * \param address module address * \return module parameters */ JModule& getModule(const JModuleAddress& address) { return at(address.first); } /** * Check availability of module parameters. * * \param location module location * \return true if available; else false */ bool hasModule(const JLocation& location) const { for (JDetector::const_iterator module = this->begin(); module != this->end(); ++module) { if (module->getLocation() == location) { return true; } } return false; } /** * Get module parameters. * * \param location module location * \return module parameters */ const JModule& getModule(const JLocation& location) const { for (JDetector::const_iterator module = this->begin(); module != this->end(); ++module) { if (module->getLocation() == location) { return *module; } } THROW(JIndexOutOfRange, "Invalid location " << location); } /** * Get module parameters. * * \param location module location * \return module parameters */ JModule& getModule(const JLocation& location) { for (JDetector::iterator module = this->begin(); module != this->end(); ++module) { if (module->getLocation() == location) { return *module; } } THROW(JIndexOutOfRange, "Invalid location " << location); } /** * Get PMT parameters. * * \param address JPMTAddress * \return JPMT */ const JPMT& getPMT(const JPMTAddress& address) const { return at(address.first).at(address.second); } /** * Get PMT parameters. * * \param address JPMTAddress * \return JPMT */ JPMT& getPMT(const JPMTAddress& address) { return at(address.first).at(address.second); } /** * Read detector from input. * * \param in input stream * \param detector detector * \return input stream */ friend inline std::istream& operator>>(std::istream& in, JDetector& detector) { using namespace std; detector.clear(); string buffer; if (in >> detector.comment >> static_cast(detector) >> buffer) { int number_of_modules; int version = -1; try { version = getDetectorVersion(buffer); } catch(std::exception&) {} switch (version) { default: in >> static_cast(detector); case V1: in >> number_of_modules; detector.setVersion(buffer); break; case -1: detector.setVersion(putDetectorVersion(V1)); istringstream(buffer) >> number_of_modules; break; } for (JModule module; number_of_modules != 0 && in >> module; --number_of_modules) { detector.push_back(module); } } return in; } /** * Write detector to output. * * \param out output stream * \param detector detector * \return output stream */ friend inline std::ostream& operator<<(std::ostream& out, const JDetector& detector) { using namespace std; using namespace JPP; detector.setVersion(); setFormat (JFormat_t( 9, 3, std::ios::fixed | std::ios::showpos)); setFormat (JFormat_t( 9, 6, std::ios::fixed | std::ios::showpos)); setFormat(JFormat_t( 9, 6, std::ios::fixed | std::ios::showpos)); setFormat (JFormat_t(10, 3, std::ios::fixed | std::ios::showpos)); if (getDetectorVersion(detector.getVersion()) >= V3) { out << detector.comment; } out << static_cast(detector); switch (getDetectorVersion(detector.getVersion())) { default: out << " "; out << static_cast(detector) << endl; out << static_cast (detector) << endl; break; case V1: out << " "; break; } out << detector.size() << endl; for (const_iterator i = detector.begin(); i != detector.end(); ++i) { out << *i << endl; } return out; } /** * Read from input. * * \param in reader * \return reader */ virtual JReader& read(JReader& in) override { using namespace std; using namespace JPP; this->clear(); const int N = (getStartOfComment() == NEW_START_OF_COMMENT ? LENGTH_START_OF_COMMENT : 1); char prefix[sizeof(JDetectorID)]; for (string buffer; in.read(prefix, N) == N && count(prefix, prefix + N, JComment::START_COMMENT) == N; ) { in >> buffer; this->comment.add(buffer); } if (this->comment.empty()) { THROW(JIOException, "Missing comments"); } in.read(&prefix[N], sizeof(JDetectorID) - N); JByteArrayReader is(prefix, N); int number_of_modules; is >> static_cast (*this); in >> static_cast(*this); in >> static_cast (*this); in >> number_of_modules; this->setVersion(); this->resize(number_of_modules); for (JDetector::iterator out = this->begin(); number_of_modules != 0; --number_of_modules, ++out) { in >> *out; } return in; } /** * Write to output. * * \param out writer * \return writer */ virtual JWriter& write(JWriter& out) const override { using namespace std; using namespace JPP; if (getDetectorVersion(this->getVersion()) < V3 || this->comment.empty()) { THROW(JIOException, "Version " << getDetectorVersion(this->getVersion()) << " < " << V3 << " or missing comments."); } this->setVersion(); if (getDetectorVersion(this->getVersion()) >= V3) { for (JComment::const_iterator i = this->comment.begin(); i != this->comment.end(); ++i) { for (size_t i = 0; i != LENGTH_START_OF_COMMENT; ++i) { out << JComment::START_COMMENT; } out << *i; } } const int number_of_modules = this->size(); out << static_cast (*this); out << static_cast(*this); out << static_cast (*this); out << number_of_modules; for (const_iterator module = this->begin(); module != this->end(); ++module) { out << *module; } return out; } JComment comment; /** * Enumeration for different lengths of start of comment in binary I/O. */ enum start_of_comment_type { OLD_START_OF_COMMENT, NEW_START_OF_COMMENT }; /** * Get option for short start of comment in binary I/O. * * \return option */ static start_of_comment_type getStartOfComment() { return get_start_of_comment(); } /** * Set option for short start of comment in binary I/O. * * \param option option */ static void setStartOfComment(const start_of_comment_type option) { get_start_of_comment() = option; } protected: /** * Set version. * * This method should be called to set up the handling of detector version specific module and PMT I/O. */ void setVersion() const { JModule::setVersion(this->getVersion()); JPMT ::setVersion(this->getVersion()); } /** * Get option for short start of comment in binary I/O. * * \return option */ static start_of_comment_type& get_start_of_comment() { static start_of_comment_type start_of_comment = NEW_START_OF_COMMENT; return start_of_comment; } /** * Length of start of comment in binary I/O. */ static const size_t LENGTH_START_OF_COMMENT = sizeof(JDetectorID); }; } #endif