#ifndef __JDB__JDETECTORINTEGRATION_T__ #define __JDB__JDETECTORINTEGRATION_T__ #include #include #include #include #include #include #include #include "JTools/JRange.hh" #include "JDB/JDB.hh" #include "JDB/JProductIntegration.hh" #include "JDB/JPBS_t.hh" #include "JDB/JUPI_t.hh" #include "JDB/JDate_t.hh" #include "JLang/JException.hh" #include "JLang/JWhiteSpacesFacet.hh" #include "JLang/JLangToolkit.hh" #include "JLang/JPredicate.hh" #include "dbclient/KM3NeTDBClient.h" /** * \author mdejong */ namespace JDATABASE {} namespace JPP { using namespace JDATABASE; } namespace JDATABASE { using JLANG::JDatabaseException; using JLANG::JException; /** * Type definition of period. */ typedef JTOOLS::JRange JPeriod_t; /** * Write period to output stream. * * \param out output stream * \param object period * \return output stream */ inline std::ostream& operator<<(std::ostream& out, const JPeriod_t& object) { return out << "(" << object.getLowerLimit() << "," << object.getUpperLimit() << ")"; } /** * Auxiliary class for product integration data. * * This class is primarily used to * - convert the string data from JDATABASE::JProductIntegration to corresponding data structures; * - implement efficient (in)equality operations; */ struct JProductIntegration_t { /** * Default constructor. */ JProductIntegration_t() : status(false) {} /** * Constructor. * * \param input product integration data */ JProductIntegration_t(const JProductIntegration& input) : status(false) { using namespace std; this->operation = input.OPERATIONID; this->position = input.POSITION; this->container = input.CONTAINER_UPI; this->content = input.CONTENT_UPI; istringstream(input.STARTD) >> this->start_date; istringstream(input.ENDD) >> this->end_date; } /** * Check product status. * * \return true if set; else false */ bool is_set() const { return status; } /** * Set product status. */ void set() { status = true; } /** * Unset product status. */ void unset() { status = false; } /** * Read product integration from input stream. * * \param in input stream * \param object product integration * \return input stream */ friend inline std::istream& operator>>(std::istream& in, JProductIntegration_t& object) { using namespace std; in >> object.operation >> object.container >> object.content >> object.position >> object.start_date >> object.end_date; return in; } /** * Write product integration to output stream. * * \param out output stream * \param object product integration * \return output stream */ friend inline std::ostream& operator<<(std::ostream& out, const JProductIntegration_t& object) { using namespace std; out << object.operation << ' ' << object.container << ' ' << object.content << ' ' << object.position << ' ' << object.start_date << ' ' << object.end_date; return out; } std::string operation; int position; JUPI_t container; JUPI_t content; JDateAndTime_t start_date; JDateAndTime_t end_date; bool status; }; /** * Detector integration. * * This class is used * - to read product integration data from the data base; * - to organise detector specific integration data in memory; * - to efficiently %trace a product; * - to efficiently %find product(s); * * Note that the method JDetectorIntegration_t::configure should be used to set up the integration data for a specific detector. */ struct JDetectorIntegration_t : public std::vector { static const char* const getName() { return JProductIntegration::getName(); } //!< Table name typedef std::multimap map_type; typedef std::pair range_type; typedef map_type::const_iterator range_const_iterator; typedef map_type::const_iterator range_iterator; /** * Default constructor. */ JDetectorIntegration_t() {} /** * Configure detector integration for given detector identifier. * * The components of the given detector are selected based on the following rules: * -# the component should have a start date before that of the given detector; * -# if multiple components appear at the same place in the same container, * the one with the latest start date is taken. * * The option can be used to retain only those products that are part of the given detector. * * \param detid detector identifier * \param option option */ void configure(const std::string& detid, const bool option = false) { using namespace std; using namespace JPP; up .clear(); down.clear(); out .clear(); for (size_t index = 0; index != this->size(); ++index) { JProductIntegration_t& product = (*this)[index]; product.unset(); if (product.content != JUPI_t()) { up .insert(make_pair(product.content .getUPI(), index)); down.insert(make_pair(product.container.getUPI(), index)); } else { out .insert(make_pair(product.container.getUPI(), index)); } } for (iterator product = this->begin(); product != this->end(); ++product) { if (product->operation == detid) { configure(*product, JPeriod_t(product->start_date, product->end_date)); } } if (option) { this->erase(partition(this->begin(), this->end(), make_predicate(&JProductIntegration_t::is_set, true)), this->end()); } up .clear(); down.clear(); for (size_t index = 0; index != this->size(); ++index) { const JProductIntegration_t& product = (*this)[index]; if (product.is_set()) { up .insert(make_pair(product.content .getUPI(), index)); down.insert(make_pair(product.container.getUPI(), index)); } } } /** * Trace product up to given integration level. * * \param upi %UPI * \param pbs %PBS * \return product */ const JProductIntegration_t& trace(const JUPI_t& upi, const JPBS_t& pbs = PBS::DETECTOR) const { using namespace std; if (upi.getPBS() >= pbs) { const range_type range = find(upi); switch (distance(range.first, range.second)) { case 1: { const JProductIntegration_t& product = (*this)[range.first->second]; if (product.container.getPBS() == pbs) return product; else return trace(product.container.getUPI(), pbs); } case 0: THROW(JDatabaseException, "Invalid UPI " << upi); default: THROW(JDatabaseException, "Ambiguous integration of UPI " << upi); } } else { THROW(JDatabaseException, "Invalid PBS " << upi.getPBS() << " < " << pbs); } } /** * Print product trace. * * \param out output stream * \param upi %UPI */ void print(std::ostream& out, const JUPI_t& upi) const { using namespace std; range_type range; range = find(upi); for (map_type::const_iterator i = range.first; i != range.second; ++i) { out << upi << " -> "; print(out, (*this)[i->second]); } range = down.equal_range(upi); for (range_iterator i = range.first; i != range.second; ++i) { out << "<- " << (*this)[i->second] << endl; } } /** * Print product trace. * * \param out output stream * \param product product */ void print(std::ostream& out, const JProductIntegration_t& product) const { using namespace std; out << product.container.getUPI() << ' ' //<< JPeriod_t(product.start_date, product.end_date) << ' ' << "-> "; const range_type range = find(product.container.getUPI()); for (map_type::const_iterator i = range.first; i != range.second; ++i) { print(out, (*this)[i->second]); } if (distance(range.first, range.second) != 1) { out << product.operation << std::endl; } } /** * Read detector integration from result set. * * \param rs result set * \param detector detector * \return true if read; else false */ friend inline bool operator>>(ResultSet& rs, JDetectorIntegration_t& detector) { using namespace std; for (JProductIntegration parameters; rs >> parameters; ) { const JProductIntegration_t product(parameters); detector.up .insert(make_pair(product.content .getUPI(), detector.size())); detector.down.insert(make_pair(product.container.getUPI(), detector.size())); detector.push_back(product); } rs.Close(); return true; } /** * Load detector integration from CSV formatted input file. * * The input should be conform output of JPrintDB -q "integration" -c ";" -W1. * * \param file_name file name * \param separator separator */ void load(const char* const file_name, const std::string& separator = ";") { using namespace std; using namespace JPP; ifstream in(file_name); in.ignore(numeric_limits::max(), '\n'); for (string buffer; getline(in, buffer); ) { istringstream is(buffer); const locale loc(is.getloc(), new JWhiteSpacesFacet(is.getloc(), separator)); is.imbue(loc); JProductIntegration parameters; is >> buffer; istringstream(trim(buffer)) >> parameters.OPERATIONID; is >> buffer; istringstream(trim(buffer)) >> parameters.CITY; is >> buffer; istringstream(trim(buffer)) >> parameters.LOCATIONID; is >> buffer; istringstream(trim(buffer)) >> parameters.LOGIN; is >> buffer; istringstream(trim(buffer)) >> parameters.USERID; is >> buffer; istringstream(trim(buffer)) >> parameters.STARTD; is >> buffer; istringstream(trim(buffer)) >> parameters.ENDD; is >> buffer; istringstream(trim(buffer)) >> parameters.CONTAINER_UPI; is >> buffer; istringstream(trim(buffer)) >> parameters.POSITION; is >> buffer; istringstream(trim(buffer)) >> parameters.CONTENT_UPI; const JProductIntegration_t product(parameters); this->up .insert(make_pair(product.content .getUPI(), this->size())); this->down.insert(make_pair(product.container.getUPI(), this->size())); this->push_back(product); } in.close(); } /** * Read detector integration from input stream. * * \param in input stream * \param object detector integration * \return input stream */ friend inline std::istream& operator>>(std::istream& in, JDetectorIntegration_t& object) { using namespace std; for (JProductIntegration_t product; in >> product; ) { object.up .insert(make_pair(product.content .getUPI(), object.size())); object.down.insert(make_pair(product.container.getUPI(), object.size())); object.push_back(product); } return in; } /** * Write detector integration to output stream. * * \param out output stream * \param object detector integration * \return output stream */ friend inline std::ostream& operator<<(std::ostream& out, const JDetectorIntegration_t& object) { for (const_iterator i = object.begin(); i != object.end(); ++i) { out << *i << std::endl; } return out; } /** * Find range of products with given %UPI.\n * The returned range corresponds to the usual begin and end iterators, * each pointing to an STL pair consisting of a %UPI and index. * * \param upi %UPI * \return index */ range_type find(const JUPI_t& upi) const { return up.equal_range(upi); } /** * Find range of products with given %PBS.\n * The returned range corresponds to the usual begin and end iterators, * each pointing to an STL pair consisting of a %UPI and index. * * \param pbs %PBS * \return range */ range_type find(const JPBS_t& pbs) const { range_const_iterator p = up.lower_bound(JUPI_t(pbs)); range_const_iterator q = p; while (q != up.end() && (*this)[q->second].content.getPBS() <= pbs) { ++q; } return range_type(p,q); } /** * Get components of product with given %UPI.\n * The returned range corresponds to the usual begin and end iterators, * each pointing to an STL pair consisting of a %UPI and index. * * \param upi %UPI * \return index */ range_type get(const JUPI_t& upi) const { return down.equal_range(upi); } /** * Compare two product integrations. * * \param first first product integration * \param second second product integration * \return true if first integrated before second; else false */ static inline bool compare(const JProductIntegration_t& first, const JProductIntegration_t& second) { if (first.start_date == second.start_date) return first.operation < second.operation; else return first.start_date < second.start_date; } protected: /** * Configure detector integration for given detector identifier.\n * This method recursively sets the status all related products. * * \param product product * \param period validity period */ void configure(JProductIntegration_t& product, const JPeriod_t& period) { using namespace std; range_type range; range = out.equal_range(product.container); for (range_iterator i = range.first; i != range.second; ++i) { const JProductIntegration_t& object = (*this)[i->second]; if (object.position == product.position && object.start_date <= period.getLowerLimit() && object.start_date > product.start_date) { return; } } product.set(); map zmap; // position -> index range = down.equal_range(product.content); for (range_iterator i = range.first; i != range.second; ++i) { const JProductIntegration_t& object = (*this)[i->second]; if (object.start_date <= period.getLowerLimit()) { if (zmap.count(object.position) == 0 || compare((*this)[zmap[object.position]], object)) { zmap[object.position] = i->second; } } } for (map::iterator i = zmap.begin(); i != zmap.end(); ++i) { configure((*this)[i->second], period); } } map_type up; //!< up link %UPI to integration data map_type down; //!< down link %UPI to integration data map_type out; //!< link %UPI to disintegrated data }; } #endif