diff --git a/Detectors/HMPID/CMakeLists.txt b/Detectors/HMPID/CMakeLists.txt index 8bf5341885d33..5906902fa1f9a 100644 --- a/Detectors/HMPID/CMakeLists.txt +++ b/Detectors/HMPID/CMakeLists.txt @@ -1,16 +1,19 @@ -# 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. +#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". +#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 +#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. add_subdirectory(base) add_subdirectory(simulation) add_subdirectory(reconstruction) add_subdirectory(workflow) - +add_subdirectory(calibration) +if (BUILD_TESTING) +add_subdirectory(calibration/macros) +endif() diff --git a/Detectors/HMPID/calibration/CMakeLists.txt b/Detectors/HMPID/calibration/CMakeLists.txt new file mode 100644 index 0000000000000..16fae7ce76abd --- /dev/null +++ b/Detectors/HMPID/calibration/CMakeLists.txt @@ -0,0 +1,51 @@ +#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. + +o2_add_library(HMPIDCalibration + TARGETVARNAME targetName + SOURCES src/HMPIDDCSProcessor.cxx + PUBLIC_LINK_LIBRARIES O2::HMPIDBase + O2::Framework + O2::DataFormatsHMP + O2::HMPIDSimulation + O2::SimulationDataFormat + O2::DetectorsBase + O2::DetectorsCalibration + O2::DetectorsDCS + O2::DetectorsRaw + O2::CCDB + ROOT::Physics + ROOT::Minuit + O2::Steer + Microsoft.GSL::GSL) + +o2_target_root_dictionary(HMPIDCalibration + HEADERS include/HMPIDCalibration/HMPIDDCSProcessor.h) + + +if (OpenMP_CXX_FOUND) + target_compile_definitions(${targetName} PRIVATE WITH_OPENMP) + target_link_libraries(${targetName} PRIVATE OpenMP::OpenMP_CXX) +endif() + +o2_add_executable(hmpid-dcs-sim-workflow# run with o2-calibration-hmpid-dcs-workflow + COMPONENT_NAME calibration # adds calibration to the above command + SOURCES testWorkflow/hmpid-dcs-sim-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::HMPIDCalibration + O2::DCStestWorkflow) + +o2_add_executable(hmpid-dcs-workflow # run with o2-calibration-hmpid-dcs-workflow + COMPONENT_NAME calibration # adds calibration to the above command + SOURCES testWorkflow/hmpid-dcs-data-workflow.cxx + PUBLIC_LINK_LIBRARIES O2::Framework + O2::HMPIDCalibration + O2::DCStestWorkflow) diff --git a/Detectors/HMPID/calibration/include/HMPIDCalibration/HMPIDDCSProcessor.h b/Detectors/HMPID/calibration/include/HMPIDCalibration/HMPIDDCSProcessor.h new file mode 100644 index 0000000000000..0ee8ed2d8940b --- /dev/null +++ b/Detectors/HMPID/calibration/include/HMPIDCalibration/HMPIDDCSProcessor.h @@ -0,0 +1,434 @@ +// 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. + +#ifndef HMPIDDCSPROCESSOR_H +#define HMPIDDCSPROCESSOR_H + +// HMPID Base +#include "HMPIDBase/Geo.h" +#include "HMPIDBase/Param.h" + +// Root classes: +#include +#include +#include +#include + +// miscallenous libraries +#include +#include +#include +#include +#include + +// O2 includes: +#include "CCDB/CcdbApi.h" +#include "CCDB/CcdbObjectInfo.h" +#include "CommonUtils/MemFileHelper.h" +#include "DetectorsCalibration/Utils.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "Framework/Logger.h" + +using CcdbObjectInfo = o2::ccdb::CcdbObjectInfo; +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPCOM = o2::dcs::DataPointCompositeObject; +using DeliveryType = o2::dcs::DeliveryType; + +namespace o2::hmpid +{ + +using namespace std::literals; +using TimeStampType = uint64_t; + +class HMPIDDCSProcessor +{ + + public: + struct TimeRange { + uint64_t first = std::numeric_limits::max(); + uint64_t last = std::numeric_limits::min(); + }; + + HMPIDDCSProcessor() = default; + ~HMPIDDCSProcessor() = default; + + // Process Datapoints: + // ======================================================================================================== + + // process span of DPs: + // process DPs, fetch IDs and call processIR or processHMPID + void init(const std::vector& pids); + + void process(const gsl::span dps); + + void processTRANS(const DPCOM& dp); + void processHMPID(const DPCOM& dp); + + // Fill entries of DPs================================================== + void fillChPressure( + const DPCOM& dpcom); // fill element[0-6] in chamber-pressure vector + + void fillEnvPressure(const DPCOM& dpcom); // fill environment-pressure vector + + // HV in each chamber_section = 7*3 --> will result in Q_thre + void fillHV(const DPCOM& dpcom); // fill element[0-20] in HV vector + + // Temp in (T1) and out (T2), in each chamber_radiator = 7*3 : + void fillTempIn(const DPCOM& dpcom); // fill element[0-20] in tempIn vector + void fillTempOut(const DPCOM& dpcom); // fill element[0-20] in tempOut vector + + // =====finalize DPs, after run is finished + // ================================================================================== + // functions return nullptr if there is no entry in the array of DPCOM-vectors at + // the given element + std::unique_ptr finalizeEnvPressure(); + std::unique_ptr finalizeChPressure(int iCh); + std::unique_ptr finalizeHv(int iCh, int iSec); + void finalizeTempOut(int iCh, int iRad); + void finalizeTempIn(int iCh, int iRad); + + // called from HMPIDDCSDataProcessorSpec, + // loops over all the arrays of DPCOM-vectors, and calls the relevant + // fill()-methods above + void finalize(); + + //===== procTrans + //=================================================================================================== + double defaultEMean(); // just set a refractive index for C6F14 at ephot=6.675 + // eV @ T=25 C + + double procTrans(); + + bool evalCorrFactor(double dRefArgon, double dCellArgon, double dRefFreon, + double dCellFreon, double photEn, int i); + double dpVector2Double(const std::vector& dpVec, const char* dpString, int i); + double calculateWaveLength(int i); + + //===== help-functions + //================================================================================ + void setStartValidity(long t) + { + mStartValidity = t; + LOGP(info, "mStartValidity {}", mStartValidity); + } + + void resetStartValidity() + { + mStartValidity = o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP; + } + + // ef : runindenpendent, only used for verifying fits + void setEndValidityRunIndependent(long t) + { + mEndValidity = t + 3 * o2::ccdb::CcdbObjectInfo::DAY; // ef : add some time for validity + LOGP(info, "mEndValidity {}", mStartValidity); // after startValidity + } + + // ef : set end validity when Runstatus == STOP + void setEndValidityRunSpecific(long t) + { + mEndValidity = t; + LOGP(info, "mEndValidity {}", mStartValidity); + } + + void resetEndValidity() + { + mEndValidity = o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP; + } + + long getStartValidity() { return mStartValidity; } + + void useVerboseMode() { mVerbose = true; } + + // convert char in aliasString to int + int aliasStringToInt(const DPID& dpid, std::size_t startIndex); + int subStringToInt(std::string istr, std::size_t si); + uint64_t processFlags(const uint64_t flags, const char* pid); + + //===== DCS-CCDB methods and members Used in + // HMPIDDCSDataProcessor=============================================================== + + CcdbObjectInfo& getccdbRefInfo() { return mccdbRefInfo; } + std::vector getRefIndexObj() { return arNmean; } + + CcdbObjectInfo& getHmpidChargeInfo() { return mccdbChargeInfo; } + std::vector& getChargeCutObj() { return arQthre; } + + void clearCCDBObjects() + { + arQthre.clear(); + arNmean.clear(); + } + + // get methods for time-ranges + // =============================================================================== + // const auto& getTimeQThresh() const { return mTimeQThresh; } + // const auto& getTimeArNmean() const { return mTimeArNmean; } + + /// / return timestamp of first fetched datapoint for a given ID (Tin/Tout, + /// Environment pressure, HV, chamber pressure) + TimeStampType getMinTime(const std::vector& dps) + { + TimeStampType firstTime = std::numeric_limits::max(); + for (const auto& dp : dps) { + const auto time = dp.data.get_epoch_time(); + firstTime = std::min(firstTime, time); + } + return firstTime; + } + // return timestamp of last fetched datapoint for a given ID (Tin/Tout, + // Environment pressure, HV, chamber pressure) + TimeStampType getMaxTime(const std::vector& dps) + { + TimeStampType lastTime = 0; + for (const auto& dp : dps) { + + // check if tme of DP is greater (i.e. later) than previously latest + // fetched DP: + const auto time = dp.data.get_epoch_time(); + lastTime = std::max(lastTime, time); + } + return lastTime; + } + + void checkEntries(const std::vector& arQthresh, + const std::vector& arrayNmean) + { + int cnt = 0; + bool arQthreFull = true; + + LOG(info) << " "; + LOG(info) << "======================================== "; + LOG(info) << "All entries Processed"; + LOG(info) << " checking if CCDB objects are filled : "; + + for (int iCh = 0; iCh < 7; ++iCh) { + for (int iSec = 0; iSec < 6; ++iSec) { + auto tf = arQthresh[6 * iCh + iSec]; + const char* strCCDB = tf.GetName(); + const char* strExpected = Form("HMP_QthreC%iS%i", iCh, iSec); + + if (strcmp(strCCDB, strExpected) != 0) { + arQthreFull = false; + LOG(info) << "arQthre at " << 6 * iCh + iSec << "empty"; + } + // if(tf.Getr) + } + } + + cnt = 0; + bool arNmeanFull = true; + for (int iCh = 0; iCh < 7; ++iCh) { + for (int iRad = 0; iRad < 3; iRad += 2) { + + const char* strCcdbin = (arrayNmean[6 * iCh + 2 * iRad]).GetName(); + const char* strCcdbinOut = + (arrayNmean[6 * iCh + 2 * iRad + 1]).GetName(); + + const char* strExpectedIn = Form("Tin%i%i", iCh, iRad); + const char* strExpectedOut = Form("Tout%i%i", iCh, iRad); + + if (strcmp(strCcdbin, strExpectedIn) != 0) { + arNmeanFull = false; + LOG(info) << "arNmean at " << 6 * iCh + 2 * iRad << " empty"; + } + if (strcmp(strCcdbinOut, strExpectedOut) != 0) { + arNmeanFull = false; + LOG(info) << "arNmean at " << 6 * iCh + 2 * iRad + 1 << " empty"; + } + } + } + + if (strcmp((arrayNmean[42]).GetName(), "HMP_PhotEmean") != 0) { + arNmeanFull = false; + } + + if (arQthreFull) { + LOG(info) << Form("arQthre Full Sized"); + } + if (arNmeanFull) { + LOG(info) << Form("arNmean Full Sized"); + } + if (arNmeanFull && arQthreFull) { + LOG(info) << Form("All entries of CCDB objects are filled"); + } + LOG(info) << " "; + LOG(info) << "======================================== "; + } + + void clearDPsInfo() + { + mPids.clear(); + } + + int getRunNumberFromGRP() + { + return mRunNumberFromGRP; + } // ef : just using the same as for emcal + + void setRunNumberFromGRP(int rn) + { + mRunNumberFromGRP = rn; + } // ef : just using the same as for emcal + private: + std::unordered_map mPids; + + int mRunNumberFromGRP = -2; // ef : just using the same as for emcal + + // ======= DCS-CCDB + // ========================================================================================== + + long mFirstTime; // time when a CCDB object was stored first + long mStartValidity = o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP; // TF index for processing, used to store CCDB object + long mEndValidity = o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP; + long mStart = 0; // TF index for processing, used to store CCDB object + bool mFirstTimeSet = false; + + bool mVerbose = false; + + CcdbObjectInfo mccdbRefInfo; + CcdbObjectInfo mccdbChargeInfo; + + // objects to be stored in CCDB: + // refractive index: + std::vector arNmean; // 43 21* Tin and 21*Tout (1 per radiator, 3 + // radiators per chambers) + // + 1 for ePhotMean (mean photon energy) + // Charge Threshold: + std::vector arQthre; // 42 Qthre=f(time) one per sector + + //======= finalize() and fill() private variables + //============================================================ + Double_t xP, yP; + + // env pressure + int cntEnvPressure = 0; // cnt Environment-pressure entries + std::vector dpVecEnv; // environment-pressure vector + + // ch pressure + int cntChPressure = 0; // cnt chamber-pressure entries in element iCh[0..6] + std::vector dpVecCh[7]; // chamber-pressure vector [0..6] + std::unique_ptr pArrCh = std::unique_ptr(new TF1[7]); + + // Temperature + int cntTin = 0, + cntTOut = + 0; // cnt tempereature entries in element i[0..20]; i = 3*iCh+iSec + std::vector dpVecTempIn[21]; // tempIn vector [0..20] + std::vector dpVecTempOut[21]; // tempOut vector [0..20] + + // HV + int cntHV = 0; // cnt HV entries in element i[0..41]; i = iCh*6 + iSec + std::vector dpVecHV[42]; // HV vector [0..41]; 7 chambers * 6 sectors + std::unique_ptr pArrHv = std::unique_ptr(new TF1[24]); + + // procTrans variables + // ====================================================================== + const double eMeanDefault = 6.675; // Default mean photon energy if + // DP is invalid or not fetched + + double sEnergProb = 0, sProb = 0; // energy probaility, probability + double eMean = 0; // initialize eMean (Photon energy mean) to 0 + + double aCorrFactor[30] = { + 0.937575212, 0.93805688, 0.938527113, 0.938986068, 0.939433897, + 0.939870746, 0.940296755, 0.94071206, 0.941116795, 0.941511085, + 0.941895054, 0.942268821, 0.942632502, 0.942986208, 0.943330047, + 0.943664126, 0.943988544, 0.944303401, 0.944608794, 0.944904814, + 0.945191552, 0.945469097, 0.945737533, 0.945996945, 0.946247412, + 0.946489015, 0.94672183, 0.946945933, 0.947161396, 0.947368291}; + + double nm2eV; // conversion factor, nanometer to eV + double photEn; // photon energy + + // wavelength + double lambda; + std::vector waveLenVec[30]; + + // phototube current for argon reference + double refArgon; + std::vector argonRefVec[30]; + + // phototube current for freon reference + double refFreon; + std::vector freonRefVec[30]; + + // phototube current for argon cell + double cellArgon; + std::vector argonCellVec[30]; + + // phototube current for freon cell + double cellFreon; + std::vector freonCellVec[30]; + + double aTransRad, aConvFactor; // evaluate 15 mm of thickness C6F14 Trans + double aTransSiO2; // evaluate 0.5 mm of thickness SiO2 Trans + double aTransGap; // evaluate 80 cm of thickness Gap (low density CH4) + // transparency + double aCsIQE; // evaluate CsI quantum efficiency + double aTotConvolution; // evaluate total convolution of all material optical + // properties + + // indexes for getting chamber-numbers etc + // ======================================================================================= + + // Chamber Pressures + std::size_t indexChPr = 6; + + // High Voltage + std::size_t indexChHv = 7; + std::size_t indexSecHv = 13; + + // Temperatures + std::size_t indexChTemp = 6; + std::size_t indexRadTemp = 21; + + // Timestamps and TimeRanges + // ====================================================================================== + // timestamps of last and first entry in vectors of DPCOMs + uint64_t hvFirstTime, hvLastTime; + uint64_t chPrFirstTime, chPrLastTime; + uint64_t envPrFirstTime, envPrLastTime; + + uint64_t timeTinFirst, timeTinLast; + uint64_t timeToutFirst, timeToutLast; + + TimeRange mTimeEMean; // Timerange for mean photon energy(procTrans) + + //======= constExpression string-literals to assign DPs to the correct method: + //==================================================== + + // check if Transparency or other HMPID specifciation + static constexpr auto HMPID_ID{"HMP_"sv}; + static constexpr auto TRANS_ID{"HMP_TRANPLANT_MEASURE_"sv}; + // HMPID-temp, HV, pressure IDs (HMP_{"HMP_"sv};) + static constexpr auto TEMP_OUT_ID{"OUT_TEMP"sv}; + static constexpr auto TEMP_IN_ID{"_IN_TEMP"sv}; + static constexpr auto HV_ID{"_HV_VMON"sv}; + static constexpr auto ENV_PRESS_ID{"ENV_PENV"sv}; + static constexpr auto CH_PRESS_ID{"AS_PMWPC"sv}; + + // HMPID-IR IDs (TRANS_ID{"HMP_TRANPLANT_MEASURE_"sv}) + static constexpr auto WAVE_LEN_ID{"WAVELENGHT"sv}; // 0-9 + static constexpr auto REF_ID{"REFERENCE"sv}; // argonReference and freonRef + static constexpr auto ARGON_CELL_ID{"ARGONCELL"sv}; // argon Cell reference + static constexpr auto FREON_CELL_ID{"C6F14CELL"sv}; // fron Cell Reference + + static constexpr auto ARGON_REF_ID{"ARGONREFERENCE"sv}; // argonReference + static constexpr auto FREON_REF_ID{"C6F14REFERENCE"sv}; // freonReference + + ClassDefNV(HMPIDDCSProcessor, 0); +}; // end class +} // namespace o2::hmpid +#endif diff --git a/Detectors/HMPID/calibration/macros/CMakeLists.txt b/Detectors/HMPID/calibration/macros/CMakeLists.txt new file mode 100644 index 0000000000000..dee2ef31121d4 --- /dev/null +++ b/Detectors/HMPID/calibration/macros/CMakeLists.txt @@ -0,0 +1,24 @@ +# 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. + +o2_add_test_root_macro( + makeHMPIDCCDBEntryForDCS.C + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::CCDB) + +o2_add_test_root_macro( + readHMPIDDCSEntries.C + PUBLIC_LINK_LIBRARIES O2::DetectorsDCS O2::CCDB) + +install( + FILES makeHMPIDCCDBEntryForDCS.C + readHMPIDDCSEntries.C + DESTINATION share/macro/) + diff --git a/Detectors/HMPID/calibration/macros/makeHMPIDCCDBEntryForDCS.C b/Detectors/HMPID/calibration/macros/makeHMPIDCCDBEntryForDCS.C new file mode 100644 index 0000000000000..d307dbd315984 --- /dev/null +++ b/Detectors/HMPID/calibration/macros/makeHMPIDCCDBEntryForDCS.C @@ -0,0 +1,59 @@ +// 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. + +#include +#include +#include "TFile.h" +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/AliasExpander.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/DataPointIdentifier.h" + +#include +#include + +using DPID = o2::dcs::DataPointIdentifier; + +int makeHMPIDCCDBEntryForDCS(const std::string url = "localhost:8080") +{ + + // std::string url(argv[0]); + // macro to populate CCDB for HMPID with the configuration for DCS + std::vector aliases; // vector of strings that will hold DataPoints identifiers + + aliases = {"HMP_ENV_PENV", + "HMP_MP[0..6]_GAS_PMWPC", + "HMP_MP[0..6]_LIQ_LOOP_RAD_[0..2]_IN_TEMP", + "HMP_MP[0..6]_LIQ_LOOP_RAD_[0..2]_OUT_TEMP", + "HMP_MP_[0..6]_SEC_[0..5]_HV_VMON", + "HMP_TRANPLANT_MEASURE_[0..29]_WAVELENGHT", + "HMP_TRANPLANT_MEASURE_[0..29]_ARGONREFERENCE", + "HMP_TRANPLANT_MEASURE_[0..29]_ARGONCELL", + "HMP_TRANPLANT_MEASURE_[0..29]_C6F14REFERENCE", + "HMP_TRANPLANT_MEASURE_[0..29]_C6F14CELL"}; + + std::vector expaliases = o2::dcs::expandAliases(aliases); + + std::unordered_map dpid2DataDesc; + DPID dpidtmp; + for (size_t i = 0; i < expaliases.size(); ++i) { + DPID::FILL(dpidtmp, expaliases[i], o2::dcs::DeliveryType::DPVAL_DOUBLE); + dpid2DataDesc[dpidtmp] = "HMPDATAPOINTS"; + } + + o2::ccdb::CcdbApi api; + api.init(url); // or http://localhost:8080 for a local installation + std::map md; + long ts = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + api.storeAsTFileAny(&dpid2DataDesc, "HMP/Config/DCSDPconfig", md, ts, 99999999999999); + + return 0; +} diff --git a/Detectors/HMPID/calibration/macros/readHMPIDDCSEntries.C b/Detectors/HMPID/calibration/macros/readHMPIDDCSEntries.C new file mode 100644 index 0000000000000..0163bccc43feb --- /dev/null +++ b/Detectors/HMPID/calibration/macros/readHMPIDDCSEntries.C @@ -0,0 +1,63 @@ +// 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. + +// macro to read the HMP DCS information from CCDB +// Reads the vectors of TF1s and saves them in specified folder +// default ts is very big: Saturday, November 20, 2286 5:46:39 PM + +#if !defined(__CLING__) || defined(__ROOTCLING__) +#include "CCDB/CcdbApi.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "HMPIDCalibration/HMPIDDCSProcessor.h" + +#include "TCanvas.h" +#include "TF1.h" + +#include +#include +#include +#include +#endif +// in root folder; +// to start listening on localhost: java -jar local.jar +void readHMPIDDCSEntries(long ts = 9999999999000, const char* ccdb = "localhost:8080") +{ + + o2::ccdb::CcdbApi api; + api.init(ccdb); // or http://ccdb-test.cern.ch:8080 + std::map metadata; + if (ts == 9999999999000) { + ts = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + } + + std::vector>* mChargeCut = api.retrieveFromTFileAny>>("HMP/Calib/ChargeCut", metadata, ts); + + int cnt = 0; + for (TF1& tf1 : *mChargeCut) { + TCanvas* cChargeCut = new TCanvas(Form("ChargeCut number %i", cnt), Form("ChargeCut number %i", cnt), 1200, 400); + tf1.Draw(); + cChargeCut->SaveAs(Form("/root/hmpidTest/img/HV/ChargeCut number %i.png", cnt)); + cnt++; + } + + std::vector>* mRefIndex = api.retrieveFromTFileAny>>("HMP/Calib/RefIndex", metadata, ts); + // std::cout << "size of mRefIndex = " << mRefIndex->size() << std::endl; + + cnt = 0; + for (TF1& tf1 : *mRefIndex) { + TCanvas* cRefIndex = new TCanvas(Form("RefIndex number %i", cnt), Form("RefIndex number %i", cnt), 1200, 400); + tf1.Draw(); + cRefIndex->SaveAs(Form("/root/hmpidTest/img/HV/RefIndex number %i.png", cnt)); + cnt++; + } + + return; +} diff --git a/Detectors/HMPID/calibration/src/HMPIDCalibrationLinkDef.h b/Detectors/HMPID/calibration/src/HMPIDCalibrationLinkDef.h new file mode 100644 index 0000000000000..e7af30b39e9be --- /dev/null +++ b/Detectors/HMPID/calibration/src/HMPIDCalibrationLinkDef.h @@ -0,0 +1,20 @@ +// 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. + +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ class std::vector < TF1> + ; + +#endif diff --git a/Detectors/HMPID/calibration/src/HMPIDDCSProcessor.cxx b/Detectors/HMPID/calibration/src/HMPIDDCSProcessor.cxx new file mode 100644 index 0000000000000..75a90b5b7bb1a --- /dev/null +++ b/Detectors/HMPID/calibration/src/HMPIDDCSProcessor.cxx @@ -0,0 +1,803 @@ +// 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. + +#include "HMPIDCalibration/HMPIDDCSProcessor.h" +#include + +namespace o2::hmpid +{ + +// initialize map of DPIDs, function is called once in the +// HMPIDDCSDataProcessorSpec::init() function +void HMPIDDCSProcessor::init(const std::vector& pids) +{ + for (const auto& it : pids) { + mPids[it] = false; + } +} + +// process span of Datapoints, function is called repeatedly in the +// HMPIDDCSDataProcessorSpec::run() function +void HMPIDDCSProcessor::process(const gsl::span dps) +{ + + // if there is no entries in span + if (dps.size() == 0) { + LOG(debug) << "Size = 0: "; + return; + } + + if (mVerbose) { + LOG(debug) << "\n\n\nProcessing new DCS DP map\n-----------------"; + } + + if (!mFirstTimeSet) { + mFirstTime = mStartValidity; + mFirstTimeSet = true; + } + + // itterate over span of datapoints + for (const auto& dp : dps) { + const auto& el = mPids.find(dp.id); + + // check if datapoint is within the defined map of DPs for HMPID + if (el == mPids.end()) { + LOG(info) << "DP " << dp.id << "Not found, will not be processed"; + continue; + } + // The aliasstring has been processed: + mPids[dp.id] = true; + + // extract alias-string of DataPoints + const std::string_view alias(dp.id.get_alias()); + const auto detectorId = alias.substr(0, 4); // HMP_ + const auto transparencyId = alias.substr(0, 22); // HMP_TRANPLANT_MEASURE_ + + // check if given dp is from HMPID + if (transparencyId == TRANS_ID) { + processTRANS(dp); + } else if (detectorId == HMPID_ID) { + processHMPID(dp); + } else { + LOG(debug) << "Unknown data point: " << alias; + } + } // end for +} + +// if the string of the dp contains the HMPID-specifier "HMP_", +// but not the Transparency-specifier +void HMPIDDCSProcessor::processHMPID(const DPCOM& dp) +{ + + const std::string alias(dp.id.get_alias()); + const auto hmpidString = alias.substr(alias.length() - 8); + + if (hmpidString == TEMP_IN_ID) { + LOG(debug) << "Temperature_in DP: " << alias; + fillTempIn(dp); + } else if (hmpidString == TEMP_OUT_ID) { + LOG(debug) << "Temperature_out DP: " << alias; + fillTempOut(dp); + } else if (hmpidString == HV_ID) { + LOG(debug) << "HV DP: " << alias; + fillHV(dp); + } else if (hmpidString == ENV_PRESS_ID) { + LOG(debug) << "Environment Pressure DP: " << alias; + fillEnvPressure(dp); + } else if (hmpidString == CH_PRESS_ID) { + LOG(debug) << "Chamber Pressure DP: " << alias; + fillChPressure(dp); + } else { + LOG(debug) << "Unknown data point: " << alias; + } +} + +// if the string of the dp contains the Transparency-specifier +// "HMP_TRANPLANT_MEASURE_" +void HMPIDDCSProcessor::processTRANS(const DPCOM& dp) +{ + const auto& dpid = dp.id; + const std::string alias(dpid.get_alias()); + const auto transparencyString = alias.substr(alias.length() - 9); + + // exeptions have to be caught: + // const auto stringNum = alias.substr(22,2); + // const int num = stoi(stringNum); + + // Get index [0..29] of Transparency-measurement + const int dig1 = aliasStringToInt(dpid, 22); + const int dig2 = aliasStringToInt(dpid, 23); + const int num = dig1 * 10 + dig2; + + if (dig1 == -1 || dig2 == -1) { + LOG(debug) << "digits in string invalid" << dig1 << " " << dig2; + return; + } + + if (num < 0 || num > 29) { + LOG(debug) << "num out of range " << num; + return; + } + + if (alias.substr(alias.length() - 10) == WAVE_LEN_ID) { + waveLenVec[num].push_back(dp); + LOG(debug) << "WAVE_LEN_ID DP: " << alias; + } else if (transparencyString == FREON_CELL_ID) { + freonCellVec[num].push_back(dp); + LOG(debug) << "FREON_CELL_ID DP: " << alias; + } else if (transparencyString == ARGON_CELL_ID) { + LOG(debug) << "ARGON_CELL_ID DP: " << alias; + argonCellVec[num].push_back(dp); + } else if (transparencyString == REF_ID) { + if (alias.substr(alias.length() - 14) == ARGON_REF_ID) { + LOG(debug) << "ARGON_REF_ID DP: " << alias; + argonRefVec[num].push_back(dp); + } else if (alias.substr(alias.length() - 14) == FREON_REF_ID) { + freonRefVec[num].push_back(dp); + LOG(debug) << "FREON_REF_ID DP: " << alias; + } else { + LOG(debug) << "Unknown data point: " << alias; + } + } else { + LOG(debug) << "Datapoint not found: " << alias; + } +} + +// ======Fill +// DPCOM-entries=========================================================== + +// fill entries in environment pressure DPCOM-vector +void HMPIDDCSProcessor::fillEnvPressure(const DPCOM& dpcom) +{ + auto& dpid = dpcom.id; + const auto& type = dpid.get_type(); + + // check if datatype is as expected + if (type == DeliveryType::DPVAL_DOUBLE) { + dpVecEnv.push_back(dpcom); + } else { + LOG(debug) << "Invalid Datatype for Env Pressure"; + } +} + +// fill entries in chamber-pressure DPCOM-vector +void HMPIDDCSProcessor::fillChPressure(const DPCOM& dpcom) +{ + + auto& dpid = dpcom.id; + const auto& type = dpid.get_type(); + + if (type == DeliveryType::DPVAL_DOUBLE) { + + // find chamber number: + auto chNum = aliasStringToInt(dpid, indexChPr); + if (chNum < 7 && chNum >= 0) { + dpVecCh[chNum].push_back(dpcom); + } else { + LOG(debug) << "Chamber Number out of range for Pressure : " << chNum; + } + } else { + LOG(debug) << "Not correct datatype for Pressure : "; + } +} + +// HV in each chamber_section = 7*3 --> will result in Q_thre +void HMPIDDCSProcessor::fillHV(const DPCOM& dpcom) +{ + auto& dpid = dpcom.id; + const auto& type = dpid.get_type(); + + if (type == DeliveryType::DPVAL_DOUBLE) { + const auto chNum = aliasStringToInt(dpid, indexChHv); + const auto secNum = aliasStringToInt(dpid, indexSecHv); + + if (chNum < 7 && chNum >= 0) { + if (secNum < 6 && secNum >= 0) { + dpVecHV[6 * chNum + secNum].push_back(dpcom); + } else { + LOG(debug) << "Sector Number out of range for HV : " << secNum; + } + } else { + LOG(debug) << "Chamber Number out of range for HV : " << chNum; + } + } else { + LOG(debug) << "Not correct datatype for HV DP"; + } +} + +// Temp in (T1) in each chamber_radiator = 7*3 +void HMPIDDCSProcessor::fillTempIn(const DPCOM& dpcom) +{ + auto& dpid = dpcom.id; + const auto& type = dpid.get_type(); + + if (type == DeliveryType::DPVAL_DOUBLE) { + auto chNum = aliasStringToInt(dpid, indexChTemp); + auto radNum = aliasStringToInt(dpid, indexRadTemp); + + // verify chamber- and raiator-numbers + if (chNum < 7 && chNum >= 0) { + if (radNum < 3 && radNum >= 0) { + dpVecTempIn[3 * chNum + radNum].push_back(dpcom); + } else { + LOG(debug) << "Radiator Number out of range for TempIn :" << radNum; + } + } else { + LOG(debug) << "Chamber Number out of range for TempIn DP :" << chNum; + } + } else { + LOG(debug) << "Not correct datatype for TempIn DP "; + } +} + +// Temp out (T2), in each chamber_radiator = 7*3 +void HMPIDDCSProcessor::fillTempOut(const DPCOM& dpcom) +{ + auto& dpid = dpcom.id; + const auto& type = dpid.get_type(); + + if (type == DeliveryType::DPVAL_DOUBLE) { + auto chNum = aliasStringToInt(dpid, indexChTemp); + auto radNum = aliasStringToInt(dpid, indexRadTemp); + + // verify chamber- and raiator-numbers + if (chNum < 7 && chNum >= 0) { + if (radNum < 3 && radNum >= 0) { + dpVecTempOut[3 * chNum + radNum].push_back(dpcom); + + } else { + LOG(debug) << "Radiator Number out of range for TempOut DP : " + << radNum; + } + } else { + LOG(debug) << "Chamber Number out of range for TempOut DP : " << chNum; + } + } else { + LOG(debug) << "Not correct datatype for TempOut DP "; + } +} + +//==== Calculate mean photon energy============================================= + +double HMPIDDCSProcessor::procTrans() +{ + for (int i = 0; i < 30; i++) { + + photEn = calculateWaveLength(i); + + if (photEn < o2::hmpid::Param::ePhotMin() || + photEn > o2::hmpid::Param::ePhotMax()) { + LOG(info) << "photon energy out of range" << photEn; + continue; // if photon energy is out of range + } + + // ===== evaluate phototube current for argon reference + // ============================================================== + refArgon = dpVector2Double(argonRefVec[i], "ARGONREF", i); + if (refArgon == eMeanDefault) { + LOG(info) << "refArgon == defaultEMean()"; + return defaultEMean(); + } + + //===== evaluate phototube current for argon cell + //================================================================== + cellArgon = dpVector2Double(argonCellVec[i], "ARGONCELL", i); + if (cellArgon == eMeanDefault) { + LOG(info) << "cellArgon == defaultEMean()"; + return defaultEMean(); + } + + //====evaluate phototube current for freon reference + //================================================================ + refFreon = dpVector2Double(freonRefVec[i], "C6F14REFERENCE", i); + if (refFreon == eMeanDefault) { + LOG(info) << "refFreon == defaultEMean()"; + return defaultEMean(); + } + + // ==== evaluate phototube current for freon cell + // =================================================================== + cellFreon = dpVector2Double(freonCellVec[i], "C6F14CELL", i); + if (cellFreon == eMeanDefault) { + LOG(info) << "cellFreon == defaultEMean()"; + return defaultEMean(); + } + + // evaluate correction factor to calculate trasparency + bool isEvalCorrOk = + evalCorrFactor(refArgon, cellArgon, refFreon, cellFreon, photEn, i); + + // Returns false if dRefFreon * dRefArgon < 0 + if (!isEvalCorrOk) { + return defaultEMean(); + } + + // Evaluate timestamps : + + auto s1 = getMinTime(waveLenVec[i]); + auto s2 = getMinTime(argonRefVec[i]); + auto s3 = getMinTime(argonCellVec[i]); + auto s4 = getMinTime(freonRefVec[i]); + auto s5 = getMinTime(freonCellVec[i]); + + auto e1 = getMaxTime(waveLenVec[i]); + auto e2 = getMaxTime(argonRefVec[i]); + auto e3 = getMaxTime(argonCellVec[i]); + auto e4 = getMaxTime(freonRefVec[i]); + auto e5 = getMaxTime(freonCellVec[i]); + + auto minTime = std::max({s1, s2, s3, s4, s5}); + auto maxTime = std::min({e1, e2, e3, e4, e5}); + + if (minTime < mTimeEMean.first) { + mTimeEMean.first = minTime; + } + if (maxTime > mTimeEMean.last) { + mTimeEMean.last = maxTime; + } + + } // end for + + if (sProb > 0) { + eMean = sEnergProb / sProb; + } else { + LOG(info) << " sProb < 0 "; + return defaultEMean(); + } + + if (eMean < o2::hmpid::Param::ePhotMin() || + eMean > o2::hmpid::Param::ePhotMax()) { + LOG(info) << " eMean out of range " << eMean; + return defaultEMean(); + } + + return eMean; + +} // end ProcTrans + +// ==== procTrans help-functions ============================= + +double HMPIDDCSProcessor::defaultEMean() +{ + LOG(info) << Form(" Mean energy photon calculated ---> %f eV ", eMeanDefault); + return eMeanDefault; +} + +//==== evaluate wavelenght +//======================================================= +double HMPIDDCSProcessor::calculateWaveLength(int i) +{ + // if there is no entries + if (waveLenVec[i].size() == 0) { + LOG(info) << Form("No Data Point values for %i.waveLenght", i); + return defaultEMean(); // will break this entry in foor loop + } + + DPCOM dp = (waveLenVec[i])[0]; + + // check if datatype is as expected + if (dp.id.get_type() == DeliveryType::DPVAL_DOUBLE) { + lambda = o2::dcs::getValue(dp); + } else { + LOG(info) << Form( + "Not correct datatype for HMP_TRANPLANT_MEASURE_%i_WAVELENGTH --> " + "Default E mean used!", + i); + return defaultEMean(); + } + + if (lambda < 150. || lambda > 230.) { + LOG(info) << Form( + "Wrong value for HMP_TRANPLANT_MEASURE_%i_WAVELENGTH " + "--> Default E mean used!", + i); + return defaultEMean(); + } + + // find photon energy E in eV from radiation wavelength λ in nm + nm2eV = 1239.842609; // 1239.842609 from nm to eV + photEn = nm2eV / lambda; // photon energy + return photEn; +} + +double HMPIDDCSProcessor::dpVector2Double(const std::vector& dpVec, + const char* dpString, int i) +{ + + double dpVal; + if (dpVec.size() == 0) { + LOG(info) << Form( + "No Data Point values for HMP_TRANPLANT_MEASURE_%s,%i " + "---> Default E mean used!", + dpString, i); + return defaultEMean(); + } + + DPCOM dp = dpVec[0]; + + if (dp.id.get_type() == DeliveryType::DPVAL_DOUBLE) { + dpVal = o2::dcs::getValue(dp); + } else { + LOG(info) << Form( + "Not correct datatype for HMP_TRANPLANT_MEASURE_%s,%i " + "-----> Default E mean used!", + dpString, i); + return defaultEMean(); + } + return dpVal; +} + +bool HMPIDDCSProcessor::evalCorrFactor(double dRefArgon, double dCellArgon, + double dRefFreon, double dCellFreon, + double dPhotEn, int i) +{ + // evaluate correction factor to calculate trasparency (Ref. NIMA 486 (2002) + // 590-609) + + // Double_t aN1 = AliHMPIDParam::NIdxRad(photEn,tRefCR5); + // Double_t aN2 = AliHMPIDParam::NMgF2Idx(photEn); + // Double_t aN3 = 1; // Argon Idx + + // Double_t aR1 = ((aN1 - aN2)*(aN1 - aN2))/((aN1 + aN2)*(aN1 + + // aN2)); Double_t aR2 = ((aN2 - aN3)*(aN2 - aN3))/((aN2 + + // aN3)*(aN2 + aN3)); Double_t aT1 = (1 - aR1); Double_t aT2 = + // (1 - aR2); Double_t aCorrFactor = (aT1*aT1)/(aT2*aT2); + + // evaluate 15 mm of thickness C6F14 Trans + + aConvFactor = 1.0 - 0.3 / 1.8; + + if (dRefFreon * dRefArgon > 0) { + aTransRad = TMath::Power((dCellFreon / dRefFreon) / + (dCellArgon / dRefArgon) * aCorrFactor[i], + aConvFactor); + } else { + LOG(info) << "dRefFreon*dRefArgon<0" << dRefFreon * dRefArgon; + return false; + } + + // evaluate 0.5 mm of thickness SiO2 Trans + + // TMath : Double_t Exp(Double_t x) + aTransSiO2 = TMath::Exp(-0.5 / o2::hmpid::Param::lAbsWin(dPhotEn)); + + // evaluate 80 cm of thickness Gap (low density CH4) transparency + aTransGap = TMath::Exp(-80. / o2::hmpid::Param::lAbsGap(dPhotEn)); + + // evaluate CsI quantum efficiency + // if dPhotEn < 6.07267, the value is zero + aCsIQE = o2::hmpid::Param::qEffCSI(dPhotEn); + + // evaluate total convolution of all material optical properties + aTotConvolution = aTransRad * aTransSiO2 * aTransGap * aCsIQE; + + sEnergProb += aTotConvolution * dPhotEn; + double sProbPrev = sProb; + sProb += aTotConvolution; + + return true; +} +// end Calculate mean photon energy============================================= + +// ==== Functions that are called after run is finished ======================== + +// will return nullptr if there is no entry in Environment-pressure +// DPCOM-vector dpVecEnvPress +std::unique_ptr HMPIDDCSProcessor::finalizeEnvPressure() +{ + std::unique_ptr pEnv; + if (dpVecEnv.size() != 0) { + + envPrFirstTime = getMinTime(dpVecEnv); + envPrLastTime = getMaxTime(dpVecEnv); + + int cntEnvPressure = 0; + std::unique_ptr pGrPenv; + pGrPenv.reset(new TGraph); + + for (DPCOM dp : dpVecEnv) { + auto dpVal = o2::dcs::getValue(dp); + auto time = dp.data.get_epoch_time(); //-envPrFirstTime + pGrPenv->SetPoint(cntEnvPressure++, time, dpVal); + } + // envPrLastTime -= envPrFirstTime; + // envPrFirstTime = 0; + if (cntEnvPressure == 1) { + pGrPenv->GetPoint(0, xP, yP); + pEnv.reset( + new TF1("Penv", Form("%f", yP), envPrFirstTime, envPrLastTime)); + } else { + // envPrLastTime -= envPrFirstTime; + // envPrFirstTime = 0; + pEnv.reset(new TF1("Penv", "1000+x*[0]", envPrFirstTime, envPrLastTime)); + pGrPenv->Fit("Penv", "Q"); + } + return pEnv; + } + LOG(info) << Form("No entries in environment pressure"); + return pEnv; +} + +// returns nullptr if the element in array of DPCOM-vector has no entries +std::unique_ptr HMPIDDCSProcessor::finalizeChPressure(int iCh) +{ + + std::unique_ptr pCh; + if (dpVecCh[iCh].size() != 0) { + cntChPressure = 0; + + std::unique_ptr pGrP; + pGrP.reset(new TGraph); + + chPrFirstTime = getMinTime(dpVecCh[iCh]); + chPrLastTime = getMaxTime(dpVecCh[iCh]); + + for (DPCOM dp : dpVecCh[iCh]) { + auto dpVal = o2::dcs::getValue(dp); + auto time = dp.data.get_epoch_time(); //- chPrFirstTime + pGrP->SetPoint(cntChPressure++, time, dpVal); + } + // chPrLastTime -= chPrFirstTime; + // chPrFirstTime = 0; + if (cntChPressure == 1) { + pGrP->GetPoint(0, xP, yP); + (pCh).reset(new TF1(Form("P%i", iCh), Form("%f", yP), chPrFirstTime, + chPrLastTime)); + pArrCh[iCh] = *(pCh.get()); + } else { + (pCh).reset(new TF1(Form("P%i", iCh), "[0] + x*[1]", chPrFirstTime, + chPrLastTime)); + pGrP->Fit(Form("P%i", iCh), "Q"); + pArrCh[iCh] = *(pCh.get()); + } + return pCh; + } + LOG(info) << Form("no entries in chPres for Pch%i", iCh); + + return pCh; +} + +// process Tempout +void HMPIDDCSProcessor::finalizeTempOut(int iCh, int iRad) +{ + if (dpVecTempOut[3 * iCh + iRad].size() != 0) { + cntTOut = 0; + + auto minTime = getMinTime(dpVecTempOut[3 * iCh + iRad]); + auto maxTime = getMaxTime(dpVecTempOut[3 * iCh + iRad]); + + std::unique_ptr pGrTOut; + pGrTOut.reset(new TGraph); + + for (DPCOM dp : dpVecTempOut[3 * iCh + iRad]) { + auto dpVal = o2::dcs::getValue(dp); + auto time = dp.data.get_epoch_time(); // -minTime + pGrTOut->SetPoint(cntTOut++, time, dpVal); + } + // maxTime -= minTime; + // minTime = 0; + std::unique_ptr pTout; + pTout.reset( + new TF1(Form("Tout%i%i", iCh, iRad), "[0]+[1]*x", minTime, maxTime)); + + if (cntTOut == 1) { + pGrTOut->GetPoint(0, xP, yP); + pTout->SetParameter(0, yP); + pTout->SetParameter(1, 0); + + } else { + pGrTOut->Fit(Form("Tout%i%i", iCh, iRad), "R"); + } + pTout->SetTitle(Form( + "Temp-Out Fit Chamber%i Radiator%i; Time [ms];Temp [C]", iCh, iRad)); + std::vector::iterator itTout = + arNmean.begin() + 6 * iCh + 2 * iRad + 1; + arNmean.insert(itTout, *(pTout.get())); + } else { + LOG(info) << Form("No entries in temp-out for ch%irad%i", iCh, iRad); + } +} + +// process Tempin +void HMPIDDCSProcessor::finalizeTempIn(int iCh, int iRad) +{ + + if (dpVecTempIn[3 * iCh + iRad].size() != 0) { + cntTin = 0; + + auto minTime = getMinTime(dpVecTempIn[3 * iCh + iRad]); + auto maxTime = getMaxTime(dpVecTempIn[3 * iCh + iRad]); + + std::unique_ptr pGrTIn; + pGrTIn.reset(new TGraph); + + for (DPCOM dp : dpVecTempIn[3 * iCh + iRad]) { + auto dpVal = o2::dcs::getValue(dp); + auto time = dp.data.get_epoch_time(); //-minTime + pGrTIn->SetPoint(cntTin++, time, dpVal); + } + // maxTime -= minTime; + // minTime = 0; + std::unique_ptr pTin; + pTin.reset( + new TF1(Form("Tin%i%i", iCh, iRad), "[0]+[1]*x", minTime, maxTime)); + + if (cntTin == 1) { + pGrTIn->GetPoint(0, xP, yP); + pTin->SetParameter(0, yP); + pTin->SetParameter(1, 0); + } else { + pGrTIn->Fit(Form("Tin%i%i", iCh, iRad), "Q"); + } + + pTin->SetTitle(Form("Temp-In Fit Chamber%i Radiator%i; Time [ms]; Temp [C]", + iCh, iRad)); + std::vector::iterator itTin = arNmean.begin() + 6 * iCh + 2 * iRad; + arNmean.insert(itTin, *(pTin.get())); + + } else { + LOG(info) << Form("No entries in temp-in for ch%irad%i", iCh, iRad); + } +} + +// returns nullptr if the element in array of DPCOM-vector has no entries +std::unique_ptr HMPIDDCSProcessor::finalizeHv(int iCh, int iSec) +{ + std::unique_ptr pHvTF; + if (dpVecHV[3 * iCh + iSec].size() != 0) { + + std::unique_ptr pGrHV; + pGrHV.reset(new TGraph); + cntHV = 0; + + hvFirstTime = getMinTime(dpVecHV[3 * iCh + iSec]); + hvLastTime = getMaxTime(dpVecHV[3 * iCh + iSec]); + + for (DPCOM dp : dpVecHV[3 * iCh + iSec]) { + auto dpVal = o2::dcs::getValue(dp); + auto time = dp.data.get_epoch_time(); //- hvFirstTime + pGrHV->SetPoint(cntHV++, time, dpVal); + } + // hvLastTime -= hvFirstTime; + // hvFirstTime = 0; + if (cntHV == 1) { + pGrHV->GetPoint(0, xP, yP); + (pHvTF).reset(new TF1(Form("HV%i_%i", iCh, iSec), Form("%f", yP), + hvFirstTime, hvLastTime)); + pArrHv[3 * iCh + iSec] = *(pHvTF.get()); + } else { + (pHvTF).reset(new TF1(Form("HV%i_%i", iCh, iSec), "[0]+x*[1]", + hvFirstTime, hvLastTime)); + pGrHV->Fit(Form("HV%i_%i", iCh, iSec), "Q"); + pArrHv[3 * iCh + iSec] = *(pHvTF.get()); + } + + return pHvTF; + } + LOG(info) << Form("No entries in HV for ch%isec%i", iCh, iSec); + return pHvTF; +} + +// Process all arrays of DPCOM-vectors, perform fits +// Called At the end of the Stream of DPs, in +// HMPIDDCSDataProcessorSpec::endOfStream() function +void HMPIDDCSProcessor::finalize() +{ + + std::unique_ptr pEnv = finalizeEnvPressure(); + for (int iCh = 0; iCh < 7; iCh++) { + + std::unique_ptr pChPres = finalizeChPressure(iCh); + + // fills up entries 0..41 of arNmean + for (int iRad = 0; iRad < 3; iRad++) { + + finalizeTempIn(iCh, iRad); // 6*iCh + 2*iRad + finalizeTempOut(iCh, iRad); // 6*iCh + 2*iRad + 1 + } + + // Fill entries in arQthre + for (int iSec = 0; iSec < 6; iSec++) { + + std::unique_ptr pHV = finalizeHv(iCh, iSec); + + // only fill if envP, chamP and HV datapoints are all fetched + if (pEnv != nullptr && pChPres != nullptr && pHV != nullptr) { + + const char* hvChar = (pArrHv[3 * iCh + iSec]).GetName(); + const char* chChar = (pArrCh[iCh]).GetName(); + const char* envChar = (pEnv.get())->GetName(); + const char* fFormula = + "3*10^(3.01e-3*%s - 4.72)+170745848*exp(-(%s+%s)*0.0162012)"; + const char* fName = Form(fFormula, hvChar, chChar, envChar); + + auto minTime = std::max({envPrFirstTime, hvFirstTime, chPrFirstTime}); + auto maxTime = std::min({envPrLastTime, hvLastTime, chPrLastTime}); + + std::unique_ptr pQthre; + pQthre.reset(new TF1(Form("HMP_QthreC%iS%i", iCh, iSec), fName, minTime, + maxTime)); + pQthre->SetTitle(Form( + "Charge-Threshold Ch%iSec%i; Time [mS]; Threshold ", iCh, iSec)); + + std::vector::iterator itQthre = arQthre.begin() + 6 * iCh + iSec; + + arQthre.insert(itQthre, *(pQthre.get())); + + } else { + LOG(info) << "Missing entries for HV, envPressure or chPressure"; + } + } + } + + LOG(info) << "======================================== "; + + double eMean = procTrans(); + + std::unique_ptr pPhotMean; + pPhotMean.reset(new TF1("HMP_PhotEmean", Form("%f", eMean), 0, + mTimeEMean.last - mTimeEMean.first)); + std::vector::iterator itArNmean = arNmean.begin() + 42; + + pPhotMean->SetTitle(Form("HMP_PhotEmean; Time [mS]; Photon Energy [eV]")); + + arNmean.insert(itArNmean, *(pPhotMean.get())); + + // Check entries of CCDB-objects + checkEntries(arQthre, arNmean); + + // prepare CCDB: ============================================================= + + std::map md; + md["responsible"] = "CHANGE RESPONSIBLE"; + // o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP + // Refractive index (T_out, T_in, mean photon energy); + o2::calibration::Utils::prepareCCDBobjectInfo( + arNmean, mccdbRefInfo, "HMP/Calib/RefIndex", md, mStartValidity, mStartValidity + 3 * o2::ccdb::CcdbObjectInfo::DAY); + LOG(info) << "mStartValidity = " << mStartValidity; + // charge threshold; + o2::calibration::Utils::prepareCCDBobjectInfo( + arQthre, mccdbChargeInfo, "HMP/Calib/ChargeCut", md, mStartValidity, mStartValidity + 3 * o2::ccdb::CcdbObjectInfo::DAY); +} + +uint64_t HMPIDDCSProcessor::processFlags(const uint64_t flags, + const char* pid) +{ + + // function to process the flag. the return code zero means that all is fine. + // anything else means that there was an issue + + // for now, I don't know how to use the flags, so I do nothing + + if (flags & DPVAL::KEEP_ALIVE_FLAG) { + LOG(debug) << "KEEP_ALIVE_FLAG active for DP " << pid; + } + if (flags & DPVAL::END_FLAG) { + LOG(debug) << "END_FLAG active for DP " << pid; + } + return 0; +} + +// extract string from DPID, convert char at specified element in string +// to int +int HMPIDDCSProcessor::aliasStringToInt(const DPID& dpid, std::size_t startIndex) +{ + + const std::string inputString(dpid.get_alias()); + char stringPos = inputString[startIndex]; + int charInt = ((int)stringPos) - ((int)'0'); + if (charInt < 10 && charInt >= 0) { + return charInt; + } else { + return -1; + } +} +} // namespace o2::hmpid diff --git a/Detectors/HMPID/calibration/testWorkflow/HMPIDDCSDataProcessorSpec.h b/Detectors/HMPID/calibration/testWorkflow/HMPIDDCSDataProcessorSpec.h new file mode 100644 index 0000000000000..e6e1d7d5d152a --- /dev/null +++ b/Detectors/HMPID/calibration/testWorkflow/HMPIDDCSDataProcessorSpec.h @@ -0,0 +1,323 @@ +// 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. + +#ifndef O2_HMPID_DATAPROCESSOR_H +#define O2_HMPID_DATAPROCESSOR_H + +#include "DetectorsDCS/AliasExpander.h" +#include "DetectorsDCS/DataPointCompositeObject.h" +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "DetectorsDCS/DeliveryType.h" +#include "DetectorsDCS/RunStatusChecker.h" +#include + +#include "HMPIDCalibration/HMPIDDCSProcessor.h" + +#include "CCDB/BasicCCDBManager.h" +#include "CCDB/CcdbApi.h" +#include "DataFormatsParameters/GRPECSObject.h" +#include "DetectorsCalibration/Utils.h" +#include "Framework/ConfigParamRegistry.h" +#include "Framework/ControlService.h" +#include "Framework/DeviceSpec.h" +#include "Framework/Logger.h" +#include "Framework/Task.h" +#include "Framework/WorkflowSpec.h" + +namespace o2 +{ +namespace hmpid +{ + +using DPID = o2::dcs::DataPointIdentifier; +using DPVAL = o2::dcs::DataPointValue; +using DPCOM = o2::dcs::DataPointCompositeObject; +using namespace o2::ccdb; +using CcdbManager = o2::ccdb::BasicCCDBManager; +using clbUtils = o2::calibration::Utils; +using HighResClock = std::chrono::high_resolution_clock; +using Duration = std::chrono::duration>; +using namespace o2::framework; +using RunStatus = o2::dcs::RunStatusChecker::RunStatus; + +class HMPIDDCSDataProcessor : public o2::framework::Task +{ + public: + void init(o2::framework::InitContext& ic) final + { + + // will follow HMP-run by default: + //--local-test is passed only when using it on local installation + // to verify fits etc + + mLocalTest = ic.options().get("local-test"); + + if (mLocalTest) { + mCheckRunStartStop = false; + } + LOGP(info, "mCheckRunStartStop {} ", mCheckRunStartStop); + std::vector vect; + + bool useCCDBtoConfigure = ic.options().get("use-ccdb-to-configure"); + LOGP(info, "useCCDBtoConfigure set {} ", useCCDBtoConfigure); + if (useCCDBtoConfigure) { + LOG(info) << "Configuring via CCDB"; + std::string ccdbpath = ic.options().get("ccdb-path"); + auto& mgr = CcdbManager::instance(); + mgr.setURL(ccdbpath); + CcdbApi api; + api.init(mgr.getURL()); + long ts = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + std::unordered_map* dpid2DataDesc = + mgr.getForTimeStamp>( + "HMP/Config/DCSDPconfig", ts); + for (auto& i : *dpid2DataDesc) { + vect.push_back(i.first); + } + } else { + LOG(info) << "Configuring via hardcoded strings"; + std::vector expaliases = o2::dcs::expandAliases(aliases); + + for (const auto& i : expaliases) { + vect.emplace_back(i, o2::dcs::DPVAL_DOUBLE); + // LOG(info) << i; + } + + } // end else + + // LOG(info) << "Listing Data Points for HMPID:"; + // for (auto& i : vect) { + // LOG(info) << i; + // } + + mProcessor = std::make_unique(); + bool useVerboseMode = ic.options().get("use-verbose-mode"); + LOG(info) << " ************************* Verbose?" << useVerboseMode; + + if (useVerboseMode) { + mProcessor->useVerboseMode(); + } + mProcessor->init(vect); + mTimer = HighResClock::now(); + } + + //========================================================================== + + void run(o2::framework::ProcessingContext& pc) final + { + + auto timeNow = HighResClock::now(); + long dataTime = (long)(pc.services().get().creation); + if (dataTime == 0xffffffffffffffff) { + dataTime = std::chrono::duration_cast(timeNow.time_since_epoch()).count(); // in ms + } + + /* ef : only for local simulation to verify fits: + // set startValidity if not set already, and mCheckRunStartStop (--follow-hmpid-run) is not used + if (mProcessor->getStartValidity() == o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP && mCheckRunStartStop == false) + { + mProcessor->setStartValidity(dataTime); + } + */ + + if (mCheckRunStartStop) { + const auto* grp = mRunChecker.check(); // check if there is a run with HMP + // this is an example of what it will return + if (mRunChecker.getRunStatus() == RunStatus::NONE) { + LOGP(info, "No run with is ongoing or finished"); + } else if (mRunChecker.getRunStatus() == + RunStatus::START) { // saw new run with wanted detectors + LOGP(info, "Run {} has started", mRunChecker.getFollowedRun()); + grp->print(); + mProcessor->setRunNumberFromGRP( + mRunChecker.getFollowedRun()); // ef: just the same as for emcal? + // ef: set startValidity here if run-specific object + if (mProcessor->getStartValidity() == o2::ccdb::CcdbObjectInfo::INFINITE_TIMESTAMP) { + mProcessor->setStartValidity(dataTime); + } + } else if (mRunChecker.getRunStatus() == + RunStatus::ONGOING) { // run which was already seen is still + // ongoing + LOGP(info, "Run {} is still ongoing", mRunChecker.getFollowedRun()); + } else if (mRunChecker.getRunStatus() == + RunStatus::STOP) { // run which was already seen was stopped + // (EOR seen) + LOGP(info, "Run {} was stopped", mRunChecker.getFollowedRun()); + } + } else { + mProcessor->setRunNumberFromGRP(-2); // ef: just the same as for emcal? + } + + // process datapoints: + auto dps = pc.inputs().get>("input"); + mProcessor->process(dps); + + // ef: runspecific object : send CCDB + if (mCheckRunStartStop && (mRunChecker.getRunStatus() == RunStatus::STOP)) { + mProcessor->finalize(); + + mProcessor->setEndValidityRunSpecific(dataTime); + + sendChargeThresOutput(pc.outputs()); + sendRefIndexOutput(pc.outputs()); + mProcessor->clearCCDBObjects(); // clears the vectors + mProcessor->clearDPsInfo(); // clear map of DPIDs + mProcessor->resetStartValidity(); + mProcessor->resetEndValidity(); + } + } + + //========================================================================== + + void endOfStream(o2::framework::EndOfStreamContext& ec) final + { + // ef : only for local testing of Fits etc.: + if (mLocalTest) { + auto timeNow = HighResClock::now(); + long dataTime = (long)(ec.services().get().creation); + if (dataTime == 0xffffffffffffffff) { + dataTime = std::chrono::duration_cast(timeNow.time_since_epoch()).count(); // in ms + } + + mProcessor->setEndValidityRunIndependent(dataTime); + mProcessor->finalize(); + + sendChargeThresOutput(ec.outputs()); + sendRefIndexOutput(ec.outputs()); + + mProcessor->clearCCDBObjects(); // clears the vectors + mProcessor->clearDPsInfo(); // clear map of DPIDs + mProcessor->resetStartValidity(); + mProcessor->resetEndValidity(); + } // + } + + //========================================================================== + + private: + // fill CCDB with ChargeThresh (arQthre) + void sendChargeThresOutput(o2::framework::DataAllocator& output) + { + const auto& payload = mProcessor->getChargeCutObj(); + auto& info = mProcessor->getHmpidChargeInfo(); + + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(info) << "Sending object " << info.getPath() << "/" + << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() + << " : " << info.getEndValidityTimestamp(); + output.snapshot( + Output{o2::calibration::Utils::gDataOriginCDBPayload, "ChargeCut", 0}, + *image.get()); + output.snapshot( + Output{o2::calibration::Utils::gDataOriginCDBWrapper, "ChargeCut", 0}, + info); + } + + // fill CCDB with RefIndex (arrMean) + void sendRefIndexOutput(o2::framework::DataAllocator& output) + { + // fill CCDB with RefIndex (std::vector arrMean) + const auto& payload = mProcessor->getRefIndexObj(); + auto& info = mProcessor->getccdbRefInfo(); + + auto image = o2::ccdb::CcdbApi::createObjectImage(&payload, &info); + LOG(info) << "Sending object " << info.getPath() << "/" + << info.getFileName() << " of size " << image->size() + << " bytes, valid for " << info.getStartValidityTimestamp() + << " : " << info.getEndValidityTimestamp(); + + output.snapshot( + Output{o2::calibration::Utils::gDataOriginCDBPayload, "RefIndex", 0}, + *image.get()); + output.snapshot( + Output{o2::calibration::Utils::gDataOriginCDBWrapper, "RefIndex", 0}, + info); + } + + std::vector aliases = { + "HMP_ENV_PENV", + "HMP_MP[0..6]_GAS_PMWPC", + "HMP_MP[0..6]_LIQ_LOOP_RAD_[0..2]_IN_TEMP", + "HMP_MP[0..6]_LIQ_LOOP_RAD_[0..2]_OUT_TEMP", + "HMP_MP_[0..6]_SEC_[0..5]_HV_VMON", + "HMP_TRANPLANT_MEASURE_[0..29]_WAVELENGHT", + "HMP_TRANPLANT_MEASURE_[0..29]_ARGONREFERENCE", + "HMP_TRANPLANT_MEASURE_[0..29]_ARGONCELL", + "HMP_TRANPLANT_MEASURE_[0..29]_C6F14REFERENCE", + "HMP_TRANPLANT_MEASURE_[0..29]_C6F14CELL"}; + + bool isRunStarted = false; + bool mLocalTest = false; + bool mCheckRunStartStop = true; + o2::dcs::RunStatusChecker mRunChecker{o2::detectors::DetID::getMask("HMP")}; + + std::unique_ptr mProcessor; + HighResClock::time_point mTimer; + +}; // end class HMPIDDCSDataProcessor +} // namespace hmpid + +namespace framework +{ + +o2::framework::DataProcessorSpec getHMPIDDCSDataProcessorSpec() +{ + + using clbUtils = o2::calibration::Utils; + + std::vector outputs; + outputs.emplace_back( + ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, + "ChargeCut"}, + Lifetime::Sporadic); + outputs.emplace_back( + ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, + "ChargeCut"}, + Lifetime::Sporadic); + + outputs.emplace_back( + ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBPayload, + "RefIndex"}, + Lifetime::Sporadic); + outputs.emplace_back( + ConcreteDataTypeMatcher{o2::calibration::Utils::gDataOriginCDBWrapper, + "RefIndex"}, + Lifetime::Sporadic); + + return o2::framework::DataProcessorSpec{ + "hmp-dcs-data-processor", Inputs{{"input", "DCS", "HMPDATAPOINTS"}}, + outputs, AlgorithmSpec{adaptFromTask()}, + Options{{"ccdb-path", + VariantType::String, + o2::base::NameConf::getCCDBServer(), + {"Path to CCDB"}}, + {"use-ccdb-to-configure", + VariantType::Bool, + false, + {"Use CCDB to configure"}}, + {"local-test", + VariantType::Bool, + false, + {"Local installation test"}}, // Check HMPID runs SOR/EOR by default + {"use-verbose-mode", + VariantType::Bool, + false, + {"Use verbose mode"}}}}; +} + +} // namespace framework +} // namespace o2 + +#endif diff --git a/Detectors/HMPID/calibration/testWorkflow/hmpid-dcs-data-workflow.cxx b/Detectors/HMPID/calibration/testWorkflow/hmpid-dcs-data-workflow.cxx new file mode 100644 index 0000000000000..d2a86a6160dd9 --- /dev/null +++ b/Detectors/HMPID/calibration/testWorkflow/hmpid-dcs-data-workflow.cxx @@ -0,0 +1,42 @@ +// 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. + +#include "DetectorsDCS/DataPointIdentifier.h" +#include "DetectorsDCS/DataPointValue.h" +#include "Framework/TypeTraits.h" +#include +namespace o2::framework +{ +template <> +struct has_root_dictionary, void> : std::true_type { +}; +} // namespace o2::framework +#include "Framework/DataProcessorSpec.h" +#include "HMPIDDCSDataProcessorSpec.h" // #include "TOFDCSDataProcessorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + // option allowing to set parameters +} + +// ------------------------------------------------------------------ + +#include "Framework/runDataProcessing.h" + +WorkflowSpec defineDataProcessing(ConfigContext const& configcontext) +{ + WorkflowSpec specs; + specs.emplace_back(getHMPIDDCSDataProcessorSpec()); + return specs; +} diff --git a/Detectors/HMPID/calibration/testWorkflow/hmpid-dcs-sim-workflow.cxx b/Detectors/HMPID/calibration/testWorkflow/hmpid-dcs-sim-workflow.cxx new file mode 100644 index 0000000000000..18f8d62cf3b4f --- /dev/null +++ b/Detectors/HMPID/calibration/testWorkflow/hmpid-dcs-sim-workflow.cxx @@ -0,0 +1,140 @@ +// 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. + +// // we need to add workflow options before including Framework/runDataProcessing +// void customize(std::vector& workflowOptions) +// { +// // option allowing to set parameters +// } + +// ------------------------------------------------------------------ +#include +#include +#include +#include "Framework/ConfigParamSpec.h" +#include "DCStestWorkflow/DCSRandomDataGeneratorSpec.h" + +using namespace o2::framework; + +// we need to add workflow options before including Framework/runDataProcessing +void customize(std::vector& workflowOptions) +{ + std::vector options{ + {"max-chambers", VariantType::Int, 0, {"max chamber number to use DCS variables, 0-6"}}, + }; + + std::swap(workflowOptions, options); +} + +void createHints(const char* type, int i, double mean, double sd, std::vector& dphints) +{ + double lLimit = mean - 2 * sd; + double uLimit = mean + 2 * sd; + if (i > 9) { + const char* specifier = Form("HMP_TRANPLANT_MEASURE_%i_%s", i, type); + dphints.emplace_back(o2::dcs::test::DataPointHint{specifier, lLimit, uLimit}); + } else { + const char* specifier = Form("HMP_TRANPLANT_MEASURE_0%i_%s", i, type); + dphints.emplace_back(o2::dcs::test::DataPointHint{specifier, lLimit, uLimit}); + } +} + +#include "Framework/runDataProcessing.h" + +o2::framework::WorkflowSpec defineDataProcessing(ConfigContext const& config) +{ + + std::vector dphints; + + // ==| Environment Pressure (mBar) |================================= + dphints.emplace_back(o2::dcs::test::DataPointHint{"HMP_ENV_PENV", 1003., 1023.}); + + // ==|(CH4) Chamber Pressures (mBar) |================================= + dphints.emplace_back(o2::dcs::test::DataPointHint{"HMP_MP[0..6]_GAS_PMWPC", 3., 5.}); + + //==| Temperature C6F14 IN/OUT / RADIATORS (C) |================================= + + dphints.emplace_back(o2::dcs::test::DataPointHint{"HMP_MP[0..6]_LIQ_LOOP_RAD_[0..2]_IN_TEMP", 21.5, 22.5}); + dphints.emplace_back(o2::dcs::test::DataPointHint{"HMP_MP[0..6]_LIQ_LOOP_RAD_[0..2]_OUT_TEMP", 24.5, 25.5}); + + // ===| HV / SECTORS (V) |========================================================= + dphints.emplace_back(o2::dcs::test::DataPointHint{"HMP_MP_[0..6]_SEC_[0..5]_HV_VMON", 2049.5, 2050.5}); + + // string for DPs of Refractive Index Parameters ============================================================= + + // measured values for IR-parameters + // 30 entries of 8 values: + // Argon Ref mean Argon Ref std Argon Cell mean Argon Cell std C6F14 Ref mean C6F14 Ref std C6F14 Cell mean C6F14 Cell std + double irVals[30][8] = + {{-0.86698055267334, 0.015992261469364, -2.9767239093781, 0.055669896304607, -0.86270183324814, 0.015952149406075, -0.059273429214954, 0.0011367546394467}, // FIRST + {-0.34526389837265, 0.0061066164635122, -1.599116563797, 0.029814273118973, -0.34129247069359, 0.0062515325844288, -0.11364602297544, 0.0020333647262305}, + {-0.19329330325127, 0.0031397438142449, -0.85721117258072, 0.015860633924603, -0.1903311163187, 0.0034912948030978, -0.20784763991833, 0.0037625974509865}, + {-0.14834992587566, 0.002474470064044, -0.65886175632477, 0.012137032113969, -0.14846935868263, 0.0025894897989929, -0.33942249417305, 0.0061758663505316}, + {-0.14286313951015, 0.0027808723971248, -0.63008558750153, 0.011596300639212, -0.14201314747334, 0.0024778251536191, -0.48442330956459, 0.0088781854137778}, + {-0.15407188236713, 0.0029800452757627, -0.68659967184067, 0.012656413950026, -0.15283487737179, 0.0029571398627013, -0.6342813372612, 0.011700733564794}, + {-0.17301347851753, 0.0031401996966451, -0.77723491191864, 0.014357348904014, -0.17033703625202, 0.0031950008124113, -0.77303212881088, 0.014290297403932}, + {-0.19241452217102, 0.0036375673953444, -0.89939516782761, 0.016652518883348, -0.19368402659893, 0.0038244123570621, -0.9212738275528, 0.017078565433621}, + {-0.22112882137299, 0.0039031782653183, -1.0648462772369, 0.01976865530014, -0.22205835580826, 0.0039840959943831, -1.1093875169754, 0.02061739563942}, + {-0.2481614202261, 0.0044772434048355, -1.2268204689026, 0.022809866815805, -0.24697144329548, 0.0043729245662689, -1.2903002500534, 0.024012215435505}, // 10 + {-0.26668339967728, 0.0048548625782132, -1.3464559316635, 0.025057515129447, -0.26911398768425, 0.0049738502129912, -1.4212131500244, 0.026473663747311}, + {-0.28008028864861, 0.005099821370095, -1.431206703186, 0.026657309383154, -0.28283646702766, 0.0050928434357047, -1.5145578384399, 0.028227487578988}, + {-0.29250073432922, 0.0052133435383439, -1.4960530996323, 0.027876731008291, -0.29394751787186, 0.0053529520519078, -1.587148308754, 0.029599368572235}, + {-0.30391928553581, 0.0056737358681858, -1.5516122579575, 0.028916034847498, -0.30461722612381, 0.0054301782511175, -1.648961186409, 0.030760537832975}, + {-0.31080573797226, 0.0055016754195094, -1.5923854112625, 0.029680499807, -0.31138452887535, 0.0053659677505493, -1.6954737901688, 0.031633801758289}, // 15 + {-0.31008964776993, 0.0056457673199475, -1.6111241579056, 0.030030036345124, -0.31404292583466, 0.0057512698695064, -1.7176169157028, 0.032046440988779}, + {-0.30684891343117, 0.0053859171457589, -1.6295021772385, 0.030381938442588, -0.31102648377419, 0.0058898706920445, -1.7385073900223, 0.03244848921895}, + {-0.3116267323494, 0.0054278862662613, -1.6659815311432, 0.031067481264472, -0.31384035944939, 0.0056781014427543, -1.779548406601, 0.033212583512068}, + {-0.31930908560753, 0.0057652872055769, -1.7229619026184, 0.032144580036402, -0.32055324316025, 0.0059450049884617, -1.8417125940323, 0.034386739134789}, + {-0.33134245872498, 0.0058694803155959, -1.7995973825455, 0.033577345311642, -0.33342209458351, 0.0060769249685109, -1.9229571819305, 0.035908468067646}, // 20 + {-0.3437374830246, 0.0064436765387654, -1.8924849033356, 0.035330656915903, -0.34587496519089, 0.0062040886841714, -2.0227761268616, 0.03778387606144}, + {-0.36247292160988, 0.0063365683890879, -1.9954553842545, 0.037263486534357, -0.36232820153236, 0.0065949787385762, -2.1335067749023, 0.039873410016298}, + {-0.37738528847694, 0.0068919118493795, -2.1079571247101, 0.039387684315443, -0.37793877720833, 0.0066521903499961, -2.2520573139191, 0.042100977152586}, + {-0.39373001456261, 0.0070624663494527, -2.2194654941559, 0.041477311402559, -0.39541909098625, 0.0072884988039732, -2.3708393573761, 0.044334270060062}, + {-0.41024819016457, 0.0073348702862859, -2.3269090652466, 0.043495532125235, -0.41210383176804, 0.0075397142209113, -2.4846012592316, 0.046468034386635}, // 25 + {-0.42143520712852, 0.0077510792762041, -2.4250814914703, 0.045346949249506, -0.42174956202507, 0.0076608234085143, -2.588326215744, 0.048415776342154}, + {-0.43363136053085, 0.0077972891740501, -2.5094130039215, 0.046931173652411, -0.43422821164131, 0.0079285996034741, -2.6780755519867, 0.05010611563921}, + {-0.44121220707893, 0.0078951977193356, -2.5789725780487, 0.048236511647701, -0.44251444935799, 0.0080582965165377, -2.7519564628601, 0.05148757994175}, + {-0.44413486123085, 0.0082251932471991, -2.6322927474976, 0.049238469451666, -0.44755265116692, 0.0082092136144638, -2.8076829910278, 0.052542366087437}, + {-0.44769379496574, 0.0082640117034316, -2.6672098636627, 0.049895957112312, -0.45071032643318, 0.0082084992900491, -2.8445172309875, 0.053234227001667}}; // 30 + + double argonRefMean, argonRefSD; // Argon Ref current (mA) + double argonCellMean, argonCellSD; // Argon Cell current (mA) + double freonRefMean, freonRefSD; // C6F14 Ref current (mA) + double freonCellMean, freonCellSD; // C6F14 Cell current (mA) + int iR = 162; + + for (int i = 0; i < 30; ++i) { + + createHints("WAVELENGHT", i, iR, 0.025, dphints); + iR += 2; + + argonRefMean = irVals[i][0]; + argonRefSD = irVals[i][1]; + createHints("ARGONREFERENCE", i, argonRefMean, argonRefSD, dphints); + + argonCellMean = irVals[i][2]; + argonCellSD = irVals[i][3]; + createHints("ARGONCELL", i, argonCellMean, argonCellSD, dphints); + + freonRefMean = irVals[i][4]; + freonRefSD = irVals[i][5]; + createHints("C6F14REFERENCE", i, freonRefMean, freonRefSD, dphints); + + freonCellMean = irVals[i][6]; + freonCellSD = irVals[i][7]; + createHints("C6F14CELL", i, freonCellMean, freonCellSD, dphints); + } + + o2::framework::WorkflowSpec specs; + + specs.emplace_back(o2::dcs::test::getDCSRandomDataGeneratorSpec(dphints, "HMP")); + return specs; +}