File indexing completed on 2025-08-05 08:15:40
0001
0002
0003 #include "AnnularFieldSim.h"
0004 #include "TTree.h" //this prevents a lazy binding issue and/or is a magic spell.
0005 #include "TCanvas.h" //this prevents a lazy binding issue and/or is a magic spell.
0006
0007
0008 R__LOAD_LIBRARY(libfieldsim.so)
0009
0010 char field_string[200];
0011 char lookup_string[200];
0012
0013 AnnularFieldSim *SetupDefaultSphenixTpc(bool twinMe=false, bool useSpacecharge=true, float xshift=0, float yshift=0, float zshift=0);
0014 AnnularFieldSim *SetupDigitalCurrentSphenixTpc(bool twinMe=false, bool useSpacecharge=true);
0015 void TestSpotDistortion(AnnularFieldSim *t);
0016 void SurveyFiles(TFileCollection* filelist);
0017
0018
0019 void generate_distortion_map(const char *inputname, const char* gainName, const char *outputname, const char *ibfName, const char *primName, bool hasSpacecharge=true, bool isAdc=false, int nSteps=500, bool scanSteps=false, float xshift=0, float yshift=0, float zshift=0){
0020 printf("generating single distortion map. Caution: This is vastly less efficient than re-using the tpc model once it is set up\n");
0021
0022 bool hasTwin=true;
0023 TString gainHistName[2]={"hIbfGain_posz","hIbfGFain_negz"};
0024
0025
0026 bool usesChargeDensity=false;
0027 float tpc_chargescale=1.6e-19;
0028 float spacecharge_cm_per_axis_unit=0.1;
0029
0030
0031 TFile *infile, *gainfile;
0032
0033 TString sourcefilename=inputname;
0034 TString outputfilename=outputname;
0035
0036
0037 AnnularFieldSim *tpc;
0038 tpc=SetupDefaultSphenixTpc(hasTwin,hasSpacecharge, xshift, yshift, zshift);
0039
0040
0041 TVector3 pos=0.5*(tpc->GetOuterEdge()+tpc->GetInnerEdge());;
0042 pos.SetPhi(3.14159);
0043
0044 infile=TFile::Open(sourcefilename.Data(),"READ");
0045
0046
0047
0048
0049 TH3* hCharge=(TH3*)(infile->Get(ibfName));
0050 if (!isAdc){
0051 hCharge->Add((TH3*)(infile->Get(primName)));
0052 }
0053
0054
0055 TString chargestring;
0056
0057
0058
0059 if (!isAdc){
0060 chargestring=Form("%s:(%s+%s)",inputname,ibfName,primName);
0061 tpc->load_spacecharge(hCharge,0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity, chargestring.Data());
0062 if (hasTwin) tpc->twin->load_spacecharge(hCharge,0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity);
0063 }
0064 if (isAdc){
0065 gainfile=TFile::Open(gainName,"READ");
0066 TH2* hGain[2];
0067 hGain[0]=(TH2*)(gainfile->Get(gainHistName[0]));
0068 chargestring=Form("%s:(dc:%s g:%s:%s)",inputname,ibfName,gainName,gainHistName[0].Data());
0069 tpc->load_digital_current(hCharge,hGain[0],tpc_chargescale,spacecharge_cm_per_axis_unit,chargestring.Data());
0070 if (hasTwin) {
0071 hGain[1]=(TH2*)(gainfile->Get(gainHistName[1]));
0072 tpc->twin->load_digital_current(hCharge,hGain[1],tpc_chargescale,spacecharge_cm_per_axis_unit,chargestring.Data());
0073 }
0074 }
0075
0076 tpc->populate_fieldmap();
0077 if (hasTwin) tpc->twin->populate_fieldmap();
0078
0079
0080 if (scanSteps){
0081 for(int i=0;i<10;i++){
0082 TString study_filestring=Form("%s.steps%d.hist.root","study_file_changinginterval",50*(i+1));
0083 tpc->GenerateSeparateDistortionMaps(std::string(study_filestring.Data()),50*(i+1),1,1,1,1,true);
0084
0085 }
0086 }
0087 else{
0088 tpc->GenerateSeparateDistortionMaps(std::string(outputfilename.Data()),450,1,1,1,1,false);
0089 }
0090
0091 printf("distortions mapped.\n");
0092 tpc->PlotFieldSlices(outputfilename.Data(),pos, 'E');
0093 tpc->PlotFieldSlices(outputfilename.Data(),pos,'B');
0094 printf("fieldslices plotted.\n");
0095
0096 infile->Close();
0097 printf("input closed. All done. Anything else is root's problem.\n");
0098
0099 return;
0100
0101 }
0102
0103
0104 void generate_distortion_map(const char * inputpattern="./evgeny_apr/Smooth*.root", const char *outputfilebase="./apr07_maps/apr07", bool hasSpacecharge=true, bool isDigitalCurrent=false, int nSteps=500){
0105
0106
0107 int maxmaps=10;
0108 int maxmapsperfile=2;
0109
0110
0111 bool hasTwin=true;
0112
0113
0114
0115 bool usesChargeDensity=false;
0116 float tpc_chargescale=1.6e-19;
0117 float spacecharge_cm_per_axis_unit=0.1;
0118
0119
0120 TFile *infile;
0121
0122 TString sourcefilename;
0123 TString outputfilename;
0124
0125
0126
0127 TFileCollection *filelist=new TFileCollection();
0128 filelist->Add(inputpattern);
0129 filelist->Print();
0130 printf("Using pattern \"%s\", found %d files to read, eg : %s\n",inputpattern,filelist->GetList()->GetEntries(),((TFileInfo*)(filelist->GetList()->At(0)))->GetCurrentUrl()->GetUrl());
0131
0132
0133
0134
0135
0136
0137 AnnularFieldSim *tpc;
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148 tpc=SetupDefaultSphenixTpc(hasTwin,hasSpacecharge);
0149
0150
0151 TVector3 pos=0.5*(tpc->GetOuterEdge()+tpc->GetInnerEdge());;
0152 pos.SetPhi(3.14159);
0153
0154
0155
0156
0157
0158 double totalQ=0;
0159
0160 for (int i=0;i<filelist->GetNFiles();i++){
0161
0162 sourcefilename=((TFileInfo*)(filelist->GetList()->At(i)))->GetCurrentUrl()->GetFile();
0163 infile=TFile::Open(sourcefilename.Data(),"READ");
0164 TList *keys=infile->GetListOfKeys();
0165 keys->Print();
0166 int nKeys=infile->GetNkeys();
0167
0168 for (int j=0;j<nKeys;j++){
0169 TObject *tobj=infile->Get(keys->At(j)->GetName());
0170
0171 bool isHist=tobj->InheritsFrom("TH3");
0172 if (!isHist) continue;
0173 TString objname=tobj->GetName();
0174 if (objname.Contains("IBF")) continue;
0175
0176
0177 if (hasSpacecharge){
0178 if (isDigitalCurrent){
0179 tpc->load_and_resample_spacecharge(8,36,40,sourcefilename.Data(),tobj->GetName(),0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity);
0180 if (hasTwin) tpc->twin->load_and_resample_spacecharge(8,36,40,sourcefilename.Data(),tobj->GetName(),0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity);
0181
0182 }
0183
0184
0185 tpc->load_spacecharge(sourcefilename.Data(),tobj->GetName(),0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity);
0186 if (hasTwin) tpc->twin->load_spacecharge(sourcefilename.Data(),tobj->GetName(),0,tpc_chargescale,spacecharge_cm_per_axis_unit, usesChargeDensity);
0187
0188
0189
0190
0191
0192
0193
0194
0195 printf("Sanity check: Total Q in reported region is %E C\n",totalQ);
0196 }
0197 tpc->populate_fieldmap();
0198 if (hasTwin) tpc->twin->populate_fieldmap();
0199 if (sourcefilename.Contains("verage")){
0200 outputfilename=Form("%s.average.%s.%s",outputfilebase,field_string,lookup_string);
0201 } else {
0202 outputfilename=Form("%s.file%d.%s.%s.%s",outputfilebase,i,tobj->GetName(),field_string,lookup_string);
0203 }
0204 printf("%s file has %s hist. field=%s, lookup=%s. no scaling.\n",
0205 sourcefilename.Data(),tobj->GetName(),field_string,lookup_string);
0206
0207
0208
0209
0210
0211
0212 tpc->GenerateSeparateDistortionMaps(std::string(outputfilename.Data()),2,2,2,1,true,nSteps);
0213
0214 printf("distortions mapped.\n");
0215 tpc->PlotFieldSlices(outputfilename.Data(),pos);
0216 tpc->PlotFieldSlices(outputfilename.Data(),pos,'B');
0217 printf("fieldslices plotted.\n");
0218 printf("obj %d: getname: %s inherits from TH3D:%d \n",j,tobj->GetName(),tobj->InheritsFrom("TH3"));
0219
0220 if (i>maxmaps) return;
0221 }
0222 infile->Close();
0223 }
0224
0225 return;
0226
0227 }
0228
0229 void TestSpotDistortion(AnnularFieldSim *t){
0230 TVector3 dummy(20.9034,-2.3553,-103.4712);
0231 float dummydest=-103.4752;
0232 t->twin->GetStepDistortion(dummydest,dummy,true,false);
0233 dummy.SetZ(dummy.Z()*-1);
0234 t->GetStepDistortion(-dummydest,dummy,true,false);
0235 return;
0236 }
0237
0238 AnnularFieldSim *SetupDefaultSphenixTpc(bool twinMe, bool useSpacecharge, float xshift, float yshift, float zshift){
0239
0240 const float tpc_rmin=20.0;
0241 const float tpc_rmax=78.0;
0242 float tpc_deltar=tpc_rmax-tpc_rmin;
0243 const float tpc_z=105.5;
0244 const float tpc_cmVolt=-400*tpc_z;
0245
0246
0247 const float tpc_driftVel=8.0*1e6;
0248 const float tpc_magField=1.4;
0249 const char detgeoname[]="sphenix";
0250
0251
0252
0253
0254
0255
0256
0257 int nr=26;
0258 int nr_roi_min=0;
0259 int nr_roi=nr;
0260 int nr_roi_max=nr_roi_min+nr_roi;
0261 int nphi=40;
0262 int nphi_roi_min=0;
0263 int nphi_roi=nphi;
0264 int nphi_roi_max=nphi_roi_min+nphi_roi;
0265 int nz=40;
0266 int nz_roi_min=0;
0267 int nz_roi=nz;
0268 int nz_roi_max=nz_roi_min+nz_roi;
0269
0270 bool realB=true;
0271 bool realE=true;
0272
0273
0274
0275
0276
0277
0278
0279 AnnularFieldSim *tpc;
0280 if (useSpacecharge){
0281 tpc= new AnnularFieldSim(tpc_rmin,tpc_rmax,tpc_z,
0282 nr, nr_roi_min,nr_roi_max,1,2,
0283 nphi,nphi_roi_min, nphi_roi_max,1,2,
0284 nz, nz_roi_min, nz_roi_max,1,2,
0285 tpc_driftVel, AnnularFieldSim::PhiSlice, AnnularFieldSim::FromFile);
0286 }else{
0287 tpc= new AnnularFieldSim(tpc_rmin,tpc_rmax,tpc_z,
0288 nr, nr_roi_min,nr_roi_max,1,2,
0289 nphi,nphi_roi_min, nphi_roi_max,1,2,
0290 nz, nz_roi_min, nz_roi_max,1,2,
0291 tpc_driftVel, AnnularFieldSim::PhiSlice, AnnularFieldSim::NoSpacecharge);
0292 }
0293
0294 tpc->UpdateEveryN(10);
0295
0296
0297 tpc->setFlatFields(tpc_magField,tpc_cmVolt/tpc_z);
0298 sprintf(field_string,"flat_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
0299
0300 if (realE){
0301 tpc->loadEfield("/sphenix/user/rcorliss/field/externalEfield.ttree.root","fTree");
0302 sprintf(field_string,"realE_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
0303 }
0304 if (realB){
0305 tpc->load3dBfield("/sphenix/user/rcorliss/field/sphenix3dmaprhophiz.root","fieldmap",1,-1.4/1.5, xshift, yshift,zshift);
0306
0307 sprintf(field_string,"realB_B%2.1f_E%2.1f_x%2.1f_y%2.1f_z%2.1f",tpc_magField,tpc_cmVolt/tpc_z,xshift, yshift,zshift);
0308 }
0309 if (realE && realB){
0310 sprintf(field_string,"real_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
0311 }
0312 printf("set fields.\n");
0313
0314
0315
0316
0317
0318 sprintf(lookup_string,"ross_phi1_%s_phislice_lookup_r%dxp%dxz%d",detgeoname,nr,nphi,nz);
0319 char lookupFilename[300];
0320
0321 sprintf(lookupFilename,"/sphenix/user/rcorliss/rossegger/%s.root",lookup_string);
0322 TFile *fileptr=TFile::Open(lookupFilename,"READ");
0323
0324 if (!fileptr){
0325
0326 tpc->load_rossegger();
0327 printf("loaded rossegger greens functions.\n");
0328 tpc->populate_lookup();
0329 tpc->save_phislice_lookup(lookupFilename);
0330 } else{
0331 fileptr->Close();
0332 tpc->load_phislice_lookup(lookupFilename);
0333 }
0334
0335 printf("populated lookup.\n");
0336
0337
0338
0339
0340
0341
0342
0343
0344 if(twinMe){
0345 AnnularFieldSim *twin;
0346 if (useSpacecharge){
0347 twin= new AnnularFieldSim(tpc_rmin,tpc_rmax,-tpc_z,
0348 nr, nr_roi_min,nr_roi_max,1,2,
0349 nphi,nphi_roi_min, nphi_roi_max,1,2,
0350 nz, nz_roi_min, nz_roi_max,1,2,
0351 tpc_driftVel, AnnularFieldSim::PhiSlice, AnnularFieldSim::FromFile);
0352 } else{
0353 twin= new AnnularFieldSim(tpc_rmin,tpc_rmax,-tpc_z,
0354 nr, nr_roi_min,nr_roi_max,1,2,
0355 nphi,nphi_roi_min, nphi_roi_max,1,2,
0356 nz, nz_roi_min, nz_roi_max,1,2,
0357 tpc_driftVel, AnnularFieldSim::PhiSlice, AnnularFieldSim::NoSpacecharge);
0358 } twin->UpdateEveryN(10);
0359
0360
0361 twin->setFlatFields(tpc_magField,-tpc_cmVolt/tpc_z);
0362
0363
0364 twin->load3dBfield("/sphenix/user/rcorliss/rossegger/sphenix3dmaprhophiz.root","fieldmap",1,-1.4/1.5, xshift, yshift, zshift);
0365 twin->loadEfield("/sphenix/user/rcorliss/rossegger/externalEfield.ttree.root","fTree",-1);
0366
0367
0368
0369
0370
0371 twin->borrow_rossegger(tpc->green,tpc_z);
0372 twin->borrow_epartial_from(tpc,tpc_z);
0373
0374 tpc->set_twin(twin);
0375 }
0376
0377 return tpc;
0378 }
0379
0380
0381 AnnularFieldSim *SetupDigitalCurrentSphenixTpc(bool twinMe, bool useSpacecharge){
0382
0383 const float tpc_rmin=20.0;
0384 const float tpc_rmax=78.0;
0385 float tpc_deltar=tpc_rmax-tpc_rmin;
0386 const float tpc_z=105.5;
0387 const float tpc_cmVolt=-400*tpc_z;
0388
0389
0390 const float tpc_driftVel=8.0*1e6;
0391 const float tpc_magField=1.4;
0392 const char detgeoname[]="sphenix";
0393
0394
0395
0396
0397
0398
0399
0400 int nr=8;
0401 int nr_roi_min=0;
0402 int nr_roi=nr;
0403 int nr_roi_max=nr_roi_min+nr_roi;
0404 int nphi=3*12;
0405 int nphi_roi_min=0;
0406 int nphi_roi=nphi;
0407 int nphi_roi_max=nphi_roi_min+nphi_roi;
0408 int nz=40;
0409 int nz_roi_min=0;
0410 int nz_roi=nz;
0411 int nz_roi_max=nz_roi_min+nz_roi;
0412
0413 bool realB=true;
0414 bool realE=true;
0415
0416
0417
0418
0419
0420 AnnularFieldSim *tpc;
0421 if (useSpacecharge){
0422 tpc= new AnnularFieldSim(tpc_rmin,tpc_rmax,tpc_z,
0423 nr, nr_roi_min,nr_roi_max,1,2,
0424 nphi,nphi_roi_min, nphi_roi_max,1,2,
0425 nz, nz_roi_min, nz_roi_max,1,2,
0426 tpc_driftVel, AnnularFieldSim::PhiSlice, AnnularFieldSim::FromFile);
0427 }else{
0428 tpc= new AnnularFieldSim(tpc_rmin,tpc_rmax,tpc_z,
0429 nr, nr_roi_min,nr_roi_max,1,2,
0430 nphi,nphi_roi_min, nphi_roi_max,1,2,
0431 nz, nz_roi_min, nz_roi_max,1,2,
0432 tpc_driftVel, AnnularFieldSim::PhiSlice, AnnularFieldSim::NoSpacecharge);
0433 }
0434
0435 tpc->UpdateEveryN(10);
0436
0437
0438 tpc->setFlatFields(tpc_magField,tpc_cmVolt/tpc_z);
0439 sprintf(field_string,"flat_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
0440
0441 if (realE){
0442 tpc->loadEfield("externalEfield.ttree.root","fTree");
0443 sprintf(field_string,"realE_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
0444 }
0445 if (realB){
0446 tpc->load3dBfield("sphenix3dmaprhophiz.root","fieldmap",1,-1.4/1.5);
0447
0448 sprintf(field_string,"realB_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
0449 }
0450 if (realE && realB){
0451 sprintf(field_string,"real_B%2.1f_E%2.1f",tpc_magField,tpc_cmVolt/tpc_z);
0452 }
0453 printf("set fields.\n");
0454
0455
0456
0457
0458
0459 sprintf(lookup_string,"ross_phi1_%s_phislice_lookup_r%dxp%dxz%d",detgeoname,nr,nphi,nz);
0460 char lookupFilename[200];
0461 sprintf(lookupFilename,"%s.root",lookup_string);
0462 TFile *fileptr=TFile::Open(lookupFilename,"READ");
0463
0464 if (!fileptr){
0465
0466 tpc->load_rossegger();
0467 printf("loaded rossegger greens functions.\n");
0468 tpc->populate_lookup();
0469 tpc->save_phislice_lookup(lookupFilename);
0470 } else{
0471 fileptr->Close();
0472 tpc->load_phislice_lookup(lookupFilename);
0473 }
0474
0475 printf("populated lookup.\n");
0476
0477
0478
0479
0480
0481
0482
0483
0484 if(twinMe){
0485 AnnularFieldSim *twin;
0486 if (useSpacecharge){
0487 twin= new AnnularFieldSim(tpc_rmin,tpc_rmax,-tpc_z,
0488 nr, nr_roi_min,nr_roi_max,1,2,
0489 nphi,nphi_roi_min, nphi_roi_max,1,2,
0490 nz, nz_roi_min, nz_roi_max,1,2,
0491 tpc_driftVel, AnnularFieldSim::PhiSlice, AnnularFieldSim::FromFile);
0492 } else{
0493 twin= new AnnularFieldSim(tpc_rmin,tpc_rmax,-tpc_z,
0494 nr, nr_roi_min,nr_roi_max,1,2,
0495 nphi,nphi_roi_min, nphi_roi_max,1,2,
0496 nz, nz_roi_min, nz_roi_max,1,2,
0497 tpc_driftVel, AnnularFieldSim::PhiSlice, AnnularFieldSim::NoSpacecharge);
0498 } twin->UpdateEveryN(10);
0499
0500
0501 twin->setFlatFields(tpc_magField,-tpc_cmVolt/tpc_z);
0502
0503
0504 twin->load3dBfield("sphenix3dmaprhophiz.root","fieldmap",1,-1.4/1.5);
0505 twin->loadEfield("externalEfield.ttree.root","fTree",-1);
0506
0507
0508
0509
0510
0511 twin->borrow_rossegger(tpc->green,tpc_z);
0512 twin->borrow_epartial_from(tpc,tpc_z);
0513
0514 tpc->set_twin(twin);
0515 }
0516
0517 return tpc;
0518 }
0519
0520 void SurveyFiles(TFileCollection *filelist){
0521 TFile *infile;
0522
0523 TString sourcefilename;
0524 TString outputfilename;
0525
0526 float integral_sum=0;
0527 int nhists=0;
0528 for (int i=0;i<filelist->GetNFiles();i++){
0529
0530 sourcefilename=((TFileInfo*)(filelist->GetList()->At(i)))->GetCurrentUrl()->GetFile();
0531 printf("file %d: %s\n", i, sourcefilename.Data());
0532 infile=TFile::Open(sourcefilename.Data(),"READ");
0533 TList *keys=infile->GetListOfKeys();
0534
0535 int nKeys=infile->GetNkeys();
0536
0537 for (int j=0;j<nKeys;j++){
0538 TObject *tobj=infile->Get(keys->At(j)->GetName());
0539
0540 bool isHist=tobj->InheritsFrom("TH3");
0541 if (!isHist) continue;
0542 TString objname=tobj->GetName();
0543 printf(" hist %s ",objname.Data());
0544 if (objname.Contains("IBF")) {
0545 printf(" is IBF only.\n");
0546 continue;
0547 }
0548 float integral=((TH3D*)tobj)->Integral();
0549 integral_sum+=integral;
0550 nhists+=1;
0551 printf(" will be used. Total Q=%3.3E (ave=%3.3E)\n",integral,integral_sum/nhists);
0552
0553
0554
0555
0556
0557 }
0558 infile->Close();
0559 }
0560 return;
0561 }