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