File indexing completed on 2025-08-06 08:17:57
0001 #include "PHField2D.h"
0002
0003
0004 #include <TDirectory.h>
0005 #include <TFile.h>
0006 #include <TNtuple.h>
0007 #include <TSystem.h>
0008
0009 #include <Geant4/G4SystemOfUnits.hh>
0010
0011 #include <algorithm>
0012 #include <cmath>
0013 #include <cstdlib>
0014 #include <iostream>
0015 #include <iterator>
0016 #include <set>
0017 #include <utility>
0018
0019 PHField2D::PHField2D(const std::string &filename, const int verb, const float magfield_rescale)
0020 : PHField(verb)
0021 , r_index0_cache(0)
0022 , r_index1_cache(0)
0023 , z_index0_cache(0)
0024 , z_index1_cache(0)
0025 {
0026 if (Verbosity() > 0)
0027 {
0028 std::cout << " ------------- PHField2D::PHField2D() ------------------" << std::endl;
0029 }
0030
0031 TFile *rootinput = TFile::Open(filename.c_str());
0032 if (!rootinput)
0033 {
0034 std::cout << " could not open " << filename << " exiting now" << std::endl;
0035 gSystem->Exit(1);
0036 exit(1);
0037 }
0038 if (Verbosity() > 0)
0039 {
0040 std::cout << " Field grid file: " << filename << std::endl;
0041 }
0042 rootinput->cd();
0043
0044 Float_t ROOT_Z, ROOT_R;
0045 Float_t ROOT_BZ, ROOT_BR;
0046
0047 TNtuple *field_map = (TNtuple *) gDirectory->Get("fieldmap");
0048 if (field_map)
0049 {
0050 magfield_unit = tesla;
0051 }
0052 else
0053 {
0054 field_map = (TNtuple *) gDirectory->Get("map");
0055 if (!field_map)
0056 {
0057 std::cout << "PHField2D: could not locate ntuple of name map or fieldmap, exiting now" << std::endl;
0058 exit(1);
0059 }
0060 magfield_unit = gauss;
0061 }
0062 field_map->SetBranchAddress("z", &ROOT_Z);
0063 field_map->SetBranchAddress("r", &ROOT_R);
0064 field_map->SetBranchAddress("bz", &ROOT_BZ);
0065 field_map->SetBranchAddress("br", &ROOT_BR);
0066
0067
0068 int nz, nr;
0069 nz = field_map->GetEntries("z>-1e6");
0070 nr = field_map->GetEntries("r>-1e6");
0071 static const int NENTRIES = field_map->GetEntries();
0072
0073
0074 if (Verbosity() > 0)
0075 {
0076 std::cout << " The field grid contained " << NENTRIES << " entries" << std::endl;
0077 }
0078 if (Verbosity() > 1)
0079 {
0080 std::cout << "\n NENTRIES should be the same as the following values:"
0081 << "\n [ Number of values r,z: "
0082 << nr << " " << nz << " ]! " << std::endl;
0083 }
0084
0085 if (nz != nr)
0086 {
0087 std::cout << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
0088 << "\n The file you entered is not a \"table\" of values"
0089 << "\n Something very likely went oh so wrong"
0090 << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
0091 }
0092
0093
0094 std::set<float> z_set, r_set;
0095
0096
0097
0098
0099
0100
0101 if (Verbosity() > 1)
0102 {
0103 std::cout << " --> Sorting Entries..." << std::endl;
0104 }
0105 std::map<trio, trio> sorted_map;
0106 for (int i = 0; i < field_map->GetEntries(); i++)
0107 {
0108 field_map->GetEntry(i);
0109 trio coord_key(ROOT_Z, ROOT_R);
0110 trio field_val(ROOT_BZ, ROOT_BR);
0111 sorted_map[coord_key] = field_val;
0112
0113 z_set.insert(ROOT_Z * cm);
0114 r_set.insert(ROOT_R * cm);
0115 }
0116
0117
0118 if (Verbosity() > 4)
0119 {
0120 std::map<trio, trio>::iterator it = sorted_map.begin();
0121 print_map(it);
0122 float last_z = std::get<0>(it->first);
0123 for (it = sorted_map.begin(); it != sorted_map.end(); ++it)
0124 {
0125 if (std::get<0>(it->first) != last_z)
0126 {
0127 last_z = std::get<0>(it->first);
0128 print_map(it);
0129 }
0130 }
0131 }
0132
0133 if (Verbosity() > 1)
0134 {
0135 std::cout << " --> Putting entries into containers... " << std::endl;
0136 }
0137
0138
0139 minz_ = *(z_set.begin());
0140 std::set<float>::iterator ziter = z_set.end();
0141 --ziter;
0142 maxz_ = *ziter;
0143
0144
0145 nz = z_set.size();
0146 nr = r_set.size();
0147 r_map_.resize(nr, 0);
0148 z_map_.resize(nz, 0);
0149
0150 std::copy(z_set.begin(), z_set.end(), z_map_.begin());
0151 std::copy(r_set.begin(), r_set.end(), r_map_.begin());
0152
0153
0154 BFieldR_.resize(nz, std::vector<float>(nr, 0));
0155 BFieldZ_.resize(nz, std::vector<float>(nr, 0));
0156
0157
0158 unsigned int ir = 0, iz = 0;
0159 std::map<trio, trio>::iterator iter = sorted_map.begin();
0160 for (; iter != sorted_map.end(); ++iter)
0161 {
0162
0163 float z = std::get<0>(iter->first) * cm;
0164 float r = std::get<1>(iter->first) * cm;
0165 float Bz = std::get<0>(iter->second) * magfield_unit;
0166 float Br = std::get<1>(iter->second) * magfield_unit;
0167
0168 if (z > maxz_)
0169 {
0170 maxz_ = z;
0171 }
0172 if (z < minz_)
0173 {
0174 minz_ = z;
0175 }
0176
0177
0178 if (z != z_map_[iz])
0179 {
0180 ++iz;
0181 ir = 0;
0182 }
0183 else if (r != r_map_[ir])
0184 {
0185 ++ir;
0186 }
0187
0188
0189 if (iz > 0 && z < z_map_[iz - 1])
0190 {
0191 std::cout << "!!!!!!!!! Your map isn't ordered.... z: " << z << " zprev: " << z_map_[iz - 1] << std::endl;
0192 }
0193
0194 BFieldR_[iz][ir] = Br * magfield_rescale;
0195 BFieldZ_[iz][ir] = Bz * magfield_rescale;
0196
0197
0198
0199
0200 if (std::fabs(z) < 10 && ir < 10 && Verbosity() > 3)
0201 {
0202 print_map(iter);
0203
0204 std::cout << " B("
0205 << r_map_[ir] << ", "
0206 << z_map_[iz] << "): ("
0207 << BFieldR_[iz][ir] << ", "
0208 << BFieldZ_[iz][ir] << ")" << std::endl;
0209 }
0210
0211 }
0212
0213 rootinput->Close();
0214
0215 if (Verbosity() > 0)
0216 {
0217 std::cout << " Mag field z boundaries (min,max): (" << minz_ / cm << ", " << maxz_ / cm << ") cm" << std::endl;
0218 }
0219 if (Verbosity() > 0)
0220 {
0221 std::cout << " Mag field r max boundary: " << r_map_.back() / cm << " cm" << std::endl;
0222 }
0223
0224 if (Verbosity() > 0)
0225 {
0226 std::cout << " -----------------------------------------------------------" << std::endl;
0227 }
0228 }
0229
0230 void PHField2D::GetFieldValue(const double point[4], double *Bfield) const
0231 {
0232 if (Verbosity() > 2)
0233 {
0234 std::cout << "\nPHField2D::GetFieldValue" << std::endl;
0235 }
0236 double x = point[0];
0237 double y = point[1];
0238 double z = point[2];
0239 double r = sqrt(x * x + y * y);
0240 double phi;
0241 phi = atan2(y, x);
0242 if (phi < 0)
0243 {
0244 phi += 2 * M_PI;
0245 }
0246
0247
0248 if ((z >= minz_) && (z <= maxz_))
0249 {
0250 double BFieldCyl[3];
0251 double cylpoint[4] = {z, r, phi, 0};
0252
0253
0254 GetFieldCyl(cylpoint, BFieldCyl);
0255
0256
0257 Bfield[0] = cos(phi) * BFieldCyl[1] - sin(phi) * BFieldCyl[2];
0258
0259
0260 Bfield[1] = sin(phi) * BFieldCyl[1] + cos(phi) * BFieldCyl[2];
0261
0262
0263 Bfield[2] = BFieldCyl[0];
0264 }
0265 else
0266 {
0267 Bfield[0] = 0.0;
0268 Bfield[1] = 0.0;
0269 Bfield[2] = 0.0;
0270 if (Verbosity() > 2)
0271 {
0272 std::cout << "!!!!!!!!!! Field point not in defined region (outside of z bounds)" << std::endl;
0273 }
0274 }
0275
0276 if (Verbosity() > 2)
0277 {
0278 std::cout << "END PHField2D::GetFieldValue\n"
0279 << " ---> {Bx, By, Bz} : "
0280 << "< " << Bfield[0] << ", " << Bfield[1] << ", " << Bfield[2] << " >" << std::endl;
0281 }
0282
0283 return;
0284 }
0285
0286 void PHField2D::GetFieldValue_nocache(const double point[4], double *Bfield) const
0287 {
0288 if (Verbosity() > 2)
0289 {
0290 std::cout << "\nPHField2D::GetFieldValue" << std::endl;
0291 }
0292 double x = point[0];
0293 double y = point[1];
0294 double z = point[2];
0295 double r = sqrt(x * x + y * y);
0296 double phi;
0297 phi = atan2(y, x);
0298 if (phi < 0)
0299 {
0300 phi += 2 * M_PI;
0301 }
0302
0303
0304 if ((z >= minz_) && (z <= maxz_))
0305 {
0306 double BFieldCyl[3];
0307 double cylpoint[4] = {z, r, phi, 0};
0308
0309
0310 GetFieldCyl_nocache(cylpoint, BFieldCyl);
0311
0312
0313 Bfield[0] = cos(phi) * BFieldCyl[1] - sin(phi) * BFieldCyl[2];
0314
0315
0316 Bfield[1] = sin(phi) * BFieldCyl[1] + cos(phi) * BFieldCyl[2];
0317
0318
0319 Bfield[2] = BFieldCyl[0];
0320 }
0321 else
0322 {
0323 Bfield[0] = 0.0;
0324 Bfield[1] = 0.0;
0325 Bfield[2] = 0.0;
0326 if (Verbosity() > 2)
0327 {
0328 std::cout << "!!!!!!!!!! Field point not in defined region (outside of z bounds)" << std::endl;
0329 }
0330 }
0331
0332 if (Verbosity() > 2)
0333 {
0334 std::cout << "END PHField2D::GetFieldValue\n"
0335 << " ---> {Bx, By, Bz} : "
0336 << "< " << Bfield[0] << ", " << Bfield[1] << ", " << Bfield[2] << " >" << std::endl;
0337 }
0338
0339 return;
0340 }
0341
0342 void PHField2D::GetFieldCyl(const double CylPoint[4], double *BfieldCyl) const
0343 {
0344 float z = CylPoint[0];
0345 float r = CylPoint[1];
0346
0347 BfieldCyl[0] = 0.0;
0348 BfieldCyl[1] = 0.0;
0349 BfieldCyl[2] = 0.0;
0350
0351 if (Verbosity() > 2)
0352 {
0353 std::cout << "GetFieldCyl@ <z,r>: {" << z << "," << r << "}" << std::endl;
0354 }
0355
0356 if (z < z_map_[0] || z > z_map_[z_map_.size() - 1])
0357 {
0358 if (Verbosity() > 2)
0359 {
0360 std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl;
0361 }
0362 return;
0363 }
0364
0365
0366
0367
0368 unsigned int r_index0 = r_index0_cache;
0369 unsigned int r_index1 = r_index1_cache;
0370
0371 if (!((r > r_map_[r_index0]) && (r < r_map_[r_index1])))
0372 {
0373
0374 std::vector<float>::const_iterator riter = upper_bound(r_map_.begin(), r_map_.end(), r);
0375 r_index0 = distance(r_map_.begin(), riter) - 1;
0376 if (r_index0 >= r_map_.size())
0377 {
0378 if (Verbosity() > 2)
0379 {
0380 std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl;
0381 }
0382 return;
0383 }
0384
0385 r_index1 = r_index0 + 1;
0386 if (r_index1 >= r_map_.size())
0387 {
0388 if (Verbosity() > 2)
0389 {
0390 std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl;
0391 }
0392 return;
0393 }
0394
0395
0396 r_index0_cache = r_index0;
0397 r_index1_cache = r_index1;
0398 }
0399
0400 unsigned int z_index0 = z_index0_cache;
0401 unsigned int z_index1 = z_index1_cache;
0402
0403 if (!((z > z_map_[z_index0]) && (z < z_map_[z_index1])))
0404 {
0405
0406 std::vector<float>::const_iterator ziter = upper_bound(z_map_.begin(), z_map_.end(), z);
0407 z_index0 = distance(z_map_.begin(), ziter) - 1;
0408 z_index1 = z_index0 + 1;
0409 if (z_index1 >= z_map_.size())
0410 {
0411 if (Verbosity() > 2)
0412 {
0413 std::cout << "!!!! Point not in defined region (z too large in specific r-plane)" << std::endl;
0414 }
0415 return;
0416 }
0417
0418
0419 z_index0_cache = z_index0;
0420 z_index1_cache = z_index1;
0421 }
0422
0423 double Br000 = BFieldR_[z_index0][r_index0];
0424 double Br010 = BFieldR_[z_index0][r_index1];
0425 double Br100 = BFieldR_[z_index1][r_index0];
0426 double Br110 = BFieldR_[z_index1][r_index1];
0427
0428 double Bz000 = BFieldZ_[z_index0][r_index0];
0429 double Bz100 = BFieldZ_[z_index1][r_index0];
0430 double Bz010 = BFieldZ_[z_index0][r_index1];
0431 double Bz110 = BFieldZ_[z_index1][r_index1];
0432
0433 double zweight = z - z_map_[z_index0];
0434 double zspacing = z_map_[z_index1] - z_map_[z_index0];
0435 zweight /= zspacing;
0436
0437 double rweight = r - r_map_[r_index0];
0438 double rspacing = r_map_[r_index1] - r_map_[r_index0];
0439 rweight /= rspacing;
0440
0441
0442 BfieldCyl[0] =
0443 (1 - zweight) * ((1 - rweight) * Bz000 +
0444 rweight * Bz010) +
0445 zweight * ((1 - rweight) * Bz100 +
0446 rweight * Bz110);
0447
0448
0449 BfieldCyl[1] =
0450 (1 - zweight) * ((1 - rweight) * Br000 +
0451 rweight * Br010) +
0452 zweight * ((1 - rweight) * Br100 +
0453 rweight * Br110);
0454
0455
0456 BfieldCyl[2] = 0;
0457
0458 if (Verbosity() > 2)
0459 {
0460 std::cout << "End GFCyl Call: <bz,br,bphi> : {"
0461 << BfieldCyl[0] / gauss << "," << BfieldCyl[1] / gauss << "," << BfieldCyl[2] / gauss << "}"
0462 << std::endl;
0463 }
0464
0465 return;
0466 }
0467
0468
0469 void PHField2D::GetFieldCyl_nocache(const double CylPoint[4], double *BfieldCyl) const
0470 {
0471 float z = CylPoint[0];
0472 float r = CylPoint[1];
0473
0474 BfieldCyl[0] = 0.0;
0475 BfieldCyl[1] = 0.0;
0476 BfieldCyl[2] = 0.0;
0477
0478 if (Verbosity() > 2)
0479 {
0480 std::cout << "GetFieldCyl@ <z,r>: {" << z << "," << r << "}" << std::endl;
0481 }
0482
0483 if (z < z_map_[0] || z > z_map_[z_map_.size() - 1])
0484 {
0485 if (Verbosity() > 2)
0486 {
0487 std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl;
0488 }
0489 return;
0490 }
0491
0492
0493
0494
0495
0496
0497 std::vector<float>::const_iterator riter = upper_bound(r_map_.begin(), r_map_.end(), r);
0498 const unsigned int r_index0 = distance(r_map_.begin(), riter) - 1;
0499 if (r_index0 >= r_map_.size())
0500 {
0501 if (Verbosity() > 2)
0502 {
0503 std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl;
0504 }
0505 return;
0506 }
0507
0508 const unsigned int r_index1 = r_index0 + 1;
0509 if (r_index1 >= r_map_.size())
0510 {
0511 if (Verbosity() > 2)
0512 {
0513 std::cout << "!!!! Point not in defined region (radius too large in specific z-plane)" << std::endl;
0514 }
0515 return;
0516 }
0517
0518
0519 std::vector<float>::const_iterator ziter = upper_bound(z_map_.begin(), z_map_.end(), z);
0520 const unsigned int z_index0 = distance(z_map_.begin(), ziter) - 1;
0521 const unsigned int z_index1 = z_index0 + 1;
0522 if (z_index1 >= z_map_.size())
0523 {
0524 if (Verbosity() > 2)
0525 {
0526 std::cout << "!!!! Point not in defined region (z too large in specific r-plane)" << std::endl;
0527 }
0528 return;
0529 }
0530
0531 double Br000 = BFieldR_[z_index0][r_index0];
0532 double Br010 = BFieldR_[z_index0][r_index1];
0533 double Br100 = BFieldR_[z_index1][r_index0];
0534 double Br110 = BFieldR_[z_index1][r_index1];
0535
0536 double Bz000 = BFieldZ_[z_index0][r_index0];
0537 double Bz100 = BFieldZ_[z_index1][r_index0];
0538 double Bz010 = BFieldZ_[z_index0][r_index1];
0539 double Bz110 = BFieldZ_[z_index1][r_index1];
0540
0541 double zweight = z - z_map_[z_index0];
0542 double zspacing = z_map_[z_index1] - z_map_[z_index0];
0543 zweight /= zspacing;
0544
0545 double rweight = r - r_map_[r_index0];
0546 double rspacing = r_map_[r_index1] - r_map_[r_index0];
0547 rweight /= rspacing;
0548
0549
0550 BfieldCyl[0] =
0551 (1 - zweight) * ((1 - rweight) * Bz000 +
0552 rweight * Bz010) +
0553 zweight * ((1 - rweight) * Bz100 +
0554 rweight * Bz110);
0555
0556
0557 BfieldCyl[1] =
0558 (1 - zweight) * ((1 - rweight) * Br000 +
0559 rweight * Br010) +
0560 zweight * ((1 - rweight) * Br100 +
0561 rweight * Br110);
0562
0563
0564 BfieldCyl[2] = 0;
0565
0566 if (Verbosity() > 2)
0567 {
0568 std::cout << "End GFCyl Call: <bz,br,bphi> : {"
0569 << BfieldCyl[0] / gauss << "," << BfieldCyl[1] / gauss << "," << BfieldCyl[2] / gauss << "}"
0570 << std::endl;
0571 }
0572
0573 return;
0574 }
0575
0576
0577 void PHField2D::print_map(std::map<trio, trio>::iterator &it) const
0578 {
0579 std::cout << " Key: <"
0580 << std::get<0>(it->first) / cm << ","
0581 << std::get<1>(it->first) / cm << ">"
0582
0583 << " Value: <"
0584 << std::get<0>(it->second) / magfield_unit << ","
0585 << std::get<1>(it->second) / magfield_unit << ">" << std::endl;
0586 }