ATLAS Offline Software
Loading...
Searching...
No Matches
EfieldInterpolator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 */
4
5// PixelDigitization includes
7
8#include "TROOT.h"
9#include "TH1.h"
10#include "TF1.h"
11#include "TVectorD.h"
12#include <TFile.h>
13#include "TTreeReader.h"
14#include "TTreeReaderValue.h"
15#include "TTreeReaderArray.h"
16#include <TMath.h>
17#include <TGraph.h>
18#include <TPRegexp.h>
19#include <TSystemDirectory.h>
20#include <TSystemFile.h>
21#include <TGraph2D.h>
22#include <algorithm>
23#include <TString.h>
24#include <fstream>
25
26// Constructor with parameters:
27EfieldInterpolator::EfieldInterpolator(const std::string& type, const std::string& name, const IInterface* parent) :
28 AthAlgTool(type, name, parent),
30
32
34 ATH_MSG_DEBUG("Initializing " << name() << "...");
35 return StatusCode::SUCCESS;
36}
37
39 ATH_MSG_DEBUG("Finalizing " << name() << "...");
40 return StatusCode::SUCCESS;
41}
42
43TVectorD CastStdVec(const std::vector<double>& vin) {
44 TVectorD tmp(vin.size());
45 //for(uint i = 0; i<vin.size(); i++ ){
46 uint index = 0;
47
48 for (auto i : vin) {
49 tmp[index] = i;
50 index++;
51 }
52 return tmp;
53}
54
55//Returns index at of std::vectorv where val is contained
56int isContainedAt(const std::vector<double> & v, double val) {
57 for (uint i = 0; i < v.size(); i++) {
58 //Equality for decimals
59 if (v[i] - 0.00001 < val && val < v[i] + 0.00001) return i;
60 }
61 return -1;
62}
63
64// Initialize indicating layer due to different geometry
65// One instance interpolates only for fixed geometry (=pixel depth)
67 ATH_MSG_INFO("Create interpolator for layer " << layer);
68 if (layer > 0) {
69 //it's b layer
70 m_sensorDepth = 250;
71 } else {
72 //IBL
73 m_sensorDepth = 200;
74 }
75 ATH_MSG_INFO("EfieldInterpolator: Default ctor");
76}
77
78StatusCode EfieldInterpolator::loadTCADlist(const std::string& TCADfileListToLoad) {
80 ATH_MSG_INFO("Load from list " << TCADfileListToLoad);
81 if (!initializeFromFile(TCADfileListToLoad)) {
82 ATH_MSG_WARNING("ERROR: Initialize failed looking for file " << TCADfileListToLoad);
83 //Check if given path links to directory:
84 if (!initializeFromDirectory(TCADfileListToLoad)) {
85 ;
86 return StatusCode::FAILURE;
87 }
88 }
89 ATH_MSG_INFO("Finished loading TCAD list");
90 return StatusCode::SUCCESS;
91}
92
93bool EfieldInterpolator::initializeFromDirectory(const std::string& fpath) {
94 //similar to function loadTCADfiles()
95 //instead of reading file list, list files from directory fpath and create file listing information
96
97 //retrieve fluence and bias voltage from file name (including path, directory names fluence value)
98 //skip files which do not dollow naming declaration
99
100 //Create textfile for tmp storage
101 std::ofstream efieldscalib;
102 efieldscalib.open("listOfEfields.txt");
103 TPRegexp rvo("\\b-[0-9](\\w+)V\\b");
104 TPRegexp rfl("\\bfl([\\w.]+)e[0-9]{1,2}");
105 TString ext = ".dat";
106 TString sflu, svol, fullpath;
107 TSystemDirectory dir((TString)fpath, (TString)fpath);
108 TList* files = dir.GetListOfFiles();
109 if (files) {
110 TSystemFile* file;
111 TString fname;
112 TIter next(files);
113 while ((file = (TSystemFile*) next())) {
114 fname = file->GetName();
115 if (fname.BeginsWith("fl") && file->IsDirectory()) {
116 TString deeppath = fpath;
117 deeppath += fname;
118 deeppath += "/reference/";
119 TSystemDirectory deepdir(deeppath, deeppath);
120 TList* deepfiles = deepdir.GetListOfFiles();
121 if (deepfiles) {
122 TSystemFile* deepfile;
123 TString deepfname;
124 TIter deepnext(deepfiles);
125 while ((deepfile = (TSystemFile*) deepnext())) {
126 deepfname = deepfile->GetName();
127 if (!deepfile->IsDirectory() && deepfname.EndsWith(ext)) {
128 svol = deepfname(rvo);
129 svol.ReplaceAll("-", "");
130 svol.ReplaceAll("V", "");
131 sflu = deeppath(rfl);
132 sflu.ReplaceAll("fl", "");
133 fullpath = deeppath;
134 fullpath += deepfname;
135 if (!deepfname.Contains("pruned")) {
136 if (!sflu.IsFloat()) {
137 ATH_MSG_INFO("EfieldInterpolator load from directory - could not resolve fluence from " << fullpath);
138 continue;
139 }
140 if (!svol.IsFloat()) {
141 ATH_MSG_INFO("EfieldInterpolator load from directory - could not resolve voltage from " << fullpath);
142 continue;
143 }
144 } else {
145 ATH_MSG_INFO("Skip pruned files: " << fullpath);
146 continue;
147 }
148 efieldscalib << fullpath << " " << sflu << " " << svol << std::endl;
149 }
150 }
151 }
152 }
153 }
154 }
155 efieldscalib.close();
156 bool success = initializeFromFile("listOfEfields.txt");
157 if (success) ATH_MSG_INFO("Initialized from directory");
158 return success;
159}
160
161// Load maps into TTree for faster processing
162bool EfieldInterpolator::initializeFromFile(const std::string& finpath) {
163 TString fpath = finpath;
164
165 m_initialized = false;
166 TString fTCAD = "";
167 if (fpath.EndsWith(".txt")) {
168 //File list path, fluence and bias voltage of TCAD simulation as plain text
169 fTCAD = loadTCADfiles(fpath.Data());
170 ATH_MSG_INFO("Loaded file " << fpath << " - all maps accumulated in " << fTCAD);
172 ATH_MSG_INFO("created interpolation tree ");
173 m_initialized = true;
174 ATH_MSG_INFO("Loaded from .txt file");
175 } else {
176 if (fpath.EndsWith("toTTree.root")) {
177 //File list TCAD efield maps as leaves
179 m_initialized = true;
180 } else {
181 if (fpath.EndsWith(".root")) {
182 //File list is already transformed to tree
183 m_fInter = fpath;
184 m_initialized = true;
185 }
186 }
187 }
188 ATH_MSG_INFO("Interpolation has been initialized from file " << m_fInter << " - successful " << m_initialized);
189 return m_initialized;
190}
191
192// Check if requested values out of range of given TCAD samples
193void EfieldInterpolator::reliabilityCheck(double aimFluence, const std::vector<double>& fluences, double aimVoltage,
194 const std::vector<double>& voltages) {
195 bool tooLowVolt = true;
196 bool tooHighVolt = true;
197
198 for (const auto iv : voltages) {
199 if (aimVoltage < iv) tooHighVolt = false;
200 if (aimVoltage > iv) tooLowVolt = false;
201 }
202 bool tooLowFlu = true;
203 bool tooHighFlu = true;
204 for (double fluence : fluences) {
205 if (aimFluence < fluence) tooHighFlu = false;
206 if (aimFluence > fluence) tooLowFlu = false;
207 }
208 if (tooLowFlu) ATH_MSG_WARNING(
209 "WARNING: The fluence value you specified (" << aimFluence << ") is too low to be reliably interpolated!");
210 if (tooLowVolt) ATH_MSG_WARNING(
211 "WARNING: The voltage value you specified (" << aimVoltage << ") is too low to be reliably interpolated!");
212 if (tooHighFlu) ATH_MSG_WARNING(
213 "WARNING: The fluence value you specified (" << aimFluence << ") is too high to be reliably interpolated!");
214 if (tooHighVolt) ATH_MSG_WARNING("WARNING: The voltage value you specified (" << aimVoltage << ") is too high to be reliably interpolated!");
215
216 // Results from Closure Test
217 // TCAD files save 20 for 20e14 neq/cm2
218 if (12.2 < aimFluence || aimFluence < 1.) ATH_MSG_WARNING(" WARNING: The fluence value you specified (" << aimFluence << ") is outside the range within it could be reliably interpolated!"); //Based on closure test June 2018 - max fluences available: ... 10 12 15 20
219 if (1010. < aimVoltage || aimVoltage < 79.) ATH_MSG_WARNING(" WARNING: The voltage value you specified (" << aimVoltage << ") is outside the range within it could be reliably interpolated!"); }
220
221void EfieldInterpolator::scaleIntegralTo(TH1* hin, double aimInt, int first, int last) {
222 hin->Scale(aimInt / (float) hin->Integral(first, last));
223}
224
225double EfieldInterpolator::relativeDistance(double x1, double x2) {
226 if (x1 == 0.) return 0.;
227
228 return((x1 - x2) / x1);
229}
230
231//Use as definition for distance in Fluence/Voltage space
232double EfieldInterpolator::relativeDistance(double x1, double y1, double x2, double y2) {
233 return(std::sqrt(relativeDistance(x1, x2) * relativeDistance(x1, x2) + relativeDistance(y1, y2) * relativeDistance(y1, y2)));
234}
235
236double EfieldInterpolator::extrapolateLinear(double x1, double y1, double x2, double y2, double xaim) {
237 // follow linear extrapolation: y=mx+b
238 double delx = x2 - x1;
239
240 if (delx == 0) return 0.; // slope not defined
241
242 double dely = y2 - y1;
243 double b = y1 - (dely / delx) * x1;
244 return(xaim * (dely / delx) + b);
245}
246
247// Return E field which is directly read from TCAD simulation
248// and fill edges values
249TH1D* EfieldInterpolator::loadEfieldFromDat(const std::string& fname, bool fillEdges) {
250 TH1D* hefieldz = new TH1D("hefieldz", "hefieldz", m_sensorDepth + 1, -0.5, m_sensorDepth + 0.5);
251
252 std::ifstream in;
253 in.open(fname);
254 TString z, e;
255 int nlines = 0;
256 ATH_MSG_INFO("Load E field from " << fname);
257 while (1) {
258 in >> z >> e;
259 if (!in.good()) break;
260 if (nlines < 3) printf("e=%s=%f, z=%s=%f \n", e.Data(), e.Atof(), z.Data(), z.Atof());
261 nlines++;
262 hefieldz->Fill(z.Atof(), e.Atof());
263 }
264 in.close();
265 if (fillEdges) EfieldInterpolator::fillEdgeValues(hefieldz);
266 return hefieldz;
267}
268
269// original TCAD simulations given as txt (.dat) files (zVal efieldVal)
270const std::string EfieldInterpolator::loadTCADfiles(const std::string& targetList) {
271 bool isIBL = true;
272 TString tl = targetList;
273 TString fName = targetList;
274
275 fName.ReplaceAll(".txt", "_toTTree.root");
276 fName = fName.Remove(0, fName.Last('/') + 1); //Remove prepending path and store in run directory
277 TFile* bufferTCADtree = new TFile(fName.Data(), "RECREATE");
278
279 if (tl.Length() < 1) {
280 tl = "list_TCAD_efield_maps.txt";
281 ATH_MSG_WARNING("No List to load! Set default: " << tl.Data());
282 }
283 std::ifstream in;
284 TTree* tcadtree = new TTree("tcad", "All TCAD E field simulations stored as individual events in tree");
285 double voltage = -1.;
286 double fluence = -1.;
287 std::vector<double> efield;
288 std::vector<Int_t> pixeldepth;
289 tcadtree->Branch("voltage", &voltage, "voltage/D");
290 tcadtree->Branch("fluence", &fluence, "fluence/D");
291 tcadtree->Branch("efield", &efield);
292 tcadtree->Branch("pixeldepth", &pixeldepth);
293 //Get vetcor of {filename, fluence, bias voltage}
294 std::vector<std::vector<TString> > infile = list_files(tl);
295 TString z, e;
296 TString tmp = "";
297 for (uint ifile = 0; ifile < infile.size(); ifile++) {
298 tmp = infile.at(ifile).at(0);
299 in.open(infile.at(ifile).at(0));
300 // Number format eg 10e14 also 1.2e13
301 //fluence = (infile.at(ifile).at(1).ReplaceAll("e14","")).Atof();
302 fluence = (infile.at(ifile).at(1)).Atof();
303 fluence = fluence * 1e-14; //choose fluence e14 as default unit
304 voltage = infile.at(ifile).at(2).Atof();
305 Int_t nlines = 0;
306 efield.clear();
307 pixeldepth.clear();
308 while (1) {
309 in >> z >> e;
310 if (!in.good()) {
311 ATH_MSG_DEBUG("Break for file No. " << ifile << ": " << infile.at(ifile).at(0) << " . After " << nlines << " steps");
312 break;
313 }
314 ATH_MSG_DEBUG("Reading input line: fluence=" << (infile.at(ifile).at(1)).Data() << fluence << " voltage=" << voltage << " e=" << e.Atof() << "=" << e.Data() << ", z=" << (int) z.Atof() << "=" << z.Data() << " in file = " << ifile);
315 nlines++;
316 efield.push_back(e.Atof());
317 pixeldepth.push_back((int) z.Atof());
318 if (z.Atof() > 200) isIBL = false; // Pixel depth to huge to be IBL
319 }
320 bufferTCADtree->cd();
321 tcadtree->Fill();
322 in.close();
323 }
324 if (!isIBL) {
325 ATH_MSG_INFO("Pixel depth read from file too big for IBL. Set to B layer, depth = 250um\n");
326 m_sensorDepth = 250;
327 }
328 bufferTCADtree->cd();
329 tcadtree->Write();
330 bufferTCADtree->Close();
331 return fName.Data();
332}
333
334std::vector<std::vector<TString> > EfieldInterpolator::list_files(const TString& fileList_TCADsamples) {
335 std::vector<std::vector<TString> > filelist;
336 TString tmpname = "";
337 TString tmpfluence = "";
338 TString tmpvolt = "";
339 std::vector<TString> vstr;
340 std::ifstream in;
341 ATH_MSG_DEBUG("Try to open: " << fileList_TCADsamples.Data());
342 in.open(fileList_TCADsamples);
343 while (1) {
344 in >> tmpname >> tmpfluence >> tmpvolt;
345 if (!in.good()) break;
346 if (tmpname.BeginsWith('#')) continue;
347 if (tmpname.EndsWith(".dat")) {
348 vstr.push_back(tmpname);
349 vstr.push_back(tmpfluence);
350 vstr.push_back(tmpvolt);
351 filelist.push_back(vstr);
352 ATH_MSG_DEBUG("Found and load:" << tmpfluence.Atof() << " neq/cm2 " << tmpvolt.Atof() << "V - " << tmpname.Data());
353 vstr.clear();
354 } else {
355 ATH_MSG_WARNING("Wrong extension: " << tmpname.Data() << " -- check input ");
356 }
357 }
358 in.close();
359 return filelist;
360}
361
362// Return path to file containing tree
363// Final tree is restructured providing e field value as function of fluence, voltage and pixeldepth
364const std::string EfieldInterpolator::createInterpolationFromTCADtree(const std::string& fTCAD) {
365 TString tmpfinter = fTCAD;
366
367 tmpfinter.ReplaceAll("toTTree", "toInterpolationTTree");
368 TFile* faim = new TFile(tmpfinter, "Recreate");
369 TFile* ftreeTCAD = new TFile(fTCAD.c_str());
370 TTreeReader myReader("tcad", ftreeTCAD);
371 TTreeReaderValue<double> involtage(myReader, "voltage");
372 TTreeReaderValue<double> influence(myReader, "fluence");
373 TTreeReaderValue<std::vector<double> > inefield(myReader, "efield");
374 TTreeReaderValue<std::vector<int> > inpixeldepth(myReader, "pixeldepth");
375 // Get Data from TCAD tree
376 // Loop tree once to initialize values
377 // Finding which values for fluence and bias voltage exist
378 // do not hardcode values to maintain compatibility with new simulations available
379 std::vector<double> allFluences; // serves as x-axis
380 std::vector<double> allVoltages; // serves as y-axis
381 std::vector<double> allEfield;
382 int ne = 0;
383 double tmpflu, tmpvol;
384 while (myReader.Next()) {
385 tmpflu = *influence;
386 tmpvol = *involtage;
387 //Check if (double) value of fluence and bias voltage is already saved: if not save
388 if (std::find_if(allFluences.begin(), allFluences.end(), [&tmpflu](const double& b) {
389 return(std::abs(tmpflu - b) < 1E-6);
390 }) == allFluences.end()) allFluences.push_back(tmpflu);
391 if (std::find_if(allVoltages.begin(), allVoltages.end(), [&tmpvol](const double& b) {
392 return(std::abs(tmpvol - b) < 1E-6);
393 }) == allVoltages.end()) allVoltages.push_back(tmpvol);
394 ne++;
395 }
396 //put into ascending order
397 std::sort(allFluences.begin(), allFluences.end());
398 std::sort(allVoltages.begin(), allVoltages.end());
399 for (double & allFluence : allFluences) ATH_MSG_DEBUG("fluences recorded: " << allFluence);
400 for (double & allVoltage : allVoltages) ATH_MSG_DEBUG("voltages recorded: " << allVoltage);
401 std::vector<double> tmpef;
402 myReader.Restart(); //available from ROOT 6.10.
403 //Exclude TCAD efield values close to sensor edge
404 int leftEdge = 3; //unify maps - different startting points from z=1 to z=2 and z=3. Simulation not reliable at edges,
405 // skip first and last
406 int rightEdge = m_sensorDepth - 2;
407 std::vector<int> tmpz;
408 int nz = rightEdge - leftEdge;
409 // Temporary saving to avoid nesting tree loops
410 // ie read all z values at once -> add to each branch-param dimension for z
411 std::vector<double> zpixeldepth(nz, -1);
412 std::vector<std::vector<double> > zfluence(nz, std::vector<double>(ne, -1));
413 std::vector<std::vector<double> > zvoltage(nz, std::vector<double>(ne, -1));
414 std::vector<std::vector<double> > zefield(nz, std::vector<double>(ne, -1));
415 std::vector<std::vector<std::vector<double> > > zefieldmap(nz, std::vector<std::vector<double> >(allFluences.size(), std::vector<double>(allVoltages.size(), -1)));
416 int iev = 0;
417 ATH_MSG_INFO("Access TTreeReader second time\n");
418
419 while (myReader.Next()) {
420 tmpz = *inpixeldepth; //Pixeldepth of current TCAD map
421 ATH_MSG_DEBUG("Number of available z values = " << tmpz.size());
422 if (tmpz.at(0) > leftEdge) ATH_MSG_WARNING("Map starting from high pixeldepth = " << tmpz.at(0) << ". Might trouble readout.");
423 for (int iz = leftEdge; iz < rightEdge; iz++) {
424 int index = 0;
425 //Safety check:
426 //files starting from z=1, z=2 or z=3
427 //determine correct index to match sensor depth
428 ATH_MSG_DEBUG("Access tmpz \n");
429 ATH_MSG_DEBUG("Adapt index shift \n");
430 while ((tmpz.at(index) != iz) && (index < nz)) {
431 ATH_MSG_DEBUG("Adapt possible index shift for missing edge values: pixeldepth tree = " << nz << " current index = " << index);
432 index++;
433 }
434 if (iz % 2 == 0) ATH_MSG_DEBUG("Index " << index << " - iev " << iev << " - iz " << iz);
435 tmpflu = *influence;
436 tmpvol = *involtage;
437 tmpef = *inefield;
438 zfluence.at(iz - leftEdge).at(iev) = tmpflu; // assign value to certain pixeldepth(z)
439 zvoltage.at(iz - leftEdge).at(iev) = tmpvol;
440 zefield.at(iz - leftEdge).at(iev) = tmpef.at(index);
441 ((zefieldmap.at(iz - leftEdge)).at(isContainedAt(allFluences, tmpflu))).at(isContainedAt(allVoltages, tmpvol)) = tmpef.at(index);
442 ATH_MSG_DEBUG("Event #" << iev << "-z=" << iz << ": fluence =" << tmpflu << " voltage=" << tmpvol << ", E=" << tmpef.at(index));
443 }
444 iev++;
445 }
446 ATH_MSG_DEBUG("# Start filling interpolation tree \n");
447 //Filling the interpolation tree
448 faim->cd();
449 TTree* tz_tmp = new TTree("tz", "All TCAD E field simulations stored splitted by pixel depth");
450 double pixeldepth = -1.;
451 std::vector<double> fluence;
452 std::vector<double> voltage;
453 std::vector<double> xfluence;
454 std::vector<double> yvoltage;
455 std::vector<double> efield;
456 std::vector<std::vector<double> > efieldfluvol;
457
458 tz_tmp->Branch("pixeldepth", &pixeldepth);
459 tz_tmp->Branch("voltage", &voltage);
460 tz_tmp->Branch("fluence", &fluence);
461 tz_tmp->Branch("yvoltage", &yvoltage);
462 tz_tmp->Branch("xfluence", &xfluence);
463 tz_tmp->Branch("efield", &efield);
464 tz_tmp->Branch("efieldfluvol", &efieldfluvol);
465 for (int iz = leftEdge; iz < rightEdge; iz++) {
466 pixeldepth = iz;
467 fluence = zfluence.at(iz - leftEdge);
468 voltage = zvoltage.at(iz - leftEdge);
469 efield = zefield.at(iz - leftEdge);
470 efieldfluvol = zefieldmap.at(iz - leftEdge);
471 xfluence = allFluences;
472 yvoltage = allVoltages;
473 ATH_MSG_DEBUG("Fill tree for z =" << iz << " pd=" << pixeldepth);
474 faim->cd();
475 tz_tmp->Fill();
476 }
477
478 //Save new Interpolation tree
479 faim->cd();
480 tz_tmp->Write();
481 faim->Close();
482 m_fInter = tmpfinter.Data();
483 return m_fInter;
484}
485
486// Retrieve fluence values corresponding to a fixed voltage or viceversa if regular order == false
487int EfieldInterpolator::fillXYvectors(const std::vector<double> & vLoop, int ifix, const std::vector<std::vector<double> > & v2vsv1, std::vector<double>& xx, std::vector<double>& yy, bool regularOrder) {
488 yy.clear();
489 xx.clear();
490 int nfills = 0;
491 if (regularOrder) {
492 for (uint ie = 0; ie < v2vsv1.size(); ie++) {
493 double ef = v2vsv1.at(ie).at(ifix); // different fluences for voltage ifix
494 if (ef > 0) {
495 yy.push_back(ef);
496 xx.push_back(vLoop.at(ie));
497 nfills++;
498 } else {
499 ATH_MSG_DEBUG("E field value not available for Phi=" << vLoop.at(ie) << " index Vol= " << ifix);
500 //Values not ordered in a regular fluence-bias voltage grid
501 }
502 }
503 } else {
504 for (uint ie = 0; ie < v2vsv1.at(0).size(); ie++) {
505 double ef = v2vsv1.at(ifix).at(ie);
506 if (ef > 0) {
507 yy.push_back(ef);
508 xx.push_back(vLoop.at(ie));
509 nfills++;
510 } else {
511 ATH_MSG_DEBUG("E field value not available for Phi=" << vLoop.at(ifix) << " U=" << vLoop.at(ie));
512 //Values not ordered in a regular fluence-bias voltage grid
513 }
514 }
515 }
516
517 return nfills;
518}
519
520//Final computation of efield according to method specified
522 return aimVoltage / (float) m_efieldProfile->GetNbinsX() * 10000; //10^4 for unit conversion
523}
524
525//Interpolate following inverse distance weighted Interpolation
526double EfieldInterpolator::estimateEfieldInvDistance(const std::vector<double> & vvol, const std::vector<double> & vflu, const std::vector<std::vector<double> > & vfluvvol, double aimFlu, double aimVol, double measure) {
527 ATH_MSG_WARNING("Use interpolation method _Inverse distance weighted_ - guarantees positive E field but no reliable interpolation");
528 double weight = 0.;
529 double meanEf = 0.;
530 double distance = 1.;
531 double efEntry = 0.;
532 //Loop available efield values for fluence/voltage - take weighted mean
533 for (uint ivol = 0; ivol < vvol.size(); ivol++) {
534 for (uint iflu = 0; iflu < vflu.size(); iflu++) {
535 efEntry = vfluvvol.at(iflu).at(ivol);
536 if (efEntry > 0.) { //Otherwise (-1), TCAD not available
537 distance = relativeDistance(aimVol, aimFlu, vvol.at(ivol), vflu.at(iflu));
538 if (distance < 0.00001) return efEntry;//fluence and voltage almost correpsond to available TCAD simulation
539
540 meanEf += efEntry * TMath::Power((1. / distance), measure);
541 weight += TMath::Power((1. / distance), measure);
542 }
543 }
544 }
545 return(meanEf / weight);
546}
547
548// Interpolate using cubic splines
549// E efield values given as function of fluence and bias voltage (vvol, vflu)
550// interpolate to value for aimFluence and aimVoltage
551double EfieldInterpolator::estimateEfield(std::vector<double> vvol, const std::vector<double>& vflu, const std::vector<std::vector<double> >& vfluvvol, double aimFlu, double aimVol, const std::string& prepend, bool debug) {
552 ATH_MSG_DEBUG("Estimating efield");
553 std::vector<double> evol; // e field values for fixed voltages inter- or extrapolated to fluence of interest
554 std::vector<double> vvolWoEp; // fixed voltages values for which no extrapolation is used to obatin E field in
555 // between fluences
556 std::vector<double> evolWoEp;
557 //Loop the voltages
558 for (uint ifix = 0; ifix < vvol.size(); ifix++) {
559 std::vector<double> vx;// = new std::vector<double> ;
560 std::vector<double> vy;// = new std::vector<double>;
561 double efflu = -1.;
562 int availableTCADpoints = fillXYvectors(vflu, ifix, vfluvvol, vx, vy);
563 ATH_MSG_DEBUG("Number of available TCAD points for voltage " << vvol.at(ifix) << ": " << availableTCADpoints);
564 TString name = "FluenceEfield_";
565 name += ifix;
566 name += "FixVol";
567 name += TString::Format("%.0f", vvol.at(ifix));
568 name += "-aimFlu";
569 name += TString::Format("%.1f", aimFlu);
570 name += "-aimVol";
571 name += TString::Format("%.0f", aimVol);
572
573 TGraph* tmpgr = new TGraph(CastStdVec(vx), CastStdVec(vy));
574 tmpgr->SetTitle(name.Data());
575 if (isInterpolation(vx, aimFlu)) {
576 name += "_ip";
577 } else {
578 name += "_ep";
579 }
580 if (m_useSpline) {
581 efflu = tmpgr->Eval(aimFlu, nullptr, "S");
582 } else {
583 efflu = tmpgr->Eval(aimFlu); //linear extrapolation
584 }
585 if (debug) {
586 TString aimFile = m_fInter;
587 aimFile.ReplaceAll(".root", "_debug.root");
588 aimFile.ReplaceAll(".root", prepend);
589 aimFile += name;
590 aimFile += ".root";
591 tmpgr->SaveAs(aimFile);
592 }
593 if (isInterpolation(vx, aimFlu)) {
594 // try without extrapolation: skip extrapolated values
595 vvolWoEp.push_back(vvol.at(ifix));
596 evolWoEp.push_back(efflu);
597 }
598
599 delete tmpgr;
600 evol.push_back(efflu); //includes extrapolated values
601 }//end loop voltages
602
603 //Check for debugging distribution of available E field values in fluence and
604 if (debug) {
605 saveTGraph(vvol, vflu, vfluvvol, aimFlu, aimVol, prepend);
606 }
607 // if possible to reach voltage of interest without any extrapolation in previous step, prefer this
608 if (isInterpolation(vvolWoEp, aimVol) && vvolWoEp.size() > 1) {
609 vvol = std::move(vvolWoEp);
610 evol = std::move(evolWoEp);
611 } else {
612 ATH_MSG_WARNING("E field created on extrapolation. Please check if reasonable!");
613 }
614
615 TString name = "VoltageEfield";
616 name += "-aimFlu";
617 name += TString::Format("%.1f", aimFlu);
618 name += "-aimVol";
619 name += TString::Format("%.0f", aimVol);
620 double aimEf = -1;
621 TGraph* tmpgr = new TGraph(CastStdVec(vvol), CastStdVec(evol));
622 tmpgr->SetTitle(name.Data());
623 if (isInterpolation(vvol, aimVol)) {
624 name += "_ip";
625 } else {
626 name += "_ep";
627 }
628 if (m_useSpline) {
629 aimEf = tmpgr->Eval(aimVol, nullptr, "S");
630 } else {
631 aimEf = tmpgr->Eval(aimVol); //linear extrapolation
632 }
633 if (debug) {
634 TString aimFile = m_fInter;
635 aimFile.ReplaceAll(".root", "_debug.root");
636 aimFile.ReplaceAll(".root", prepend);
637 aimFile += name;
638 aimFile += ".root";
639 tmpgr->SaveAs(aimFile);
640 }
641 delete tmpgr;
642 return aimEf;
643}
644
645//Save all E field values as function of fluence and bias voltage for debugging
646void EfieldInterpolator::saveTGraph(std::vector<double> vvol, std::vector<double> vflu, std::vector<std::vector<double> > vfluvvol, double aimFlu, double aimVol, const std::string& prepend, bool skipNegative) {
647 TString name = "VoltageEfield";
648
649 name += "-aimFlu";
650 name += TString::Format("%.1f", aimFlu);
651 name += "-aimVol";
652 name += TString::Format("%.0f", aimVol);
653 TGraph2D* tmpgr = new TGraph2D();
654 tmpgr->GetYaxis()->SetTitle("voltage");
655 tmpgr->GetXaxis()->SetTitle("fluence");
656 tmpgr->SetTitle(name.Data());
657 ATH_MSG_DEBUG("E field values: " << vfluvvol.size() << " x " << vfluvvol.at(0).size() << ", flu(x)" << vflu.size() << ", vol(y)" << vvol.size());
658 int npoint = 0;
659 for (uint ix = 0; ix < vfluvvol.size(); ix++) {
660 for (uint iy = 0; iy < vfluvvol.at(ix).size(); iy++) {
661 printf("Set point %i, %f,%f,%f\n", npoint, vflu.at(ix), vvol.at(iy), vfluvvol.at(ix).at(iy));
662 if (vfluvvol.at(ix).at(iy) < 0) {
663 if (!skipNegative) tmpgr->SetPoint(npoint, vflu.at(ix), vvol.at(iy), -1);
664 } else {
665 tmpgr->SetPoint(npoint, vflu.at(ix), vvol.at(iy), vfluvvol.at(ix).at(iy));
666 }
667 npoint++;
668 }
669 }
670 TString aimFile = m_fInter;
671 aimFile.ReplaceAll(".root", "_debugAvailableEfieldVals.root");
672 aimFile.ReplaceAll(".root", prepend);
673 aimFile += name;
674 aimFile += ".root";
675 tmpgr->SaveAs(aimFile);
676}
677
678TH1D* EfieldInterpolator::createEfieldProfile(double aimFluence, double aimVoltage) {
679 if (!m_initialized) {
680 ATH_MSG_WARNING("ERROR: EfieldInterpolator not properly intialized from " << m_fInter);
681 return nullptr;
682 }
683 if (aimFluence > 1e12) aimFluence = aimFluence / 1e14; //adapt units - TCAD files save 20 for 20e14 neq/cm2
684 TString title = "hefieldz";
685 TString info = "#Phi=";
686 info += TString::Format("%.2f", aimFluence);
687 info += "-U=";
688 info += TString::Format("%.0f", aimVoltage);
689 info += ";Pixeldepth z [#mum]";
690 info += ";E [V/cm]";
691 m_efieldProfile = new TH1D(title, info, m_sensorDepth, -0.5, m_sensorDepth + 0.5);
692 double pixeldepth;
693 std::vector<double> xfluence;
694 std::vector<double> yvoltage;
695 std::vector<std::vector<double> > efieldfluvol;
696 TFile* ftreeInterpolation = TFile::Open(m_fInter.c_str());
697 TTreeReader myReader("tz", ftreeInterpolation);
698 TTreeReaderValue<std::vector<double> > involtage(myReader, "yvoltage");
699 TTreeReaderValue<std::vector<double> > influence(myReader, "xfluence");
700 TTreeReaderValue<std::vector<std::vector<double> > > inefield(myReader, "efieldfluvol");
701 TTreeReaderValue<double> inpixeldepth(myReader, "pixeldepth");
702 int ientry = 0;
703 while (myReader.Next()) {
704 ATH_MSG_DEBUG("TTree entry: " << ientry);
705 pixeldepth = *inpixeldepth;
706 xfluence = *influence;
707 yvoltage = *involtage;
708 efieldfluvol = *inefield;
709 // Check if interpolation is reliable based on given TCAD samples
710 if (ientry < 2) {
711 reliabilityCheck(aimFluence, xfluence, aimVoltage, yvoltage);
712 }
713 double aimEf = 0.;
714 switch (m_efieldOrigin) {
715 case interspline: aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol, aimFluence, aimVoltage);
716 break;
717
718 case interinvdist: aimEf = estimateEfieldInvDistance(yvoltage, xfluence, efieldfluvol, aimFluence, aimVoltage);
719 break;
720
721 case linearField: m_useSpline = false;
722 aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol, aimFluence, aimVoltage);
723 break;
724
725 case TCAD: aimEf = estimateEfieldLinear(aimVoltage);
726 if (aimEf < 0.) ATH_MSG_ERROR("TCAD E field negative at" << pixeldepth << " !");
727 break;
728 }
729
730 if (aimEf < 0.) {
731 if (m_useSpline) {
732 TString debugName = "negativeSplineZ";
733 debugName += TString::Format("%.0f", pixeldepth);
734 aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol, aimFluence, aimVoltage, debugName.Data(), true);
735 ATH_MSG_INFO("InterpolatorMessage: linearly interpolated e=" << aimEf << ", z=" << pixeldepth << " Phi=," << aimFluence << " U=" << aimVoltage);
736 m_useSpline = false;
737 m_efieldOrigin = linearField; // not as good as interpolation
738 } else {
739 TString debugName = "negativeLinearZ";
740 debugName += TString::Format("%.0f", pixeldepth);
741 aimEf = estimateEfield(yvoltage, xfluence, efieldfluvol, aimFluence, aimVoltage, debugName.Data(), true);
742 ATH_MSG_ERROR("InterpolatorMessage: spline and linear interpolation failed => InvDistWeighhted e=" << aimEf << ", z=" << pixeldepth << " Phi=," << aimFluence << " U=" << aimVoltage);
743 m_efieldOrigin = interinvdist; // not as good as interpolation (linear or spline) but guaranteed to be positive
744 }
745
746 myReader.Restart();
747 }
748 m_efieldProfile->SetBinContent(m_efieldProfile->FindBin(pixeldepth), aimEf);
749 ientry++;
750 }
751 ftreeInterpolation->Close();
752 //Check edge values
753 ATH_MSG_DEBUG("Fill edges");
755 scaleIntegralTo(m_efieldProfile, aimVoltage * 10000, 2, m_sensorDepth); //exclude first and last bin
756 TString newtitle = m_efieldProfile->GetTitle();
757 switch (m_efieldOrigin) {
758 case interspline: newtitle += " spline";
759 break;
760
761 case interinvdist: newtitle += " inverse distance";
762 break;
763
764 case linearField: newtitle += " linear";
765 break;
766
767 case TCAD: newtitle += " TCAD";
768 break;
769 }
770
771 m_efieldProfile->SetTitle(newtitle.Data());
772 ATH_MSG_DEBUG("Created Efield");
773 m_efieldProfile->SetLineWidth(3);
774 m_efieldProfile->SetLineStyle(2);
775 m_efieldProfile->SetLineColor(4);
776 m_efieldProfile->SetStats(0);
777 return m_efieldProfile;
778}
779
780//First few and last few bins of TCAD maps not filled due to edge effect - fill with extrapolation
782 int nBins = hin->GetNbinsX();
783
784 //Check first and last bins if filled
785 // if not extrapolate linearly from two neighbouring values
786 // empty (or zero) e field values cause unphysical behaviour in ATHENA/Allpix
787 for (int i = 5; i > 0; i--) {
788 //first bins
789 float curval = hin->GetBinContent(i);
790 float binii = hin->GetBinContent(i + 1);
791 float biniii = hin->GetBinContent(i + 2);
792 float bini = hin->GetBinContent(i);
793 if ((bini < 0.01 && binii > 0.01 && biniii > 0.01) || ((biniii - binii) / (float) binii * (binii - bini) / (float) binii < -0.2)) {//either neighbour filled and bin negative, or edge detected, i.e. slope changes sign and relatively larger than middle entry
794 bini = extrapolateLinear(i + 1, binii, i + 2, biniii, i);
795 if (bini > 0) {
796 hin->SetBinContent(i, bini);
797 } else {
798 ATH_MSG_WARNING("Could not correct bin " << i << " for zero or edge ");
799 if (curval <= 0.) hin->SetBinContent(i, 1.); //avoid negative Efield
800 }
801 } else {
802 ATH_MSG_INFO("No need to fill edge bin: " << i);
803 }
804 //Last bins = right hand edge
805 curval = hin->GetBinContent(nBins + 1 - i);
806 binii = hin->GetBinContent(nBins + 1 - i - 1);
807 biniii = hin->GetBinContent(nBins + 1 - i - 2);
808 bini = hin->GetBinContent(nBins + 1 - i);
809 if ((bini < 0.01 && binii > 0.01 && biniii > 0.01) || ((biniii - binii) / (float) binii * (binii - bini) / (float) binii < -0.2)) {//left neighbour filled and bin below negative or slope changes sign and magnitude
810 bini = extrapolateLinear(nBins + 1 - i - 2, hin->GetBinContent(nBins + 1 - i - 2), nBins + 1 - i - 1, hin->GetBinContent(nBins + 1 - i - 1), nBins + 1 - i);
811 if (bini > 0.) {
812 hin->SetBinContent(nBins + 1 - i, bini);
813 } else {
814 ATH_MSG_WARNING("Could not correct bin" << nBins + 1 - i << " for zero or edge ");
815 if (curval <= 0.) hin->SetBinContent(nBins + 1 - i, 1.); //avoid negative Efield
816 }
817 } else {
818 ATH_MSG_INFO("No need to fill edge bin: " << (nBins - i));
819 }
820 }
821}
822
823// Main function to be called to create E field of interest
824
825TH1D* EfieldInterpolator::getEfield(double aimFluence, double aimVoltage) {
826 if (m_initialized) {
827 m_efieldProfile = createEfieldProfile(aimFluence, aimVoltage);
828 } else {
829 ATH_MSG_WARNING("EfieldInterpolator not initialized! Not able to produce E field.");
830 }
831 return m_efieldProfile;
832}
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
TVectorD CastStdVec(const std::vector< double > &vin)
int isContainedAt(const std::vector< double > &v, double val)
Instances of this class create a map (TH1D) describing the electric field profile along the pixeldept...
@ interspline
@ interinvdist
@ linearField
unsigned int uint
const bool debug
bool isIBL(uint32_t robId)
#define z
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Property< bool > m_initialized
interpolationMethod m_efieldOrigin
virtual StatusCode finalize() override
Gaudi::Property< int > m_sensorDepth
EfieldInterpolator(const std::string &type, const std::string &name, const IInterface *parent)
TH1D * loadEfieldFromDat(const std::string &fname, bool fillEdges=true)
virtual StatusCode initialize() override
bool initializeFromFile(const std::string &finpath)
std::vector< std::vector< TString > > list_files(const TString &fileList_TCADsamples)
const std::string createInterpolationFromTCADtree(const std::string &fTCAD)
static double relativeDistance(double x1, double x2)
void saveTGraph(std::vector< double > vvol, std::vector< double > vflu, std::vector< std::vector< double > > vfluvvol, double aimFlu, double aimVol, const std::string &prepend, bool skipNegative=true)
bool initializeFromDirectory(const std::string &fpath)
static double extrapolateLinear(double x1, double y1, double x2, double y2, double xaim)
StatusCode loadTCADlist(const std::string &TCADfileListToLoad)
virtual ~EfieldInterpolator()
const std::string loadTCADfiles(const std::string &targetList="")
double estimateEfield(std::vector< double > vvol, const std::vector< double > &vflu, const std::vector< std::vector< double > > &vfluvvol, double aimFlu, double aimVol, const std::string &prepend="", bool debug=false)
int fillXYvectors(const std::vector< double > &vLoop, int ifix, const std::vector< std::vector< double > > &v2vsv1, std::vector< double > &xx, std::vector< double > &yy, bool regularOrder=true)
static void scaleIntegralTo(TH1 *hin, double aimInt, int first=1, int last=-1)
void fillEdgeValues(TH1D *hin)
TH1D * getEfield(double aimFluence, double aimVoltage)
void reliabilityCheck(double aimFluence, const std::vector< double > &fluences, double aimVoltage, const std::vector< double > &voltages)
TH1D * createEfieldProfile(double aimFluence, double aimVoltage)
bool isInterpolation(const std::vector< double > &vval, double aimval)
Gaudi::Property< bool > m_useSpline
double estimateEfieldInvDistance(const std::vector< double > &vvol, const std::vector< double > &vflu, const std::vector< std::vector< double > > &vfluvvol, double aimFlu, double aimVol, double measure=1.)
double estimateEfieldLinear(double aimVoltage)
std::vector< std::string > files
file names and file pointers
Definition hcg.cxx:50
Definition index.py:1
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TFile * file