// // Hamburg.C // Script to calculate development // // Created by Christian Elsasser on 31.05.13. // University of Zurich, elsasser@cern.ch // Copyright only for commercial use // // General include #include <iostream> #include <fstream> #include <vector> #include <map> #include <stdlib.h> #include <limits> #include <string> #include <time.h> // ROOT include #include "../../include/incBasicROOT.h" #include "../../include/incDrawROOT.h" #include "../../include/incGraphROOT.h" #include "../../include/incHistROOT.h" #include "../../include/incIOROOT.h" #include "../../include/incRooFit.h" #include "../../include/incStatROOT.h" #include "../../include/basicROOTTools.h" #include "../../include/basicRooFitTools.h" #include "../../include/lhcbstyle.C" #include "deplTool.h" #include "hamburgTool.h" // -d detector (TT/IT) // -l layer (TTaX,TTaU,TTbV,TTbX, T[1-3]{X1,U,V,X2}) // -s read-out sector number // -r consider only hit in a distance closer than r mm from the beam axis int Hamburg(int argc, char* argv[]); double rungeKutta4(HMap, double, double, double, double,double,bool); double GetNc(HMap, double); double GetNa(HMap, double, double, double, double, double); double GetNy(HMap, double, double, double, double, double); double conv_Neff_DeltaV(HMap); int main(int argc, char* argv[]){ TStyle* style = lhcbStyle(); int argc_copy = argc; TApplication* theApp = new TApplication("Analysis", &argc, argv); argc = theApp->Argc(); argv = theApp->Argv(); bool runBatch = false; for (int i = 1; i<argc; i++) { if (strcmp(argv[i],"-b")==0) { runBatch = true; gROOT->SetBatch(); } } int exit = Hamburg(argc,argv); Printf("End"); if (!runBatch) { theApp->Run(!runBatch); } return exit; } // Executable method int Hamburg(int argc, char* argv[]){ TVectorD v_res(5); gStyle->SetPadLeftMargin(0.20); gStyle->SetTitleOffset(1.5,"Y"); gStyle->SetTitleOffset(1.0,"X"); const char* diskVar = std::getenv ("DISK"); const char* homeVar = std::getenv ("CCEHOME"); // const char* homeVar = "/afs/cern.ch/user/e/egraveri/cmtuser/STMonitoring/STAging"; TString det("TT"); TString lay("TTaU"); double radius = -1000.0; int sector = 2634; for (int i=1; i<argc; i++) { if (strcmp(argv[i],"-d")==0 && i+1<argc) { det = argv[++i]; }else if (strcmp(argv[i],"-l")==0 && i+1<argc) { lay = argv[++i]; }else if (strcmp(argv[i],"-r")==0 && i+1<argc) { radius = std::atof(argv[++i]); }else if (strcmp(argv[i],"-s")==0 && i+1<argc) { sector = std::atoi(argv[++i]); } } TString vn_output = TString::Format("v_Hamburg_%s_%d", lay.Data(),sector); if (radius>0.0) { vn_output += Form("_r%d",(int)radius); } // Directory and file name for the output TString dn_out(Form("%s/data/ST/Aging", diskVar)); TString fn_out(Form("%s/Hamburg.root", dn_out.Data())); // Directory and file name for the temperature TString dn_temp(Form("%s/data/temperature",homeVar)); TString fn_temp(Form("%s/temperature.root",dn_temp.Data())); // Directory and file name for the luminosity TString dn_lumi(Form("%s/data/lumi",homeVar)); //TString dn_lumi(Form("%s/data/db",homeVar)); TString fn_lumi(Form("%s/lumi.root",dn_lumi.Data())); // // Directory and file name for the fluence TString dn_sector(Form("%s/data/db",homeVar)); TString fn_sector(Form("%s/fluence.root",dn_sector.Data())); TFile* f_temp = TFile::Open(fn_temp.Data()); TFile* f_lumi = TFile::Open(fn_lumi.Data()); TFile* f_sector = TFile::Open(fn_sector.Data()); if (!f_temp || !f_lumi || !f_sector) { Error("Hamburg","Some files are not available"); return EXIT_FAILURE; } // Extract vectors to get beam periods TVectorF* vp_fillTime = (TVectorF*)f_lumi->Get("v_fillTime_tot"); TVectorF* vp_beamEner = (TVectorF*)f_lumi->Get("v_beamEner_tot"); TVectorF* vp_stopTime = (TVectorF*)f_lumi->Get("v_stopTime_tot"); TVectorF* vp_peakLumi = (TVectorF*)f_lumi->Get("v_peakLumi_tot"); if (!vp_fillTime || !vp_beamEner || !vp_stopTime || !vp_peakLumi) { Error("Hamburg","Luminosity vectors are not available"); return EXIT_FAILURE; } TVectorD v_fillTime = *vp_fillTime; TVectorD v_beamEner = *vp_beamEner; TVectorD v_stopTime = *vp_stopTime; TVectorD v_peakLumi = *vp_peakLumi; // Extract temperature measurements TVectorD* vp_temp1 = (TVectorD*)f_temp->Get("v_TT_CT6_temp"); TVectorD* vp_temp2 = (TVectorD*)f_temp->Get("v_TT_AT6_temp"); TVectorD* vp_time1 = (TVectorD*)f_temp->Get("v_TT_CT6_time"); TVectorD* vp_time2 = (TVectorD*)f_temp->Get("v_TT_AT6_time"); if (det.EqualTo("IT")) { vp_temp1 = (TVectorD*)f_temp->Get("v_IT_T3_temp"); vp_temp2 = (TVectorD*)f_temp->Get("v_IT_B3_temp"); vp_time1 = (TVectorD*)f_temp->Get("v_IT_T3_time"); vp_time2 = (TVectorD*)f_temp->Get("v_IT_B3_time"); } if (!vp_temp1 || !vp_temp2 || !vp_time1 || !vp_time2) { Error("Hamburg","Temperature vectors are not available"); return EXIT_FAILURE; } TVectorD v_temp1 = *vp_temp1; TVectorD v_temp2 = *vp_temp2; TVectorD v_time1 = *vp_time1; TVectorD v_time2 = *vp_time2; double v_time1_max = v_time1.Max(); double v_time2_max = v_time2.Max(); double v_fillTime_max = v_fillTime.Max(); Info("Hamburg", "temp1, temp2 and lumi vectors finish at %f, %f, %f", v_time1_max, v_time2_max, v_fillTime_max); // Extract information about the flux in the corresponding layer TString vn_sector("v_sector_"); TString vn_flux7_v("v_flux7_v_"); TString vn_flux7_e("v_flux7_e_"); TString vn_flux8_v("v_flux8_v_"); TString vn_flux8_e("v_flux8_e_"); TString vn_flux13_v("v_flux13_v_"); TString vn_flux13_e("v_flux13_e_"); vn_sector += lay.Data(); vn_flux7_v += lay.Data(); vn_flux7_e += lay.Data(); vn_flux8_v += lay.Data(); vn_flux8_e += lay.Data(); vn_flux13_v += lay.Data(); vn_flux13_e += lay.Data(); // Add radius postfix if (det.EqualTo("IT")) { }else{ if (radius>0.0) { vn_sector += Form("_r%d",(int)radius); vn_flux7_v += Form("_r%d",(int)radius); vn_flux7_e += Form("_r%d",(int)radius); vn_flux8_v += Form("_r%d",(int)radius); vn_flux8_e += Form("_r%d",(int)radius); vn_flux13_v += Form("_r%d",(int)radius); vn_flux13_e += Form("_r%d",(int)radius); } } TVectorD* vp_sector = (TVectorD*)f_sector->Get(vn_sector.Data()); TVectorD* vp_flux7_v = (TVectorD*)f_sector->Get(vn_flux7_v.Data()); TVectorD* vp_flux7_e = (TVectorD*)f_sector->Get(vn_flux7_e.Data()); TVectorD* vp_flux8_v = (TVectorD*)f_sector->Get(vn_flux8_v.Data()); TVectorD* vp_flux8_e = (TVectorD*)f_sector->Get(vn_flux8_e.Data()); TVectorD* vp_flux13_v = (TVectorD*)f_sector->Get(vn_flux13_v.Data()); TVectorD* vp_flux13_e = (TVectorD*)f_sector->Get(vn_flux13_e.Data()); if (!vp_sector || !vp_flux7_v || !vp_flux7_e || !vp_flux8_v || !vp_flux8_e || !vp_flux13_v || !vp_flux13_e) { Error("Hamburg","Flux vectors are not available"); return EXIT_FAILURE; } TVectorD v_sector = *vp_sector; TVectorD v_flux7_v = *vp_flux7_v; TVectorD v_flux7_e = *vp_flux7_e; TVectorD v_flux8_v = *vp_flux8_v; TVectorD v_flux8_e = *vp_flux8_e; TVectorD v_flux13_v = *vp_flux13_v; TVectorD v_flux13_e = *vp_flux13_e; // Define number of calculated pathes int nErr = 1000; // Parameters for Hamburg model HMap para_base = STHamburg::hamburgPara; HMap unce_base = STHamburg::hamburgUnce; if (det.EqualTo("IT")) { para_base["d"] = 410.0e-4; // So far only 410 µm sensors considered } std::vector<HMap> v_para; std::vector<double> v_tempUnce; std::vector<double> v_fluxUnce7; std::vector<double> v_fluxUnce8; std::vector<double> v_fluxUnce13; std::vector<double> v_deltaV; std::vector<TVectorD> v_N; std::vector<double> v_time; std::vector<double> v_val; std::vector<double> v_low; std::vector<double> v_hig; std::vector<double> v_flux; int i_flux = getClosestIndex(v_sector,(double)sector); double flux7_v = v_flux7_v(i_flux); double flux7_e = v_flux7_e(i_flux); double flux8_v = v_flux8_v(i_flux); double flux8_e = v_flux8_e(i_flux); double flux13_v = v_flux13_v(i_flux); double flux13_e = v_flux13_e(i_flux); // Temperature uncertainty of 2 degree double temp_e = 2.0; Info("Hamburg","Filling parameter vectors"); for (int i=0; i<nErr; i++) { HMap temp_para = para_base; // Define parameter for each path if (i==0) { v_para.push_back(para_base); v_fluxUnce7.push_back(0.0); v_fluxUnce8.push_back(0.0); v_fluxUnce13.push_back(0.0); v_tempUnce.push_back(0.0); }else{ // Make gaussian variation of parameters std::map<std::string, double>::iterator it = temp_para.begin(); for(;it!=temp_para.end(); ++it){ it->second += gRandom->Gaus()*unce_base[it->first]; } v_para.push_back(temp_para); v_fluxUnce7.push_back(flux7_e*gRandom->Gaus()); v_fluxUnce8.push_back(flux8_e*gRandom->Gaus()); v_fluxUnce13.push_back(flux13_e*gRandom->Gaus()); v_tempUnce.push_back(temp_e*(2.0*gRandom->Uniform()-1.0)); } v_deltaV.push_back(0.0); v_flux.push_back(0.0); v_N.push_back(TVectorD(3)); } double flux = 0.0; double dFlux = 0.0; int i_temp1 = 0; int i_temp2 = 0; int i_lumi = 0; double tStart = 1262325600; // 1-1-2010 // double tStop = 1372654800; // 1-7-2013 // double tStop = 1448928000; // 1-12-2015 double tStop = 1577750400; // 31-12-2019 std::vector<double> endTimes; endTimes.push_back(tStop); endTimes.push_back(v_time1_max); endTimes.push_back(v_time2_max); endTimes.push_back(v_fillTime_max); TVectorD v_endTimes(endTimes.size(), &endTimes[0]); tStop = v_endTimes.Min(); double tRun = tStart; double tFillEnd = tStart; double tStep = 60000.0; time_t raw_tStart = (long)tStart; time_t raw_tStop = (long)tStop; Info("Hamburg","Starting on: %20s",ctime(&raw_tStart)); Info("Hamburg","Stopping on: %20s",ctime(&raw_tStop )); Info("Hamburg","Steps are %6.2f sec",tStep); Info("Hamburg","Start running"); int print_interval = 0; int print_freq = 200; // Run between the start and the stop time and check if the index for temperature and luminosity needs to be increased while (tRun<tStop) { double temp = 273.15; while (i_temp1<v_time1.GetNoElements() && tRun>v_time1(i_temp1)) { ++i_temp1; } while (i_temp2<v_time2.GetNoElements() && tRun>v_time2(i_temp2)) { ++i_temp2; } temp = (v_temp1(i_temp1)+v_temp2(i_temp2))/2.0+273.15; if(i_lumi<v_fillTime.GetNoElements() && tRun>v_fillTime(i_lumi)) { tFillEnd = v_stopTime(i_lumi); } while (i_lumi<v_fillTime.GetNoElements() && tRun>v_stopTime(i_lumi)){ ++i_lumi; } // Calculate for each path the evolution of the depletion voltage for (int i=0; i<v_deltaV.size(); i++) { temp += v_tempUnce[i]; dFlux = 0.0; if (i_lumi<v_fillTime.GetNoElements()) { if (tRun<v_fillTime(i_lumi)) { dFlux = 0.0; }else{ if (v_beamEner(i_lumi)==7.0) { dFlux = (flux7_v+v_fluxUnce7[i])*v_peakLumi(i_lumi)*STTool::FLUKAConvFac; }else if(v_beamEner(i_lumi)==8.0) { dFlux = (flux8_v+v_fluxUnce8[i])*v_peakLumi(i_lumi)*STTool::FLUKAConvFac; }else if(v_beamEner(i_lumi)==13.0) { dFlux = (flux13_v+v_fluxUnce13[i])*v_peakLumi(i_lumi)*STTool::FLUKAConvFac; }else{ dFlux = 0.0; } } } // Calculate change in the effective doping concentration v_N[i](0) = GetNc(v_para[i],v_flux[i]); v_N[i](1) = GetNa(v_para[i],v_N[i](1),v_flux[i],dFlux,tStep,temp); v_N[i](2) = GetNy(v_para[i],v_N[i](2),v_flux[i],dFlux,tStep,temp); // Convert it to a change in the depletion voltage v_deltaV[i] = v_N[i].Sum()*conv_Neff_DeltaV(v_para[i]); v_flux[i] += dFlux*tStep; // Reset temperature temp -= v_tempUnce[i]; } v_time.push_back(tRun); v_val.push_back(v_deltaV[0]); std::vector<double> v_temp = v_deltaV; std::sort(v_temp.begin(),v_temp.end()); // Extract 68% confidence interval v_low.push_back(TMath::Max(0.0,v_deltaV[0]-v_temp[(int)(0.158*v_temp.size())])); v_hig.push_back(TMath::Max(0.0,v_temp[(int)(0.842*v_temp.size())]-v_deltaV[0])); if (print_interval%print_freq == 0) Printf("Delta V = (%6.2f+%6.2f/-%6.2f) V", v_deltaV[0], TMath::Max(0.0,v_temp[(int)(0.842*v_temp.size())]-v_deltaV[0]), TMath::Max(0.0,v_deltaV[0]-v_temp[(int)(0.158*v_temp.size())])); tRun+=tStep; time_t raw_tRun = (long)tRun; print_interval += 1; if (print_interval%print_freq == 0) Info("Hamburg","Date/Time: %s",ctime(&raw_tRun)); } // Reduce the number of data points to be plotted Info("Hamburg","Reduce number of data points"); std::vector<double> v_val_red; std::vector<double> v_time_red; std::vector<double> v_hig_red; std::vector<double> v_low_red; int redFac = (int)(86400/tStep); // Printf("%d",v_val.size()); for (int i=0; i<v_val.size(); i++) { // Printf("%d",i); if(i%redFac==0){ v_val_red.push_back(v_val[i]); v_time_red.push_back(v_time[i]); v_hig_red.push_back(v_hig[i]); v_low_red.push_back(v_low[i]); } } TVectorD vr_val = getROOTVector<double>(v_val_red); TVectorD vr_time = getROOTVector<double>(v_time_red); TVectorD vr_hig = getROOTVector<double>(v_hig_red); TVectorD vr_low = getROOTVector<double>(v_low_red); // Store result TFile* f_out = new TFile(fn_out.Data(),"UPDATE"); f_out->Delete(Form("%s_deltaV;*",vn_output.Data())); f_out->Delete(Form("%s_time;*" ,vn_output.Data())); f_out->Delete(Form("%s_hig;*" ,vn_output.Data())); f_out->Delete(Form("%s_low;*" ,vn_output.Data())); vr_val.Write(Form("%s_deltaV",vn_output.Data())); vr_time.Write(Form("%s_time",vn_output.Data())); vr_hig.Write(Form("%s_hig",vn_output.Data())); vr_low.Write(Form("%s_low",vn_output.Data())); f_out->Close(); Info("Hamburg","Data written to %s",fn_out.Data()); Printf("=========================================\n"); return EXIT_SUCCESS; } // Runge-Kutta 4th order algorithm for Hamburg model (not used) double rungeKutta4(HMap para, double flux, double dFlux, double temp, double dT,double T_noBeam,bool isBeam){ double dNc = 0.0; double dNa = 0.0; double dNy = 0.0; double tau_a = 1.0/(para["k0a"]*TMath::Exp(-para["Eaa"]/(para["kB"]*temp))); double tau_y = 1.0/(para["k0y"]*TMath::Exp(-para["Ey" ]/(para["kB"]*temp))); Printf("tau_a: %f,tau_y: %f",tau_a,tau_y); Printf("flux: %f, dFlux: %f, t: %f",flux,dFlux,T_noBeam); dNc += (para["gc"]+para["Nc"]*para["c"]*TMath::Exp(-para["c"]*flux))*dFlux*dT/2.0; dNa += (flux*para["ga"]*-1.0/tau_a+para["ga"]*dFlux)*TMath::Exp(-T_noBeam/tau_a)*dT/2.0; dNy += (dFlux*para["gy"]*(1.0-1.0/(1.0+T_noBeam/tau_y))+ flux*para["gy"]/TMath::Power(1.0+T_noBeam/tau_y,2)/tau_y)*dT/2.0; flux += dFlux*dT/2.0; dNc += (para["gc"]+para["Nc"]*para["c"]*TMath::Exp(-para["c"]*flux))*dFlux*dT/2.0; dNa += (flux*para["ga"]*-1.0/tau_a+para["ga"]*dFlux)*TMath::Exp(-T_noBeam/tau_a)*dT/2.0; dNy += (dFlux*para["gy"]*(1.0-1.0/(1.0+T_noBeam/tau_y))+ flux*para["gy"]/TMath::Power(1.0+T_noBeam/tau_y,2)/tau_y)*dT/2.0; Printf("dNc: %f,dNa: %f,dNy: %f",dNc,dNa,dNy); return dNc+dNa+dNy; } // Calculate stable damage part double GetNc(HMap para, double flux){ return para["Nc"]*(1.0-TMath::Exp(-para["c"]*flux))+para["gc"]*flux; } // Calculate change in the annealing part double GetNa(HMap para, double Na, double flux, double dFlux, double dT, double temp){ double tau_a = 1.0/(para["k0a"]*TMath::Exp(-para["Eaa"]/(para["kB"]*temp))); Na += (para["ga"]*dFlux-Na/tau_a)*dT/2.0; flux += dFlux*dT/2.0; Na += (para["ga"]*dFlux-Na/tau_a)*dT/2.0; return Na; } // Calculate change in the reverse annealing part double GetNy(HMap para, double Ny, double flux, double dFlux, double dT, double temp){ double tau_y = 1.0/(para["k0y"]*TMath::Exp(-para["Ey" ]/(para["kB"]*temp))); Ny += (TMath::Power((flux==0.0?0.0:Ny/(flux*para["gy"]))-1,2)*flux*para["gy"]/tau_y)*dT/2.0; flux += dFlux*dT/2.0; Ny += (TMath::Power((flux==0.0?0.0:Ny/(flux*para["gy"]))-1,2)*flux*para["gy"]/tau_y)*dT/2.0; return Ny; } // Convert change in the effective doping concentration to change in the depletion voltage double conv_Neff_DeltaV(HMap para){ return para["q"]*para["d"]*para["d"]/(2.0*para["eps"]*para["eps0"]); }