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