ECCE @ EIC Software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
generate_distortion_map.C
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file generate_distortion_map.C
1 
2 
3 #include "AnnularFieldSim.h"
4 #include "TTree.h" //this prevents a lazy binding issue and/or is a magic spell.
5 #include "TCanvas.h" //this prevents a lazy binding issue and/or is a magic spell.
6 R__LOAD_LIBRARY(.libs/libfieldsim)
7 
8  char field_string[200];
9  char lookup_string[200];
10 
11 AnnularFieldSim *SetupDefaultSphenixTpc(bool twinMe=false, bool useSpacecharge=true);
12 AnnularFieldSim *SetupDigitalCurrentSphenixTpc(bool twinMe=false, bool useSpacecharge=true);
14 void SurveyFiles(TFileCollection* filelist);
15 
16 
17 void generate_distortion_map(const char * inputpattern="./evgeny_apr/Smooth*.root", const char *outputfilebase="./apr07_maps/apr07", bool hasSpacecharge=true, bool isDigitalCurrent=false){
18 
19  int maxmaps=10;
20  int maxmapsperfile=2;
21 
22 
23  bool hasTwin=true;
24  //bool hasSpacecharge=true;
25 
26  //and some parameters of the files we're loading:
27  bool usesChargeDensity=false; //true if source hists contain charge density per bin. False if hists are charge per bin.
28  float tpc_chargescale=1.6e-19;//Coulombs per bin unit.
29  float spacecharge_cm_per_axis_unit=100;//cm per histogram axis unit.
30 
31  //file names we'll be filling as we go:
32  TFile *infile;
33 
34  TString sourcefilename;
35  TString outputfilename;
36 
37 
38  //find all files that match the input string (we don't need this yet, but doing it before building the fieldsim saves time if there's an empty directory or something.
39  TFileCollection *filelist=new TFileCollection();
40  filelist->Add(inputpattern);
41  filelist->Print();
42  printf("Using pattern \"%s\", found %d files to read, eg : %s\n",inputpattern,filelist->GetList()->GetEntries(),((TFileInfo*)(filelist->GetList()->At(0)))->GetCurrentUrl()->GetUrl());//Title());//Print();
43 
44 
45  SurveyFiles( filelist);
46 
47  //now build the time-consuming part:
48  //AnnularFieldSim *tpc=SetupDefaultSphenixTpc(hasTwin,hasSpacecharge);//loads the lookup, fields, etc.
49  AnnularFieldSim *tpc;
50 
51 
52  //previously I flagged digital current and used a different rossegger lookup table.
53  //now I just resample the histogram in that event. There is a ~hard problem there to get right:
54  //in each direction, if the source hist is binned more finely than the dest hist, I need to sum the total charge
55  //if the source hist is binned more coarsely, I need to interpolate the charge density and multiply by the dest cell volume
56  //but really, I need to differentiate between the source geometry and field point geometry. task for another time...
57  // if (isDigitalCurrent){
58  // tpc=SetupDigitalCurrentSphenixTpc(hasTwin,hasSpacecharge);//loads the lookup, fields, etc.
59  // }else {
60  tpc=SetupDefaultSphenixTpc(hasTwin,hasSpacecharge);//loads the lookup, fields, etc.
61  // }
62  //and the location to plot the fieldslices about:
63  TVector3 pos=0.5*(tpc->GetOuterEdge()+tpc->GetInnerEdge());;
64  pos.SetPhi(3.14159);
65 
66 
67 
68 
69 
70  double totalQ=0;
71 
72  for (int i=0;i<filelist->GetNFiles();i++){
73  //for each file, find all histograms in that file.
74  sourcefilename=((TFileInfo*)(filelist->GetList()->At(i)))->GetCurrentUrl()->GetFile();//gross
75  infile=TFile::Open(sourcefilename.Data(),"READ");
76  TList *keys=infile->GetListOfKeys();
77  keys->Print();
78  int nKeys=infile->GetNkeys();
79 
80  for (int j=0;j<nKeys;j++){
81  TObject *tobj=infile->Get(keys->At(j)->GetName());
82  //if this isn't a 3d histogram, skip it:
83  bool isHist=tobj->InheritsFrom("TH3");
84  if (!isHist) continue;
85  TString objname=tobj->GetName();
86  if (objname.Contains("IBF")) continue; //this is an IBF map we don't want.
87  //assume this histogram is a charge map.
88  //load just the averages:
89  if (hasSpacecharge){
90  if (isDigitalCurrent){
91  tpc->load_and_resample_spacecharge(8,36,40,sourcefilename.Data(),tobj->GetName(),0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity);
92  if (hasTwin) tpc->twin->load_and_resample_spacecharge(8,36,40,sourcefilename.Data(),tobj->GetName(),0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity);
93 
94  }
95  tpc->load_spacecharge(sourcefilename.Data(),tobj->GetName(),0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity);
96  if (hasTwin) tpc->twin->load_spacecharge(sourcefilename.Data(),tobj->GetName(),0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity);
97 
98  //or load just the average:
99  //tpc->load_spacecharge(sourcefilename.Data(),"h_Charge_0",0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity);
100  printf("Sanity check: Q has %d elements and dim=%d\n",tpc->q->Length(), tpc->q->dim);
101  totalQ=0;
102  for (int k=0;k<tpc->q->Length();k++){
103  totalQ+=*(tpc->q->GetFlat(k));
104  }
105  printf("Sanity check: Total Q in reported region is %E C\n",totalQ);
106  }
107  tpc->populate_fieldmap();
108  if (hasTwin) tpc->twin->populate_fieldmap();
109  if (sourcefilename.Contains("verage")){ //this is an IBF map we don't want.
110  outputfilename=Form("%s.average.%s.%s",outputfilebase,field_string,lookup_string);
111  } else {
112  outputfilename=Form("%s.file%d.%s.%s.%s",outputfilebase,fileIndex,tobj->GetName(),field_string,lookup_string);
113  }
114  printf("%s file has %s hist. field=%s, lookup=%s. no scaling.\n",
115  sourcefilename.Data(),tobj->GetName(),field_string,lookup_string);
116 
117  //TestSpotDistortion(tpc);
118 
119  //tpc->GenerateDistortionMaps(outputfilename,2,2,2,1,true);
120  tpc->GenerateSeparateDistortionMaps(outputfilename,2,2,2,1,true);
121  printf("distortions mapped.\n");
122  tpc->PlotFieldSlices(outputfilename,pos);
123  tpc->PlotFieldSlices(outputfilename,pos,'B');
124  printf("fieldslices plotted.\n");
125  printf("obj %d: getname: %s inherits from TH3D:%d \n",j,tobj->GetName(),tobj->InheritsFrom("TH3"));
126  //break; //rcc temp -- uncomment this to process one hist per file.
127  if (i>maxmaps) return;
128  }
129  infile->Close();
130  }
131 
132  return;
133 
134 }
135 
137  TVector3 dummy(20.9034,-2.3553,-103.4712);
138  float dummydest=-103.4752;
139  t->twin->GetStepDistortion(dummydest,dummy,true,false);
140  dummy.SetZ(dummy.Z()*-1);
141  t->GetStepDistortion(-dummydest,dummy,true,false);
142  return;
143 }
144 
145 AnnularFieldSim *SetupDefaultSphenixTpc(bool twinMe, bool useSpacecharge){
146  //step1: specify the sPHENIX space charge model parameters
147  const float tpc_rmin=20.0;
148  const float tpc_rmax=78.0;
149  float tpc_deltar=tpc_rmax-tpc_rmin;
150  const float tpc_z=105.5;
151  const float tpc_cmVolt=-400*tpc_z; //V =V_CM-V_RDO -- volts per cm times the length of the drift volume.
152  //const float tpc_magField=0.5;//T -- The old value used in carlos's studies.
153  //const float tpc_driftVel=4.0*1e6;//cm per s -- used in carlos's studies
154  const float tpc_driftVel=8.0*1e6;//cm per s -- 2019 nominal value
155  const float tpc_magField=1.4;//T -- 2019 nominal value
156  const char detgeoname[]="sphenix";
157 
158  //step 2: specify the parameters of the field simulation. Larger numbers of bins will rapidly increase the memory footprint and compute times.
159  //there are some ways to mitigate this by setting a small region of interest, or a more parsimonious lookup strategy, specified when AnnularFieldSim() is actually constructed below.
160  int nr=26;//10;//24;//159;//159 nominal
161  int nr_roi_min=0;
162  int nr_roi=nr;//10;
163  int nr_roi_max=nr_roi_min+nr_roi;
164  int nphi=40;//38;//360;//360 nominal
165  int nphi_roi_min=0;
166  int nphi_roi=nphi;//38;
167  int nphi_roi_max=nphi_roi_min+nphi_roi;
168  int nz=40;//62;//62 nominal
169  int nz_roi_min=0;
170  int nz_roi=nz;
171  int nz_roi_max=nz_roi_min+nz_roi;
172 
173  bool realB=true;
174  bool realE=true;
175 
176 
177  //step 3: create the fieldsim object. different choices of the last few arguments will change how it builds the lookup table spatially, and how it loads the spacecharge. The various start-up steps are exposed here so they can be timed in the macro.
178  AnnularFieldSim *tpc;
179  if (useSpacecharge){
180  tpc= new AnnularFieldSim(tpc_rmin,tpc_rmax,tpc_z,
181  nr, nr_roi_min,nr_roi_max,1,2,
182  nphi,nphi_roi_min, nphi_roi_max,1,2,
183  nz, nz_roi_min, nz_roi_max,1,2,
185  }else{
186  tpc= new AnnularFieldSim(tpc_rmin,tpc_rmax,tpc_z,
187  nr, nr_roi_min,nr_roi_max,1,2,
188  nphi,nphi_roi_min, nphi_roi_max,1,2,
189  nz, nz_roi_min, nz_roi_max,1,2,
191  }
192 
193  tpc->UpdateEveryN(10);//show reports every 10%.
194 
195  //load the field maps, either flat or actual maps
196  tpc->setFlatFields(tpc_magField,tpc_cmVolt/tpc_z);
197  sprintf(field_string,"flat_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
198 
199  if (realE){
200  tpc->loadEfield("externalEfield.ttree.root","fTree");
201  sprintf(field_string,"realE_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
202  }
203  if (realB){
204  tpc->load3dBfield("sphenix3dmaprhophiz.root","fieldmap",1,-1.4/1.5);
205  //tpc->loadBfield("sPHENIX.2d.root","fieldmap");
206  sprintf(field_string,"realB_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
207  }
208  if (realE && realB){
209  sprintf(field_string,"real_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
210  }
211  printf("set fields.\n");
212 
213 
214 
215 
216  //load the greens functions:
217  sprintf(lookup_string,"ross_phi1_%s_phislice_lookup_r%dxp%dxz%d",detgeoname,nr,nphi,nz);
218  char lookupFilename[300];
219  //sprintf(lookupFilename,"%s.root",lookup_string);
220  sprintf(lookupFilename,"/sphenix/user/rcorliss/rossegger/%s.root",lookup_string); //hardcoded for racf
221  TFile *fileptr=TFile::Open(lookupFilename,"READ");
222 
223  if (!fileptr){ //generate the lookuptable
224  //to use the full rossegger terms instead of trivial free-space greens functions, uncomment the line below:
225  tpc->load_rossegger();
226  printf("loaded rossegger greens functions.\n");
227  tpc->populate_lookup();
228  tpc->save_phislice_lookup(lookupFilename);
229  } else{ //load it from a file
230  fileptr->Close();
231  tpc->load_phislice_lookup(lookupFilename);
232  }
233 
234  printf("populated lookup.\n");
235 
236 
237 
238 
239 
240 
241 
242  //make our twin:
243  if(twinMe){
244  AnnularFieldSim *twin;
245  if (useSpacecharge){
246  twin= new AnnularFieldSim(tpc_rmin,tpc_rmax,-tpc_z,
247  nr, nr_roi_min,nr_roi_max,1,2,
248  nphi,nphi_roi_min, nphi_roi_max,1,2,
249  nz, nz_roi_min, nz_roi_max,1,2,
251  } else{
252  twin= new AnnularFieldSim(tpc_rmin,tpc_rmax,-tpc_z,
253  nr, nr_roi_min,nr_roi_max,1,2,
254  nphi,nphi_roi_min, nphi_roi_max,1,2,
255  nz, nz_roi_min, nz_roi_max,1,2,
257  } twin->UpdateEveryN(10);//show reports every 10%.
258 
259  //same magnetic field, opposite electric field
260  twin->setFlatFields(tpc_magField,-tpc_cmVolt/tpc_z);
261  //sprintf(field_string,"flat_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
262  //twin->loadBfield("sPHENIX.2d.root","fieldmap");
263  twin->load3dBfield("/sphenix/user/rcorliss/rossegger/sphenix3dmaprhophiz.root","fieldmap",1,-1.4/1.5);
264  twin->loadEfield("/sphenix/user/rcorliss/rossegger/externalEfield.ttree.root","fTree",-1);//final '-1' tells it to flip z and the field z coordinate. r coordinate doesn't change, and we assume phi won't either, though the latter is less true.
265 
266 
267 
268 
269  //borrow the greens functions:
270  twin->borrow_rossegger(tpc->green,tpc_z);//use the original's green's functions, shift our internal coordinates by tpc_z when querying those functions.
271  twin->borrow_epartial_from(tpc,tpc_z);//use the original's epartial. Note that those values ought to be symmetric about z, and since our boundary conditions are translated along with our coordinates, they're completely unchanged.
272 
273  tpc->set_twin(twin);
274  }
275 
276  return tpc;
277 }
278 
279 
280 AnnularFieldSim *SetupDigitalCurrentSphenixTpc(bool twinMe, bool useSpacecharge){
281  //step1: specify the sPHENIX space charge model parameters
282  const float tpc_rmin=20.0;
283  const float tpc_rmax=78.0;
284  float tpc_deltar=tpc_rmax-tpc_rmin;
285  const float tpc_z=105.5;
286  const float tpc_cmVolt=-400*tpc_z; //V =V_CM-V_RDO -- volts per cm times the length of the drift volume.
287  //const float tpc_magField=0.5;//T -- The old value used in carlos's studies.
288  //const float tpc_driftVel=4.0*1e6;//cm per s -- used in carlos's studies
289  const float tpc_driftVel=8.0*1e6;//cm per s -- 2019 nominal value
290  const float tpc_magField=1.4;//T -- 2019 nominal value
291  const char detgeoname[]="sphenix";
292 
293  //step 2: specify the parameters of the field simulation. Larger numbers of bins will rapidly increase the memory footprint and compute times.
294  //there are some ways to mitigate this by setting a small region of interest, or a more parsimonious lookup strategy, specified when AnnularFieldSim() is actually constructed below.
295  int nr=8;//10;//24;//159;//159 nominal
296  int nr_roi_min=0;
297  int nr_roi=nr;//10;
298  int nr_roi_max=nr_roi_min+nr_roi;
299  int nphi=3*12;//38;//360;//360 nominal
300  int nphi_roi_min=0;
301  int nphi_roi=nphi;//38;
302  int nphi_roi_max=nphi_roi_min+nphi_roi;
303  int nz=40;//62;//62 nominal
304  int nz_roi_min=0;
305  int nz_roi=nz;
306  int nz_roi_max=nz_roi_min+nz_roi;
307 
308  bool realB=true;
309  bool realE=true;
310 
311 
312  //step 3: create the fieldsim object. different choices of the last few arguments will change how it builds the lookup table spatially, and how it loads the spacecharge. The various start-up steps are exposed here so they can be timed in the macro.
313  AnnularFieldSim *tpc;
314  if (useSpacecharge){
315  tpc= new AnnularFieldSim(tpc_rmin,tpc_rmax,tpc_z,
316  nr, nr_roi_min,nr_roi_max,1,2,
317  nphi,nphi_roi_min, nphi_roi_max,1,2,
318  nz, nz_roi_min, nz_roi_max,1,2,
320  }else{
321  tpc= new AnnularFieldSim(tpc_rmin,tpc_rmax,tpc_z,
322  nr, nr_roi_min,nr_roi_max,1,2,
323  nphi,nphi_roi_min, nphi_roi_max,1,2,
324  nz, nz_roi_min, nz_roi_max,1,2,
326  }
327 
328  tpc->UpdateEveryN(10);//show reports every 10%.
329 
330  //load the field maps, either flat or actual maps
331  tpc->setFlatFields(tpc_magField,tpc_cmVolt/tpc_z);
332  sprintf(field_string,"flat_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
333 
334  if (realE){
335  tpc->loadEfield("externalEfield.ttree.root","fTree");
336  sprintf(field_string,"realE_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
337  }
338  if (realB){
339  tpc->load3dBfield("sphenix3dmaprhophiz.root","fieldmap",1,-1.4/1.5);
340  //tpc->loadBfield("sPHENIX.2d.root","fieldmap");
341  sprintf(field_string,"realB_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
342  }
343  if (realE && realB){
344  sprintf(field_string,"real_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
345  }
346  printf("set fields.\n");
347 
348 
349 
350 
351  //load the greens functions:
352  sprintf(lookup_string,"ross_phi1_%s_phislice_lookup_r%dxp%dxz%d",detgeoname,nr,nphi,nz);
353  char lookupFilename[200];
354  sprintf(lookupFilename,"%s.root",lookup_string);
355  TFile *fileptr=TFile::Open(lookupFilename,"READ");
356 
357  if (!fileptr){ //generate the lookuptable
358  //to use the full rossegger terms instead of trivial free-space greens functions, uncomment the line below:
359  tpc->load_rossegger();
360  printf("loaded rossegger greens functions.\n");
361  tpc->populate_lookup();
362  tpc->save_phislice_lookup(lookupFilename);
363  } else{ //load it from a file
364  fileptr->Close();
365  tpc->load_phislice_lookup(lookupFilename);
366  }
367 
368  printf("populated lookup.\n");
369 
370 
371 
372 
373 
374 
375 
376  //make our twin:
377  if(twinMe){
378  AnnularFieldSim *twin;
379  if (useSpacecharge){
380  twin= new AnnularFieldSim(tpc_rmin,tpc_rmax,-tpc_z,
381  nr, nr_roi_min,nr_roi_max,1,2,
382  nphi,nphi_roi_min, nphi_roi_max,1,2,
383  nz, nz_roi_min, nz_roi_max,1,2,
385  } else{
386  twin= new AnnularFieldSim(tpc_rmin,tpc_rmax,-tpc_z,
387  nr, nr_roi_min,nr_roi_max,1,2,
388  nphi,nphi_roi_min, nphi_roi_max,1,2,
389  nz, nz_roi_min, nz_roi_max,1,2,
391  } twin->UpdateEveryN(10);//show reports every 10%.
392 
393  //same magnetic field, opposite electric field
394  twin->setFlatFields(tpc_magField,-tpc_cmVolt/tpc_z);
395  //sprintf(field_string,"flat_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
396  //twin->loadBfield("sPHENIX.2d.root","fieldmap");
397  twin->load3dBfield("sphenix3dmaprhophiz.root","fieldmap",1,-1.4/1.5);
398  twin->loadEfield("externalEfield.ttree.root","fTree",-1);//final '-1' tells it to flip z and the field z coordinate. r coordinate doesn't change, and we assume phi won't either, though the latter is less true.
399 
400 
401 
402 
403  //borrow the greens functions:
404  twin->borrow_rossegger(tpc->green,tpc_z);//use the original's green's functions, shift our internal coordinates by tpc_z when querying those functions.
405  twin->borrow_epartial_from(tpc,tpc_z);//use the original's epartial. Note that those values ought to be symmetric about z, and since our boundary conditions are translated along with our coordinates, they're completely unchanged.
406 
407  tpc->set_twin(twin);
408  }
409 
410  return tpc;
411 }
412 
413 void SurveyFiles(TFileCollection *filelist){
414  TFile *infile;
415 
416  TString sourcefilename;
417  TString outputfilename;
418  //run a check of the files we'll be looking at:
419  float integral_sum=0;
420  int nhists=0;
421  for (int i=0;i<filelist->GetNFiles();i++){
422  //for each file, find all histograms in that file.
423  sourcefilename=((TFileInfo*)(filelist->GetList()->At(i)))->GetCurrentUrl()->GetFile();//gross
424  printf("file %d: %s\n", i, sourcefilename.Data());
425  infile=TFile::Open(sourcefilename.Data(),"READ");
426  TList *keys=infile->GetListOfKeys();
427  //keys->Print();
428  int nKeys=infile->GetNkeys();
429 
430  for (int j=0;j<nKeys;j++){
431  TObject *tobj=infile->Get(keys->At(j)->GetName());
432  //if this isn't a 3d histogram, skip it:
433  bool isHist=tobj->InheritsFrom("TH3");
434  if (!isHist) continue;
435  TString objname=tobj->GetName();
436  printf(" hist %s ",objname.Data());
437  if (objname.Contains("IBF")) {
438  printf(" is IBF only.\n");
439  continue; //this is an IBF map we don't want.
440  }
441  float integral=((TH3D*)tobj)->Integral();
442  integral_sum+=integral;
443  nhists+=1;
444  printf(" will be used. Total Q=%3.3E (ave=%3.3E)\n",integral,integral_sum/nhists);
445  //assume this histogram is a charge map.
446  //load just the averages:
447 
448  //break; //rcc temp -- uncomment this to process one hist per file.
449  //if (i>maxmaps) return;
450  }
451  infile->Close();
452  }
453  return;
454 }