diff --git a/Software/IVScan/IVScan.C b/Software/IVScan/IVScan.C index 6c7c4bf..6aa5b2e 100644 --- a/Software/IVScan/IVScan.C +++ b/Software/IVScan/IVScan.C @@ -135,7 +135,7 @@ ifstream datFile; std::string line; - // Number of rows to be read from the text files. + // Number of rows to be read from the text files. int rows1; int rows2; diff --git a/Software/Monitoring/Makefile b/Software/Monitoring/Makefile new file mode 100755 index 0000000..5921a0a --- /dev/null +++ b/Software/Monitoring/Makefile @@ -0,0 +1,34 @@ +# +CC=$(CXX) +glib_cflags=$(shell pkg-config --cflags glib-2.0 gio-2.0) +glib_libs=$(shell pkg-config --libs glib-2.0 gio-2.0) + +ROOTC=$(shell root-config --cflags) +ROOTL=$(shell root-config --libs) +OPT=-g -fno-inline #-std=c++11 +CppFLAGS=$(OPT) -I. $(glib_cflags) +CXXFLAGS=-fPIC $(CppFLAGS) + + +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + SO=so + SO_FLAGS=-shared + CXXFLAGS += -D LINUX +endif +ifeq ($(UNAME_S),Darwin) + SO=dylib + SO_FLAGS=-dynamiclib -undefined dynamic_lookup -install_name @rpath/$@ + CXXFLAGS += -D OSX +endif + +all: PlotTrends + +PlotTrends: PlotTrends.C + c++ -I$(OPT) $(CXXFLAGS) $(ROOTC) -o $@ $^ $(LDLIBS) $(ROOTL) $(gliblibs) + + +clean: + rm -f *.o PlotTrends + rm -rf *.dSYM + diff --git a/Software/Monitoring/PlotTrends.C b/Software/Monitoring/PlotTrends.C new file mode 100644 index 0000000..5e3f7c5 --- /dev/null +++ b/Software/Monitoring/PlotTrends.C @@ -0,0 +1,485 @@ +//************************************************ +// Author: Federica Lionetto +// Created on: 09/04/2015 +//************************************************ + +/* + +PlotTrends creates a ROOT file with temperature, relative humidity, and dew point trends. + +Compile with: + +make + +Run with: + +./PlotTrends [sensor] [from] [to] [additional folder] + +where + +- [sensor] is the type of sensor (Hans410, ...); +- [from] is the optional starting time from which one wants to display the trends, according to the "ddd mmm d hh:mm:ss yyyy" format; +- [to] is the optional stopping time to which one wants to display the trends, according to the "ddd mmm d hh:mm:ss yyyy" format; +- [additional folder] is the optional additional folder where the output will be saved. + +For example: + +./PlotTrends Hans320 + +or + +./PlotTrends Hans320 Thu Apr 9 16:55:00 2015 Thu Apr 9 16:55:52 2015 + +A folder named AnalysisResults will be created in a fixed location and a ROOT file will be saved in there. A folder named Figures will be created inside the folder named AnalysisResults, with some monitoring plots. + +If needed, an additional folder can be specified, that will be created inside the folder named AnalysisResults. +*/ + +#include "../Tools/Lib.C" +#include "../Tools/UsefulFunctions.C" +#include "../Tools/lhcbStyle.C" +#include "../Tools/Style.C" + +#include "../Tools/Par.C" + +void PlotTrends(char *sensor, char *from=0, char *to=0, char *externalPath=0); + +vector SelectFiles(string inputDirectory, vector list_of_files, time_t t_from, time_t t_to); + + +int main(int argc, char *argv[]) +{ + getLHCbStyle(); + PersonalStyle(); + + if ((argc ==2) && (string(argv[1]) == "--info")) + { + cout << "**************************************************" << endl; + + cout << "Some comments." << endl; + + cout << "**************************************************" << endl; + + return 0; + } + else if (argc < 2) + { + cout << "**************************************************" << endl; + + cout << "Error! Input information missing..." << endl; + cout << "Please use the following format:" << endl; + cout << "./PlotTrends [1] [2] [3] [4]" << endl; + cout << "with:" << endl; + cout << "[1] = Type of sensor (Hans410, ...);" << endl; + cout << "[2] = Starting time, optional;" << endl; + cout << "[3] = Stopping time, optional;" << endl; + cout << "[4] = Additional folder, optional." << endl; + cout << "Type ./PlotTrends --info for more information." << endl; + + cout << "**************************************************" << endl; + + return 0; + } + else + { + cout << "Type of sensor: " << argv[1] << endl; + if (argc == 2) + PlotTrends(argv[1]); + else if (argc == 3) + { + cout << "**************************************************" << endl; + + cout << "Error! Stopping time not specified..." << endl; + + cout << "**************************************************" << endl; + + return 0; + } + else if (argc == 4) + { + cout << "Starting time: " << argv[2] << endl; + cout << "Stopping time: " << argv[3] << endl; + PlotTrends(argv[1],argv[2],argv[3]); + } + else if (argc == 5) + { + cout << "Staring time: " << argv[2] << endl; + cout << "Stopping time: " << argv[3] << endl; + cout << "Additional folder: " << argv[4] << endl; + PlotTrends(argv[1],argv[2],argv[3],argv[4]); + } + else + { + cout << "Error! Too many arguments given..." << endl; + + return 0; + } + + return 0; + } +} + +void PlotTrends(char *sensor, char *from, char *to, char *externalPath) +{ + cout << "**************************************************" << endl; + cout << "Plotting trends..." << endl; + cout << "**************************************************" << endl; + + // Do not comment this line. + gROOT->ProcessLine("#include "); + + + + // Convert the string with date and time to something that is interpreted as date and time. tm_from is a tm object, t_from is a time_t object and corresponds to the number of seconds since epoch. The format specifier %c stands for date and time representation. + + struct tm tm_from; + memset(&tm_from, 0, sizeof(struct tm)); + strptime(from,"%c",&tm_from); + time_t t_from = mktime(&tm_from); + + /* + cout << tm_from.tm_year << endl; + cout << t_from << endl; + */ + + struct tm tm_to; + memset(&tm_to, 0, sizeof(struct tm)); + strptime(to,"%c",&tm_to); + time_t t_to = mktime(&tm_to); + + /* + cout << tm_to.tm_year << endl; + cout << t_to << endl; + */ + + // Check that the starting time is earlier than the stopping time. + if (t_from >= t_to) + { + cout << "Error! Starting time earlier than stopping time..." << endl; + return; + } + + // Adjust time format for output ROOT file and figures. + string s_from = string(from); + string s_to = string(to); + + // Remove white spaces from s_from and s_to. + s_from.erase(remove(s_from.begin(), s_from.end(), ' '), s_from.end()); + s_to.erase(remove(s_to.begin(), s_to.end(), ' '), s_to.end()); + + // Do some fanciness to get the directory right. + string inputDirectory = "/disk/groups/hep/flionett/TestStand/Data/"+string(sensor)+"/Monitoring"; + string outputDirectory = "/disk/groups/hep/flionett/TestStand/AnalysisResults/"+string(sensor)+"/Monitoring"; + if (externalPath!=0) + outputDirectory = string(outputDirectory+"/"+externalPath); + cout << "The input directory is: " << inputDirectory << endl; + cout << "The output directory is: " << outputDirectory << endl; + + // Create the outputDirectory directory if it does not exist. + string path_to_make = "mkdir -p "+outputDirectory; + system(path_to_make.c_str()); + + cout << "Figures stored in: " << outputDirectory+"/Figures" << endl; + + // Create a directory named Figures inside the directory named outputDirectory if it does not exist. + string path_to_make_figures = "mkdir -p "+outputDirectory+"/Figures"; + if ((from != 0) && (to !=0)) + path_to_make_figures = path_to_make_figures+"/PlotTrends-"+"from"+s_from+"to"+s_to; + else + path_to_make_figures = path_to_make_figures+"/PlotTrends-all.root"; + system(path_to_make_figures.c_str()); + + TString path_to_figures = (string(path_to_make_figures)).substr((string(path_to_make_figures)).find_last_of(' ')+1); + + + + TDatime *time; + vector vtime; + + double T; + vector vT; + + double RH; + vector vRH; + + double DP; + vector vDP; + + string trash1; + string trash2; + string trash3; + string trash4; + string trash5; + + // Given starting and stopping time, find the corresponding input text files. + vector list_of_files; + vector list_of_selected_files; + + list_of_files = open(inputDirectory); + list_of_selected_files = SelectFiles(inputDirectory, list_of_files, t_from, t_to); + + if (list_of_selected_files.size() == 0) { + cout << "Error! No input text file selected..." << endl; + return; + } + + ifstream file; + string header; + string line; + struct tm tm_time_in_line; + time_t t_time_in_line; + + // Read data from selected input text files. + for (vector::const_iterator i = list_of_selected_files.begin(); i != list_of_selected_files.end(); ++i) + { + // Open file. + cout << "Selected input text file #" << i-list_of_selected_files.begin() << ": " << *i << endl; + file.open((inputDirectory+"/"+*i).c_str()); + if (file.is_open()) + { + // cout << "Great! File opened..." << endl; + + // Skip header. + if (getline(file,header)) + { + // Read time in each line. + while (getline(file,line)) + { + memset(&tm_time_in_line, 0, sizeof(struct tm)); + strptime(line.c_str(),"%c",&tm_time_in_line); + t_time_in_line = mktime(&tm_time_in_line); + + if ((t_time_in_line <= t_to) && (t_time_in_line >= t_from)) + { + // cout << "Time in line: " << t_time_in_line << " from epoch time" << endl; + time = new TDatime(tm_time_in_line.tm_year,tm_time_in_line.tm_mon+1,tm_time_in_line.tm_mday,tm_time_in_line.tm_hour+1,tm_time_in_line.tm_min,tm_time_in_line.tm_sec); + // cout << "Time going in the ROOT file: " << time->Convert() << endl; + // Get time, temperature, humidity, and dew point. + istringstream iss(line); + iss >> trash1 >> trash2 >> trash3 >> trash4 >> trash5 >> T >> RH >> DP; + vtime.push_back(time->Convert()); + vT.push_back(T); + vRH.push_back(RH); + vDP.push_back(DP); + } + } + } + else + { + cout << "Error! Unable to read header..." << endl; + return; + } + + // Close file. + file.close(); + } + else { + cout << "Error! Unable to open file." << endl; // To be modified to stop everything if there is a problem. + return; + } + } + + double *aT = &vT[0]; + double *aRH = &vRH[0]; + double *aDP = &vDP[0]; + double *atime = &vtime[0]; + + /* + cout << vT.size() << endl; + cout << vtime.size() << endl; + + cout << vT[0] << endl; + cout << vtime[0] << endl; + + cout << vT[10] << endl; + cout << vtime[10] << endl; + */ + + // Open output ROOT file. + string output_ROOT; + if ((from != 0) && (to !=0)) + output_ROOT = outputDirectory+"/PlotTrends-"+"from"+s_from+"to"+s_to+".root"; + else + output_ROOT = outputDirectory+"/PlotTrends-all.root"; + TFile *output = TFile::Open(TString(output_ROOT),"RECREATE"); + + // Temperature trends. + TCanvas *cT = new TCanvas("PlotTrends-T","",400,300); + + cT->SetLeftMargin(0.1363636); + cT->SetRightMargin(0.08808081); + cT->SetBottomMargin(0.2095588); + + TGraph *gT = new TGraph(vT.size(),atime,aT); + InitGraph(gT,"Temperature trends","Time","Temperature (#circC)"); + gT->GetXaxis()->SetTimeDisplay(1); + gT->GetXaxis()->SetLabelOffset(0.04); + gT->GetXaxis()->SetTitleOffset(1.50); + gT->GetYaxis()->SetTitleOffset(0.95); + gT->GetXaxis()->SetTimeFormat("#splitline{%Y-%m-%d}{%H:%M:%S}"); + gT->GetXaxis()->SetNdivisions(-503); + gT->GetXaxis()->SetTimeOffset(0,"gmt"); + DrawGraph(cT,gT,"APC",path_to_figures); + + // Relative humidity trends. + TCanvas *cRH = new TCanvas("PlotTrends-RH","",400,300); + + cRH->SetLeftMargin(0.1363636); + cRH->SetRightMargin(0.08808081); + cRH->SetBottomMargin(0.2095588); + + TGraph *gRH = new TGraph(vRH.size(),atime,aRH); + InitGraph(gRH,"Relative humidity trends","Time","Relative humidity (%)"); + gRH->GetXaxis()->SetTimeDisplay(1); + gRH->GetXaxis()->SetLabelOffset(0.04); + gRH->GetXaxis()->SetTitleOffset(1.50); + gRH->GetYaxis()->SetTitleOffset(0.95); + gRH->GetXaxis()->SetTimeFormat("#splitline{%Y-%m-%d}{%H:%M:%S}"); + gRH->GetXaxis()->SetNdivisions(-503); + gRH->GetXaxis()->SetTimeOffset(0,"gmt"); + DrawGraph(cRH,gRH,"APC",path_to_figures); + + // Dew point trends. + TCanvas *cDP = new TCanvas("PlotTrends-DP","",400,300); + + cDP->SetLeftMargin(0.1363636); + cDP->SetRightMargin(0.08808081); + cDP->SetBottomMargin(0.2095588); + + TGraph *gDP = new TGraph(vDP.size(),atime,aDP); + InitGraph(gDP,"Dew point trends","Time","Dew point (#circC)"); + gDP->GetXaxis()->SetTimeDisplay(1); + gDP->GetXaxis()->SetLabelOffset(0.04); + gDP->GetXaxis()->SetTitleOffset(1.50); + gDP->GetYaxis()->SetTitleOffset(0.95); + gDP->GetXaxis()->SetTimeFormat("#splitline{%Y-%m-%d}{%H:%M:%S}"); + gDP->GetXaxis()->SetNdivisions(-503); + gDP->GetXaxis()->SetTimeOffset(0,"gmt"); + DrawGraph(cDP,gDP,"APC",path_to_figures); + + // Temperature and dew point trends. + TCanvas *cTandDP = new TCanvas("PlotTrends-TandDP","",400,300); + + cTandDP->SetLeftMargin(0.1363636); + cTandDP->SetRightMargin(0.08808081); + cTandDP->SetBottomMargin(0.2095588); + + TMultiGraph *mgTandDP = new TMultiGraph(); + + gT->SetMarkerColor(kGreen); + gT->SetLineColor(kGreen); + gDP->SetMarkerColor(kRed); + gDP->SetLineColor(kRed); + + TLegend *legTandDP = CreateLegend2(gT,"temperature",gDP,"dew point","lpw",0.63,0.59,0.88,0.84); + + mgTandDP->Add(gT); + mgTandDP->Add(gDP); + + cTandDP->cd(); + mgTandDP->Draw("APC"); + + mgTandDP->GetXaxis()->SetTimeDisplay(1); + mgTandDP->GetXaxis()->SetLabelOffset(0.04); + mgTandDP->GetXaxis()->SetTitleOffset(1.50); + mgTandDP->GetYaxis()->SetTitleOffset(0.95); + mgTandDP->GetXaxis()->SetTimeFormat("#splitline{%Y-%m-%d}{%H:%M:%S}"); + mgTandDP->GetXaxis()->SetNdivisions(-503); + mgTandDP->GetXaxis()->SetTimeOffset(0,"gmt"); + + DrawGraphCompare(cTandDP,mgTandDP,legTandDP,"Temperature and dew point trends","Time","Temperature (#circC)","APC",path_to_figures); + + + + // Write output ROOT file. + output->Write(); + + // Close output ROOT file. + output->Close(); + + return; +} + + + +vector SelectFiles(string inputDirectory, vector list_of_files, time_t t_from, time_t t_to) { + ifstream file; + + string header; + string first_line; + string last_line; + + struct tm tm_time_in_first_line; + struct tm tm_time_in_last_line; + + time_t t_time_in_first_line; + time_t t_time_in_last_line; + + vector list_of_selected_files; + + for (vector::const_iterator i = list_of_files.begin(); i != list_of_files.end(); ++i) + { + cout << "Input text file #" << i-list_of_files.begin() << ": " << *i << endl; + + // Check whether this input text file must be selected. + file.open((inputDirectory+"/"+*i).c_str()); + if (file.is_open()) + { + // cout << "Great! File opened..." << endl; + + // Skip header. + if (getline(file,header)) + { + // Read time in first line. + if (getline(file,first_line)) + { + memset(&tm_time_in_first_line, 0, sizeof(struct tm)); + strptime(first_line.c_str(),"%c",&tm_time_in_first_line); + t_time_in_first_line = mktime(&tm_time_in_first_line); + + // cout << "Time in first line: " << t_time_in_first_line << " from epoch time" << endl; + } + else + { + cout << "Error! Cannot read time in first line..." << endl; + return vector(); + } + // Read time in last line. + last_line = getLastLine(file); + memset(&tm_time_in_last_line, 0, sizeof(struct tm)); + strptime(last_line.c_str(),"%c",&tm_time_in_last_line); + t_time_in_last_line = mktime(&tm_time_in_last_line); + + // cout << "Time in last line: " << t_time_in_last_line << " from epoch time" << endl; + + // Decide if this input text file must be selected. + + if ((t_time_in_first_line <= t_to) && (t_time_in_last_line >= t_from)) + { + // Select the input text file. + list_of_selected_files.push_back(*i); + } + + } + else + { + cout << "Error! Unable to read header..." << endl; + return vector(); + } + + file.close(); + } + else { + cout << "Error! Unable to open file." << endl; // To be modified to stop everything if there is a problem. + return vector(); + } + } + + // cout << "Selected input text files" << endl; + for (vector::const_iterator i = list_of_selected_files.begin(); i != list_of_selected_files.end(); ++i) + { + // cout << "Selected input text file #" << i-list_of_selected_files.begin() << ": " << *i << endl; + } + + return list_of_selected_files; +} diff --git a/Software/Tools/Lib.C b/Software/Tools/Lib.C index 6455d48..a594ce6 100644 --- a/Software/Tools/Lib.C +++ b/Software/Tools/Lib.C @@ -46,10 +46,15 @@ #include // #include +#include +#include +#include #include #include +#include #include #include +#include #include // #include "Alibava/AsciiRoot.h" diff --git a/Software/Tools/Style.C b/Software/Tools/Style.C index 8af0827..070a8e2 100644 --- a/Software/Tools/Style.C +++ b/Software/Tools/Style.C @@ -202,6 +202,7 @@ style->SetTitleOffset(1.05,"Y"); style->SetStatY(0.88); // TGaxis::SetMaxDigits(3); + style->SetPadTopMargin(0.0735); return; }