File indexing completed on 2025-08-05 08:15:39
0001 #include "AnnularFieldSim.h"
0002
0003 #include "AnalyticFieldModel.h"
0004 #include "ChargeMapReader.h"
0005 #include "MultiArray.h" //for TH3 alternative
0006 #include "Rossegger.h"
0007
0008 #include <TCanvas.h>
0009 #include <TFile.h>
0010 #include <TH1.h>
0011 #include <TH2.h>
0012 #include <TH3.h>
0013 #include <TLatex.h>
0014 #include <TPad.h>
0015 #include <TStyle.h>
0016 #include <TTree.h>
0017 #include <TVector3.h>
0018
0019 #include <boost/format.hpp>
0020
0021 #include <cassert> // for assert
0022 #include <cmath>
0023 #include <cstdint>
0024 #include <cstdlib>
0025 #include <iostream>
0026
0027 #define ALMOST_ZERO 0.00001
0028
0029 AnnularFieldSim::AnnularFieldSim(float in_innerRadius, float in_outerRadius, float in_outerZ,
0030 int r, int roi_r0, int roi_r1, int , int ,
0031 int phi, int roi_phi0, int roi_phi1, int , int ,
0032 int z, int roi_z0, int roi_z1, int , int ,
0033 float vdr, LookupCase in_lookupCase, ChargeCase in_chargeCase)
0034 {
0035
0036 if (roi_r0 >= r || roi_r1 > r || roi_r0 >= roi_r1)
0037 {
0038 exit(1);
0039 }
0040 if (roi_phi0 >= phi || roi_phi1 > phi || roi_phi0 >= roi_phi1)
0041 {
0042 std::cout << "phi roi is out of range or spans the wrap-around. Please spare me that math." << std::endl;
0043 exit(1);
0044 }
0045 if (roi_z0 >= z || roi_z1 > z || roi_z0 >= roi_z1)
0046 {
0047 exit(1);
0048 }
0049
0050 hasTwin = false;
0051 green_shift = 0;
0052
0053 std::cout << boost::str(boost::format("AnnularFieldSim::AnnularFieldSim with (%dx%dx%d) grid") % r % phi % z) << std::endl;
0054 std::cout << boost::str(boost::format("units m=%1.2E, cm=%1.2E, mm=%1.2E, um=%1.2E,") % m % cm % mm % um) << std::endl;
0055 std::cout << boost::str(boost::format("units s=%1.2E, us=%1.2E, ns=%1.2E,") % s % us % ns) << std::endl;
0056 std::cout << boost::str(boost::format("units C=%1.2E, nC=%1.2E, fC=%1.2E, ") % C % nC % fC) << std::endl;
0057 std::cout << boost::str(boost::format("units Tesla=%1.2E, kGauss=%1.2E") % Tesla % kGauss) << std::endl;
0058
0059
0060
0061 debug_printActionEveryN = -1;
0062 debug_printCounter = 0;
0063 debug_distortionScale.SetXYZ(0, 0, 0);
0064 debug_npercent = 5;
0065
0066
0067
0068
0069
0070 Enominal = 400 * V / cm;
0071 Bnominal = 1.4 * Tesla;
0072 vdrift = vdr * cm / s;
0073 langevin_T1 = 1.0;
0074 langevin_T2 = 1.0;
0075 omegatau_nominal = -10 * (Bnominal / kGauss) * (vdrift / (cm / us)) / (Enominal / (V / cm));
0076
0077 rmin = in_innerRadius * cm;
0078 rmax = in_outerRadius * cm;
0079 zmin = 0;
0080 zmax = in_outerZ * cm;
0081 if (zmin > zmax)
0082 {
0083 zmin = zmax;
0084 zmax = 0;
0085 }
0086 zero_vector.SetXYZ(0, 0, 0);
0087
0088
0089 dim.SetXYZ(1, 0, 0);
0090 dim.SetPerp(rmax - rmin);
0091 dim.SetPhi(0);
0092 phispan = 2 * M_PI;
0093 dim.SetZ(zmax - zmin);
0094
0095
0096
0097
0098 green = nullptr;
0099
0100
0101 nr = r;
0102 nphi = phi;
0103 nz = z;
0104 std::cout << boost::str(boost::format("AnnularFieldSim::AnnularFieldSim set variables nr=%d, nphi=%d, nz=%d") % nr % nphi % nz) << std::endl;
0105
0106 truncation_length = -1;
0107
0108
0109
0110 step.SetXYZ(1, 0, 0);
0111 step.SetPerp(dim.Perp() / nr);
0112 step.SetPhi(phispan / nphi);
0113 step.SetZ(dim.Z() / nz);
0114 std::cout << boost::str(boost::format("f-bin size: r=%f,phi=%f, z=%f, wanted %f,%f") % step.Perp() % step.Phi() % ((rmax - rmin) / nr) % (phispan / nphi) % ((zmax - zmin) / nz)) << std::endl;
0115
0116
0117
0118
0119 q = new ChargeMapReader(nr, rmin, rmax, nphi, 0, phispan, nz, zmin, zmax);
0120 chargestring = "No spacecharge present.";
0121
0122
0123 rmin_roi = roi_r0;
0124 phimin_roi = roi_phi0;
0125 zmin_roi = roi_z0;
0126 rmax_roi = roi_r1;
0127 phimax_roi = roi_phi1;
0128 zmax_roi = roi_z1;
0129 std::cout << boost::str(boost::format("AnnularFieldSim::AnnularFieldSim set roi variables rmin=%d phimin=%d zmin=%d rmax=%d phimax=%d zmax=%d") % rmin_roi % phimin_roi % zmin_roi % rmax_roi % phimax_roi % zmax_roi) << std::endl;
0130
0131 nr_roi = rmax_roi - rmin_roi;
0132 nphi_roi = phimax_roi - phimin_roi;
0133 nz_roi = zmax_roi - zmin_roi;
0134 std::cout << boost::str(boost::format("AnnularFieldSim::AnnularFieldSim calc'd roi variables nr=%d nphi=%d nz=%d") % nr_roi % nphi_roi % nz_roi) << std::endl;
0135
0136
0137 Efield = new MultiArray<TVector3>(nr_roi, nphi_roi, nz_roi);
0138 for (int i = 0; i < Efield->Length(); i++)
0139 {
0140 Efield->GetFlat(i)->SetXYZ(0, 0, 0);
0141 }
0142
0143
0144 Eexternal = new MultiArray<TVector3>(nr_roi, nphi_roi, nz_roi);
0145 for (int i = 0; i < Eexternal->Length(); i++)
0146 {
0147 Eexternal->GetFlat(i)->SetXYZ(0, 0, 0);
0148 }
0149
0150
0151 Bfield = new MultiArray<TVector3>(nr_roi, nphi_roi, nz_roi);
0152 for (int i = 0; i < Bfield->Length(); i++)
0153 {
0154 Bfield->GetFlat(i)->SetXYZ(0, 0, 0);
0155 }
0156
0157
0158 lookupCase = in_lookupCase;
0159 chargeCase = in_chargeCase;
0160 if (chargeCase == ChargeCase::NoSpacecharge)
0161 {
0162 lookupCase = LookupCase::NoLookup;
0163 }
0164
0165 if (lookupCase == Full3D)
0166 {
0167 std::cout << boost::str(boost::format("AnnularFieldSim::AnnularFieldSim building Epartial (full3D) with nr_roi=%d nphi_roi=%d nz_roi=%d =~%2.2fM TVector3 objects") % nr_roi % nphi_roi % nz_roi % (nr_roi * nphi_roi * nz_roi * nr * nphi * nz / (1.0e6))) << std::endl;
0168
0169 Epartial = new MultiArray<TVector3>(nr_roi, nphi_roi, nz_roi, nr, nphi, nz);
0170 for (int i = 0; i < Epartial->Length(); i++)
0171 {
0172 Epartial->GetFlat(i)->SetXYZ(0, 0, 0);
0173 }
0174
0175 Epartial_highres = new MultiArray<TVector3>(1);
0176 Epartial_highres->GetFlat(0)->SetXYZ(0, 0, 0);
0177
0178 Epartial_lowres = new MultiArray<TVector3>(1);
0179 Epartial_lowres->GetFlat(0)->SetXYZ(0, 0, 0);
0180
0181 Epartial_phislice = new MultiArray<TVector3>(1);
0182 Epartial_phislice->GetFlat(0)->SetXYZ(0, 0, 0);
0183 q_lowres = new MultiArray<double>(1);
0184 *(q_lowres->GetFlat(0)) = 0;
0185 q_local = new MultiArray<double>(1);
0186 *(q_local->GetFlat(0)) = 0;
0187 }
0188 else if (lookupCase == HybridRes)
0189 {
0190 std::cout << "lookupCase==HybridRes" << std::endl;
0191
0192 Epartial = new MultiArray<TVector3>(1);
0193 Epartial->GetFlat(0)->SetXYZ(0, 0, 0);
0194
0195 Epartial_phislice = new MultiArray<TVector3>(1);
0196 Epartial_phislice->GetFlat(0)->SetXYZ(0, 0, 0);
0197 }
0198 else if (lookupCase == PhiSlice)
0199 {
0200 std::cout << "lookupCase==PhiSlice" << std::endl;
0201
0202 Epartial_phislice = new MultiArray<TVector3>(nr_roi, 1, nz_roi, nr, nphi, nz);
0203 for (int i = 0; i < Epartial_phislice->Length(); i++)
0204 {
0205 Epartial_phislice->GetFlat(i)->SetXYZ(0, 0, 0);
0206 }
0207
0208 Epartial = new MultiArray<TVector3>(1);
0209 Epartial->GetFlat(0)->SetXYZ(0, 0, 0);
0210 Epartial_highres = new MultiArray<TVector3>(1);
0211 Epartial_highres->GetFlat(0)->SetXYZ(0, 0, 0);
0212
0213 Epartial_lowres = new MultiArray<TVector3>(1);
0214 Epartial_lowres->GetFlat(0)->SetXYZ(0, 0, 0);
0215
0216 q_lowres = new MultiArray<double>(1);
0217 *(q_lowres->GetFlat(0)) = 0;
0218 q_local = new MultiArray<double>(1);
0219 *(q_local->GetFlat(0)) = 0;
0220 }
0221 else if (lookupCase == Analytic || lookupCase == NoLookup)
0222 {
0223 std::cout << "lookupCase==Analytic (or NoLookup)" << std::endl;
0224
0225
0226 Epartial_phislice = new MultiArray<TVector3>(1);
0227 Epartial_phislice->GetFlat(0)->SetXYZ(0, 0, 0);
0228
0229 Epartial = new MultiArray<TVector3>(1);
0230 Epartial->GetFlat(0)->SetXYZ(0, 0, 0);
0231
0232 Epartial_highres = new MultiArray<TVector3>(1);
0233 Epartial_highres->GetFlat(0)->SetXYZ(0, 0, 0);
0234
0235 Epartial_lowres = new MultiArray<TVector3>(1);
0236 Epartial_lowres->GetFlat(0)->SetXYZ(0, 0, 0);
0237
0238 q_lowres = new MultiArray<double>(1);
0239 *(q_lowres->GetFlat(0)) = 0;
0240 q_local = new MultiArray<double>(1);
0241 *(q_local->GetFlat(0)) = 0;
0242 }
0243 else
0244 {
0245 std::cout << "Ran into wrong lookupCase logic in constructor." << std::endl;
0246 exit(1);
0247 }
0248
0249 return;
0250 }
0251 AnnularFieldSim::AnnularFieldSim(float in_innerRadius, float in_outerRadius, float in_outerZ,
0252 int r, int roi_r0, int roi_r1, int in_rLowSpacing, int in_rHighSize,
0253 int phi, int roi_phi0, int roi_phi1, int in_phiLowSpacing, int in_phiHighSize,
0254 int z, int roi_z0, int roi_z1, int in_zLowSpacing, int in_zHighSize,
0255 float vdr, LookupCase in_lookupCase)
0256 : AnnularFieldSim(in_innerRadius, in_outerRadius, in_outerZ,
0257 r, roi_r0, roi_r1, in_rLowSpacing, in_rHighSize,
0258 phi, roi_phi0, roi_phi1, in_phiLowSpacing, in_phiHighSize,
0259 z, roi_z0, roi_z1, in_zLowSpacing, in_zHighSize,
0260 vdr, in_lookupCase, ChargeCase::FromFile)
0261 {
0262 std::cout << "AnnularFieldSim::OldConstructor building AnnularFieldSim with ChargeCase::FromFile" << std::endl;
0263 return;
0264 }
0265 AnnularFieldSim::AnnularFieldSim(float in_innerRadius, float in_outerRadius, float in_outerZ,
0266 int r, int roi_r0, int roi_r1,
0267 int phi, int roi_phi0, int roi_phi1,
0268 int z, int roi_z0, int roi_z1,
0269 float vdr, LookupCase in_lookupCase)
0270 : AnnularFieldSim(in_innerRadius, in_outerRadius, in_outerZ,
0271 r, roi_r0, roi_r1, 1, 3,
0272 phi, roi_phi0, roi_phi1, 1, 3,
0273 z, roi_z0, roi_z1, 1, 3,
0274 vdr, in_lookupCase, ChargeCase::FromFile)
0275 {
0276
0277
0278 std::cout << "AnnularFieldSim::OldConstructor building AnnularFieldSim with local_size=1 in all dimensions, lowres_spacing=1 in all dimensions" << std::endl;
0279 return;
0280 }
0281 AnnularFieldSim::AnnularFieldSim(float rin, float rout, float dz, int r, int phi, int z, float vdr)
0282 : AnnularFieldSim(rin, rout, dz,
0283 r, 0, r,
0284 phi, 0, phi,
0285 z, 0, z,
0286 vdr, LookupCase::PhiSlice)
0287 {
0288
0289 std::cout << "AnnularFieldSim::OldConstructor building AnnularFieldSim with roi=full in all dimensions" << std::endl;
0290 return;
0291 }
0292
0293 TVector3 AnnularFieldSim::calc_unit_field(TVector3 at, TVector3 from)
0294 {
0295
0296 int r_position;
0297 if (GetRindexAndCheckBounds(at.Perp(), &r_position) != InBounds)
0298 {
0299 std::cout << boost::str(boost::format("something's asking for 'at' with r=%f, which is index=%d") % at.Perp() % r_position) << std::endl;
0300 exit(1);
0301 }
0302
0303
0304
0305
0306
0307 TVector3 field(0, 0, 0);
0308
0309
0310
0311
0312 if (green == nullptr)
0313 {
0314 TVector3 delr = at - from;
0315 field = delr;
0316 if (delr.Mag() < ALMOST_ZERO * ALMOST_ZERO)
0317 {
0318
0319
0320 }
0321 else
0322 {
0323 field.SetMag(k_perm * 1 / (delr * delr));
0324 }
0325
0326 }
0327 else
0328 {
0329 double atphi = FilterPhiPos(at.Phi());
0330 double fromphi = FilterPhiPos(from.Phi());
0331 double delphi = std::abs(at.DeltaPhi(from));
0332
0333 at.SetZ(at.Z() + green_shift);
0334 from.SetZ(from.Z() + green_shift);
0335 double Er = green->Er(at.Perp(), atphi, at.Z(), from.Perp(), fromphi, from.Z());
0336
0337 double Ephi = 0;
0338 if (delphi > ALMOST_ZERO)
0339 {
0340 Ephi = green->Ephi(at.Perp(), atphi, at.Z(), from.Perp(), fromphi, from.Z());
0341 }
0342 double Ez = green->Ez(at.Perp(), atphi, at.Z(), from.Perp(), fromphi, from.Z());
0343 field.SetXYZ(-Er, -Ephi, -Ez);
0344 field = field * epsinv;
0345 field.RotateZ(at.Phi());
0346
0347 }
0348 return field;
0349 }
0350
0351
0352
0353 TVector3 AnnularFieldSim::GetLocalFieldComponents(const TVector3 &field, const TVector3 &pos, const TVector3 &origin)
0354 {
0355
0356
0357
0358
0359
0360 TVector3 local_pos = pos - origin;
0361
0362 TVector3 radial_vector = local_pos;
0363 radial_vector.SetZ(0);
0364 if(radial_vector.Mag()==0){
0365
0366 radial_vector.SetXYZ(1, 0, 0);
0367 }else {
0368 radial_vector.SetMag(1);
0369 }
0370
0371 TVector3 azimuthal_vector = radial_vector;
0372 azimuthal_vector.SetXYZ(-radial_vector.Y(), radial_vector.X(), 0);
0373
0374 TVector3 local_field;
0375 local_field.SetXYZ(field.Dot(radial_vector), field.Dot(azimuthal_vector), field.Z());
0376 return local_field;
0377 }
0378
0379
0380 double AnnularFieldSim::FilterPhiPos(double phi)
0381 {
0382
0383
0384 double p = phi;
0385 if (p >= 2 * M_PI)
0386 {
0387 p -= 2 * M_PI;
0388 }
0389 if (p < 0)
0390 {
0391 p += 2 * M_PI;
0392 }
0393 if (p >= 2 * M_PI || p < 0)
0394 {
0395 std::cout << boost::str(boost::format("AnnularFieldSim::FilterPhiPos asked to filter %f, which is more than range=%f out of bounds. Check what called this.") % phi % (2 * M_PI)) << std::endl;
0396 exit(1);
0397 }
0398 return p;
0399 }
0400 int AnnularFieldSim::FilterPhiIndex(int phi, int range = -1)
0401 {
0402 if (range < 0)
0403 {
0404 range = nphi;
0405 }
0406
0407
0408 int p = phi;
0409 if (p >= range)
0410 {
0411 p -= range;
0412 }
0413 if (p < 0)
0414 {
0415 p += range;
0416 }
0417 if (p >= range || p < 0)
0418 {
0419 std::cout << boost::str(boost::format("AnnularFieldSim::FilterPhiIndex asked to filter %d, which is more than range=%d out of bounds. Check what called this.") % phi % range) << std::endl;
0420 exit(1);
0421 }
0422 return p;
0423 }
0424
0425 int AnnularFieldSim::GetRindex(float pos)
0426 {
0427 float r0f = (pos - rmin) / step.Perp();
0428 int r0 = std::floor(r0f);
0429 return r0;
0430 }
0431
0432 int AnnularFieldSim::GetPhiIndex(float pos)
0433 {
0434 float p0f = (pos) / step.Phi();
0435 int phitemp = std::floor(p0f);
0436 int p0 = FilterPhiIndex(phitemp);
0437 return p0;
0438 }
0439
0440 int AnnularFieldSim::GetZindex(float pos)
0441 {
0442 float z0f = (pos - zmin) / step.Z();
0443 int z0 = std::floor(z0f);
0444 return z0;
0445 }
0446
0447 AnnularFieldSim::BoundsCase AnnularFieldSim::GetRindexAndCheckBounds(float pos, int *r)
0448 {
0449
0450
0451 float r0f = (pos - rmin) / step.Perp();
0452 int r0 = std::floor(r0f);
0453 *r = r0;
0454
0455 int r0lowered_slightly = std::floor(r0f - ALMOST_ZERO);
0456 int r0raised_slightly = std::floor(r0f + ALMOST_ZERO);
0457 if (r0lowered_slightly >= rmax_roi || r0raised_slightly < rmin_roi)
0458 {
0459 return OutOfBounds;
0460 }
0461
0462
0463 if (r0 >= rmax_roi)
0464 {
0465 return OnHighEdge;
0466 }
0467 if (r0 < rmin_roi)
0468 {
0469 return OnLowEdge;
0470 }
0471
0472 return InBounds;
0473 }
0474 AnnularFieldSim::BoundsCase AnnularFieldSim::GetPhiIndexAndCheckBounds(float pos, int *phi)
0475 {
0476
0477 float p0f = (pos) / step.Phi();
0478 int phitemp = std::floor(p0f);
0479 int p0 = FilterPhiIndex(phitemp);
0480 *phi = p0;
0481
0482 phitemp = std::floor(p0f - ALMOST_ZERO);
0483 int p0lowered_slightly = FilterPhiIndex(phitemp);
0484 phitemp = std::floor(p0f + ALMOST_ZERO);
0485 int p0raised_slightly = FilterPhiIndex(phitemp);
0486
0487
0488
0489
0490
0491 if ((p0lowered_slightly >= phimax_roi && p0 != 0) || (p0raised_slightly < phimin_roi && p0 != (nphi - 1)))
0492 {
0493 return OutOfBounds;
0494 }
0495
0496 if (p0 >= phimax_roi)
0497 {
0498 return OnHighEdge;
0499 }
0500 if (p0 < phimin_roi)
0501 {
0502 return OnLowEdge;
0503 }
0504
0505 return InBounds;
0506 }
0507
0508 AnnularFieldSim::BoundsCase AnnularFieldSim::GetZindexAndCheckBounds(float pos, int *z)
0509 {
0510
0511 float z0f = (pos - zmin) / step.Z();
0512 int z0 = std::floor(z0f);
0513 *z = z0;
0514
0515 int z0lowered_slightly = std::floor(z0f - ALMOST_ZERO);
0516 int z0raised_slightly = std::floor(z0f + ALMOST_ZERO);
0517
0518 if (z0lowered_slightly >= zmax_roi || z0raised_slightly < zmin_roi)
0519 {
0520 return OutOfBounds;
0521 }
0522
0523 if (z0 >= zmax_roi)
0524 {
0525 return OnHighEdge;
0526 }
0527 if (z0 < zmin_roi)
0528 {
0529 return OnLowEdge;
0530 }
0531
0532 return InBounds;
0533 }
0534
0535 TVector3 AnnularFieldSim::analyticFieldIntegral(float zdest, TVector3 start, MultiArray<TVector3> *field)
0536 {
0537
0538
0539
0540
0541
0542
0543 int r, phi;
0544 bool rOkay = (GetRindexAndCheckBounds(start.Perp(), &r) == InBounds);
0545 bool phiOkay = (GetPhiIndexAndCheckBounds(FilterPhiPos(start.Phi()), &phi) == InBounds);
0546
0547
0548
0549
0550
0551
0552 if (!rOkay || !phiOkay)
0553 {
0554 std::cout << boost::str(boost::format("AnnularFieldSim::analyticFieldIntegral asked to integrate along (r=%f,phi=%f), index=(%d,%d), which is out of bounds. returning starting position.") % start.Perp() % start.Phi() % r % phi) << std::endl;
0555 return start;
0556 }
0557
0558 int dir = (start.Z() > zdest ? -1 : 1);
0559
0560 int zi, zf;
0561 double startz, endz;
0562 BoundsCase startBound, endBound;
0563
0564
0565 if (dir > 0)
0566 {
0567 startBound = GetZindexAndCheckBounds(start.Z(), &zi);
0568 endBound = GetZindexAndCheckBounds(zdest, &zf);
0569 startz = start.Z();
0570 endz = zdest;
0571 }
0572 else
0573 {
0574 endBound = GetZindexAndCheckBounds(start.Z(), &zf);
0575 startBound = GetZindexAndCheckBounds(zdest, &zi);
0576 startz = zdest;
0577 endz = start.Z();
0578 }
0579 bool startOkay = (startBound == InBounds);
0580 bool endOkay = (endBound == InBounds || endBound == OnHighEdge);
0581
0582 if (!startOkay || !endOkay)
0583 {
0584 std::cout << boost::str(boost::format("AnnularFieldSim::analyticFieldIntegral asked to integrate from z=%f to %f, index=%d to %d), which is out of bounds. returning starting position.") % startz % endz % zi % zf) << std::endl;
0585 return start;
0586 }
0587
0588 start.SetZ(startz);
0589 TVector3 integral;
0590 if (field == Efield)
0591 {
0592 integral = aliceModel->Eint(endz, start) + Eexternal->Get(r - rmin_roi, phi - phimin_roi, zi - zmin_roi) * (endz - startz);
0593 return dir * integral;
0594 }
0595 else if (field == Bfield)
0596 {
0597 return interpolatedFieldIntegral(zdest, start, Bfield);
0598 }
0599 return integral;
0600 }
0601
0602 TVector3 AnnularFieldSim::fieldIntegral(float zdest, const TVector3 &start, MultiArray<TVector3> *field)
0603 {
0604
0605
0606
0607 int r, phi;
0608 bool rOkay = (GetRindexAndCheckBounds(start.Perp(), &r) == InBounds);
0609 bool phiOkay = (GetPhiIndexAndCheckBounds(FilterPhiPos(start.Phi()), &phi) == InBounds);
0610
0611 if (!rOkay || !phiOkay)
0612 {
0613 std::cout << boost::str(boost::format("AnnularFieldSim::fieldIntegral asked to integrate along (r=%f,phi=%f), index=(%d,%d), which is out of bounds. returning starting position.") % start.Perp() % start.Phi() % r % phi) << std::endl;
0614 return start;
0615 }
0616
0617 int dir = (start.Z() > zdest ? -1 : 1);
0618
0619 int zi, zf;
0620 double startz, endz;
0621 BoundsCase startBound, endBound;
0622
0623
0624 if (dir > 0)
0625 {
0626 startBound = GetZindexAndCheckBounds(start.Z(), &zi);
0627 endBound = GetZindexAndCheckBounds(zdest, &zf);
0628 startz = start.Z();
0629 endz = zdest;
0630 }
0631 else
0632 {
0633 endBound = GetZindexAndCheckBounds(start.Z(), &zf);
0634 startBound = GetZindexAndCheckBounds(zdest, &zi);
0635 startz = zdest;
0636 endz = start.Z();
0637 }
0638 bool startOkay = (startBound == InBounds);
0639 bool endOkay = (endBound == InBounds || endBound == OnHighEdge);
0640
0641 if (!startOkay || !endOkay)
0642 {
0643 std::cout << boost::str(boost::format("AnnularFieldSim::fieldIntegral asked to integrate from z=%f to %f, index=%d to %d), which is out of bounds. returning starting position.") % startz % endz % zi % zf) << std::endl;
0644 return start;
0645 }
0646
0647 TVector3 fieldInt(0, 0, 0);
0648
0649 TVector3 tf;
0650 for (int i = zi; i < zf; i++)
0651 {
0652 tf = field->Get(r - rmin_roi, phi - phimin_roi, i - zmin_roi);
0653
0654 fieldInt += tf * step.Z();
0655 }
0656
0657
0658 fieldInt -= field->Get(r - rmin_roi, phi - phimin_roi, zi - zmin_roi) * (startz - zi * step.Z());
0659
0660
0661 if (endz / step.Z() - zf > ALMOST_ZERO)
0662 {
0663
0664
0665 fieldInt += field->Get(r - rmin_roi, phi - phimin_roi, zf - zmin_roi) * (endz - zf * step.Z());
0666 }
0667
0668 return dir * fieldInt;
0669 }
0670
0671 TVector3 AnnularFieldSim::GetCellCenter(int r, int phi, int z)
0672 {
0673
0674
0675 TVector3 c(1, 0, 0);
0676 c.SetPerp((r + 0.5) * step.Perp() + rmin);
0677 c.SetPhi((phi + 0.5) * step.Phi());
0678 c.SetZ((z + 0.5) * step.Z() + zmin);
0679
0680 return c;
0681 }
0682
0683 TVector3 AnnularFieldSim::GetRoiCellCenter(int r, int phi, int z)
0684 {
0685
0686
0687
0688 if (r > nr_roi || r < 0 || phi > nphi_roi || phi < 0 || z > nz_roi || z < 0)
0689 {
0690 return zero_vector;
0691 }
0692
0693 TVector3 c(1, 0, 0);
0694 c.SetPerp((r + rmin_roi + 0.5) * step.Perp() + rmin);
0695 c.SetPhi((phi + phimin_roi + 0.5) * step.Phi());
0696 c.SetZ((z + zmin_roi + 0.5) * step.Z() + zmin);
0697
0698 return c;
0699 }
0700
0701 TVector3 AnnularFieldSim::GetGroupCellCenter(int r0, int r1, int phi0, int phi1, int z0, int z1)
0702 {
0703
0704 float ravg = (r0 + r1) / 2.0 + 0.5;
0705 if (phi0 > phi1)
0706 {
0707 phi1 += nphi;
0708 }
0709 if (phi0 > phi1)
0710 {
0711 std::cout << boost::str(boost::format("phi1(%d)<=phi0(%d) even after boosting phi1. check what called this!") % phi1 % phi0) << std::endl;
0712 exit(1);
0713 }
0714 float phiavg = (r0 + r1) / 2.0 + 0.5;
0715 if (phiavg >= nphi)
0716 {
0717 phiavg -= nphi;
0718 }
0719
0720 float zavg = (z0 + z1) / 2.0 + 0.5;
0721
0722 TVector3 c(1, 0, 0);
0723 c.SetPerp((ravg) *step.Perp() + rmin);
0724 c.SetPhi((phiavg) *step.Phi());
0725 c.SetZ((zavg) *step.Z() + zmin);
0726
0727 return c;
0728 }
0729
0730 TVector3 AnnularFieldSim::GetWeightedCellCenter(int r, int phi, int z)
0731 {
0732
0733
0734 TVector3 c(1, 0, 0);
0735
0736 float rin = r * step.Perp() + rmin;
0737 float rout = rin + step.Perp();
0738
0739 float rMid = (4 * sin(step.Phi() / 2) * (pow(rout, 3) - pow(rin, 3)) / (3 * step.Phi() * (pow(rout, 2) - pow(rin, 2))));
0740 c.SetPerp(rMid);
0741 c.SetPhi((phi + 0.5) * step.Phi());
0742 c.SetZ((z + 0.5) * step.Z());
0743
0744 return c;
0745 }
0746
0747 TVector3 AnnularFieldSim::interpolatedFieldIntegral(float zdest, const TVector3 &start, MultiArray<TVector3> *field)
0748 {
0749
0750
0751 float r0 = (start.Perp() - rmin) / step.Perp() - 0.5;
0752 int r0i = std::floor(r0);
0753 float r0d = r0 - r0i;
0754 int ri[4];
0755 ri[0] = ri[1] = r0i;
0756 ri[2] = ri[3] = r0i + 1;
0757 float rw[4];
0758 rw[0] = rw[1] = 1 - r0d;
0759 rw[2] = rw[3] = r0d;
0760
0761 bool skip[] = {false, false, false, false};
0762 if (ri[0] < rmin_roi)
0763 {
0764 skip[0] = true;
0765 skip[1] = true;
0766 rw[2] = rw[3] = 1;
0767 }
0768 if (ri[2] >= rmax_roi)
0769 {
0770 skip[2] = true;
0771 skip[3] = true;
0772 rw[0] = rw[1] = 1;
0773 }
0774
0775
0776 float p0 = (start.Phi()) / step.Phi() - 0.5;
0777 int p0i = std::floor(p0);
0778 float p0d = p0 - p0i;
0779 int pi[4];
0780 pi[0] = pi[2] = FilterPhiIndex(p0i);
0781 pi[1] = pi[3] = FilterPhiIndex(p0i + 1);
0782 float pw[4];
0783 pw[0] = pw[2] = 1 - p0d;
0784 pw[1] = pw[3] = p0d;
0785
0786
0787 if (pi[0] < phimin_roi || pi[0] >= phimax_roi)
0788 {
0789 skip[0] = true;
0790 skip[2] = true;
0791 pw[1] = pw[3] = 1;
0792 }
0793 if (pi[1] >= phimax_roi || pi[1] < phimin_roi)
0794 {
0795 skip[1] = true;
0796 skip[3] = true;
0797 pw[0] = pw[2] = 1;
0798 }
0799
0800 int dir = (start.Z() < zdest ? 1 : -1);
0801
0802 int zi, zf;
0803 double startz, endz;
0804 BoundsCase startBound, endBound;
0805
0806
0807 if (dir > 0)
0808 {
0809 startBound = GetZindexAndCheckBounds(start.Z(), &zi);
0810 endBound = GetZindexAndCheckBounds(zdest, &zf);
0811 startz = start.Z();
0812 endz = zdest;
0813 }
0814 else
0815 {
0816 endBound = GetZindexAndCheckBounds(start.Z(), &zf);
0817 startBound = GetZindexAndCheckBounds(zdest, &zi);
0818 startz = zdest;
0819 endz = start.Z();
0820 }
0821 bool startOkay = (startBound == InBounds || startBound == OnLowEdge);
0822 bool endOkay = (endBound == InBounds || endBound == OnHighEdge);
0823
0824 if (!startOkay || !endOkay)
0825 {
0826 std::cout << boost::str(boost::format("AnnularFieldSim::InterpolatedFieldIntegral asked to integrate from z=%f to %f, index=%d to %d), which is out of bounds. returning zero") % startz % endz % zi % zf) << std::endl;
0827 return zero_vector;
0828 }
0829
0830 if (startBound == OnLowEdge)
0831 {
0832
0833 zi++;
0834 }
0835
0836 if (false)
0837 {
0838 bool isE = (field == Efield);
0839 bool isB = (field == Bfield);
0840 std::cout << boost::str(boost::format("interpFieldInt: isE=%d, isB=%d, start=(%2.4f,%2.4f,%2.4f) dest=%2.4f") % isE % isB % start.X() % start.Y() % start.Z() % zdest) << std::endl;
0841 std::cout << boost::str(boost::format("interpolating fieldInt for %s at r=%f,phi=%f") % ((field == Efield) ? "Efield" : "Bfield") % r0 % p0) << std::endl;
0842 std::cout << boost::str(boost::format("direction=%d, startz=%2.4f, endz=%2.4f, zi=%d, zf=%d") % dir % startz % endz % zi % zf) << std::endl;
0843 for (int i = 0; i < 4; i++)
0844 {
0845 std::cout << boost::str(boost::format("skip[%d]=%d\tw[i]=%2.2f, (pw=%2.2f, rw=%2.2f)") % i % skip[i] % (rw[i] * pw[i]) % pw[i] % rw[i]) << std::endl;
0846 }
0847 }
0848
0849 TVector3 fieldInt(0, 0, 0), partialInt;
0850
0851 for (int i = 0; i < 4; i++)
0852 {
0853 if (skip[i])
0854 {
0855
0856 continue;
0857 }
0858 partialInt.SetXYZ(0, 0, 0);
0859 for (int j = zi; j < zf; j++)
0860 {
0861
0862 partialInt += field->Get(ri[i] - rmin_roi, pi[i] - phimin_roi, j - zmin_roi) * step.Z();
0863 }
0864 if (startBound != OnLowEdge)
0865 {
0866 partialInt -= field->Get(ri[i] - rmin_roi, pi[i] - phimin_roi, zi - zmin_roi) * (startz - (zi * step.Z() + zmin));
0867
0868 }
0869 if ((endz - zmin) / step.Z() - zf > ALMOST_ZERO)
0870 {
0871 partialInt += field->Get(ri[i] - rmin_roi, pi[i] - phimin_roi, zf - zmin_roi) * (endz - (zf * step.Z() + zmin));
0872
0873 }
0874
0875
0876 fieldInt += rw[i] * pw[i] * partialInt;
0877 }
0878
0879 return dir * fieldInt;
0880 }
0881
0882 void AnnularFieldSim::load_analytic_spacecharge(float scalefactor = 1)
0883 {
0884
0885
0886
0887
0888
0889
0890
0891 double ifc_radius = 83.5 * cm;
0892 double ofc_radius = 254.5 * cm;
0893 double tpc_halfz = 250 * cm;
0894
0895 aliceModel = new AnalyticFieldModel(ifc_radius / cm, ofc_radius / cm, tpc_halfz / cm, scalefactor);
0896 double totalcharge = 0;
0897 double localcharge = 0;
0898
0899 TVector3 pos;
0900 for (int ifr = 0; ifr < nr; ifr++)
0901 {
0902 for (int ifphi = 0; ifphi < nphi; ifphi++)
0903 {
0904 for (int ifz = 0; ifz < nz; ifz++)
0905 {
0906 pos = GetCellCenter(ifr, ifphi, ifz);
0907 pos = pos * (1.0 / cm);
0908 double vol = step.Z() * step.Phi() * (2 * (ifr * step.Perp() + rmin) + step.Perp()) * step.Perp();
0909
0910 localcharge = vol * aliceModel->Rho(pos);
0911 totalcharge += localcharge;
0912
0913 q->AddChargeInBin(ifr, ifphi, ifz, localcharge);
0914 }
0915 }
0916 }
0917 std::cout << boost::str(boost::format("AnnularFieldSim::load_analytic_spacecharge: Total charge Q=%E Coulombs") % totalcharge) << std::endl;
0918
0919 if (lookupCase == HybridRes)
0920 {
0921
0922 for (int i = 0; i < q_lowres->Length(); i++)
0923 {
0924 *(q_lowres->GetFlat(i)) = 0;
0925 }
0926
0927
0928
0929 for (int ifr = 0; ifr < nr; ifr++)
0930 {
0931 int r_low = ifr / r_spacing;
0932 for (int ifphi = 0; ifphi < nphi; ifphi++)
0933 {
0934 int phi_low = ifphi / phi_spacing;
0935 for (int ifz = 0; ifz < nz; ifz++)
0936 {
0937 int z_low = ifz / z_spacing;
0938 q_lowres->Add(r_low, phi_low, z_low, q->GetChargeInBin(ifr, ifphi, ifz));
0939 }
0940 }
0941 }
0942 }
0943 return;
0944 }
0945
0946 void AnnularFieldSim::loadEfield(const std::string &filename, const std::string &treename, int zsign)
0947 {
0948
0949
0950 printf("AnnularFieldSim::loadEfield: loading E field from file %s, tree %s (sign=%d)\n", filename.c_str(), treename.c_str(),zsign);
0951 TFile fieldFile(filename.c_str(), "READ");
0952 TTree *fTree;
0953 fieldFile.GetObject(treename.c_str(), fTree);
0954 Efieldname = "E:" + filename + ":" + treename;
0955 float r, z;
0956 float fr, fz, fphi;
0957 fTree->SetBranchAddress("r", &r);
0958 fTree->SetBranchAddress("er", &fr);
0959 fTree->SetBranchAddress("z", &z);
0960 fTree->SetBranchAddress("ez", &fz);
0961
0962 fphi = 0;
0963
0964
0965
0966 loadField(&Eexternal, fTree, &r, nullptr, &z, &fr, &fphi, &fz, V / cm, zsign);
0967 printf("AnnularFieldSim::loadEfield: finished loading E field from file %s, tree %s (sign=%d)\n", filename.c_str(), treename.c_str(), zsign);
0968 fieldFile.Close();
0969 return;
0970 }
0971 void AnnularFieldSim::loadBfield(const std::string &filename, const std::string &treename)
0972 {
0973
0974
0975 TFile fieldFile(filename.c_str(), "READ");
0976 TTree *fTree;
0977 fieldFile.GetObject(treename.c_str(), fTree);
0978 Bfieldname = "B:" + filename + ":" + treename;
0979 float r, z;
0980 float fr, fz, fphi;
0981 fTree->SetBranchAddress("r", &r);
0982 fTree->SetBranchAddress("br", &fr);
0983 fTree->SetBranchAddress("z", &z);
0984 fTree->SetBranchAddress("bz", &fz);
0985
0986 fphi = 0;
0987
0988
0989
0990 loadField(&Bfield, fTree, &r, nullptr, &z, &fr, &fphi, &fz, Tesla, 1);
0991 printf("AnnularFieldSim::loadBfield: finished loading B field from file %s, tree %s\n", filename.c_str(), treename.c_str());
0992 fieldFile.Close();
0993
0994 return;
0995 }
0996
0997 void AnnularFieldSim::load3dBfield(const std::string &filename, const std::string &treename, int zsign, float scale, float xshift, float yshift, float zshift)
0998 {
0999
1000
1001 printf("AnnularFieldSim::load3dBfield: loading B field from file %s, tree %s (sign=%d)\n", filename.c_str(), treename.c_str(),zsign);
1002
1003 TFile fieldFile(filename.c_str(), "READ");
1004 TTree *fTree;
1005 fieldFile.GetObject(treename.c_str(), fTree);
1006 Bfieldname = "B(3D):" + filename + ":" + treename + " Scale =" + boost::str(boost::format("%2.2f") % scale);
1007 float r, z, phi;
1008 float fr, fz, fphi;
1009 fTree->SetBranchAddress("rho", &r);
1010 fTree->SetBranchAddress("brho", &fr);
1011 fTree->SetBranchAddress("z", &z);
1012 fTree->SetBranchAddress("bz", &fz);
1013 fTree->SetBranchAddress("phi", &phi);
1014 fTree->SetBranchAddress("bphi", &fphi);
1015 loadField(&Bfield, fTree, &r, &phi, &z, &fr, &fphi, &fz, Tesla * scale, zsign, xshift, yshift, zshift);
1016 printf("AnnularFieldSim::load3dBfield: finished loading B field from file %s, tree %s (sign=%d) with scale %f\n", filename.c_str(), treename.c_str(), zsign, scale);
1017 fieldFile.Close();
1018 return;
1019 }
1020
1021 void AnnularFieldSim::loadField(MultiArray<TVector3> **field, TTree *source, float *rptr, float *phiptr, float *zptr, float *frptr, float *fphiptr, float *fzptr, float fieldunit, int zsign, float xshift, float yshift, float zshift)
1022 {
1023
1024
1025
1026 TVector3 origin= TVector3(xshift, yshift, zshift);
1027 bool phiSymmetry = (phiptr == nullptr);
1028
1029 printf("AnnularFieldSim::loadField: loading field from %s, detector origin at (%f,%f,%f) in the field map, field unit %f, zsign %d, handling=%s\n", source->GetName(), origin.X(), origin.Y(), origin.Z(), fieldunit, zsign, (phiSymmetry ? "phi-symmetric" : "not phi-symmetric"));
1030
1031
1032 int lowres_factor = 3;
1033
1034
1035
1036
1037
1038
1039
1040 int nlowbins_phi= nphi / lowres_factor + 1;
1041 int nlowbins_r = nr / lowres_factor + 1;
1042 int nlowbins_z = nz / lowres_factor + 1;
1043 float phi_lowres_step = M_PI * 2.0 / nlowbins_phi;
1044 float r_lowres_step = (rmax - rmin) / nlowbins_r;
1045 float z_lowres_step = (zmax - zmin) / nlowbins_z;
1046
1047
1048 std::cout << boost::str(boost::format("loading field from %f<z<%f") % zmin % zmax) << std::endl;
1049 TH3F *htEntries = new TH3F("htentries", "num of entries in the field loading", nphi, 0, M_PI * 2.0, nr, rmin, rmax, nz, zmin, zmax);
1050 TH3F *htSum[3];
1051 TH3F *htEntriesLow = new TH3F("htentrieslow", "num of lowres entries in the field loading", nlowbins_phi+2, -phi_lowres_step, M_PI * 2.0+phi_lowres_step, nlowbins_r+2, rmin-r_lowres_step, rmax+r_lowres_step, nlowbins_z+2, zmin-z_lowres_step, zmax+z_lowres_step);
1052 TH3F *htSumLow[3];
1053 printf("AnnularFieldSim::loadField: hires has %d phi bins from %f to %f, %d r bins from %f to %f, and %d z bins from %f to %f\n",
1054 htEntries->GetNbinsX(), htEntries->GetXaxis()->GetXmin(), htEntries->GetXaxis()->GetXmax(),
1055 htEntries->GetNbinsY(), htEntries->GetYaxis()->GetXmin(), htEntries->GetYaxis()->GetXmax(),
1056 htEntries->GetNbinsZ(), htEntries->GetZaxis()->GetXmin(), htEntries->GetZaxis()->GetXmax());
1057 printf("AnnularFieldSim::loadField: lowres has %d phi bins from %f to %f, %d r bins from %f to %f, and %d z bins from %f to %f\n",
1058 htEntriesLow->GetNbinsX(), htEntriesLow->GetXaxis()->GetXmin(), htEntriesLow->GetXaxis()->GetXmax(),
1059 htEntriesLow->GetNbinsY(), htEntriesLow->GetYaxis()->GetXmin(), htEntriesLow->GetYaxis()->GetXmax(),
1060 htEntriesLow->GetNbinsZ(), htEntriesLow->GetZaxis()->GetXmin(), htEntriesLow->GetZaxis()->GetXmax());
1061
1062
1063
1064 std::string axis[]{"r", "p", "z"};
1065 for (int i = 0; i < 3; i++)
1066 {
1067
1068 htSum[i] = new TH3F(std::string("htsum" + std::to_string(i)).c_str(), std::string("sum of " + axis[i] + "-axis entries in the field loading").c_str(), htEntries->GetNbinsX(), htEntries->GetXaxis()->GetXmin(), htEntries->GetXaxis()->GetXmax(), htEntries->GetNbinsY(), htEntries->GetYaxis()->GetXmin(), htEntries->GetYaxis()->GetXmax(), htEntries->GetNbinsZ(), htEntries->GetZaxis()->GetXmin(), htEntries->GetZaxis()->GetXmax());
1069
1070 htSumLow[i] = new TH3F(std::string("htsumlow" + std::to_string(i)).c_str(), std::string("sum of low " + axis[i] + "-axis entries in the field loading").c_str(), htEntriesLow->GetNbinsX(), htEntriesLow->GetXaxis()->GetXmin(), htEntriesLow->GetXaxis()->GetXmax(), htEntriesLow->GetNbinsY(), htEntriesLow->GetYaxis()->GetXmin(), htEntriesLow->GetYaxis()->GetXmax(), htEntriesLow->GetNbinsZ(), htEntriesLow->GetZaxis()->GetXmin(), htEntriesLow->GetZaxis()->GetXmax());
1071 }
1072
1073
1074 std::vector<float> phiCoords(nphi);
1075 int nPhiCoords=1;
1076 if(phiSymmetry){
1077
1078
1079 for (int j = 0; j < nphi; j++)
1080 {
1081 float phi0=(j+0.5)*step.Phi();
1082 phiCoords[j]=phi0;
1083 printf("%2.2f ", phi0);
1084 }
1085 printf("\n");
1086 nPhiCoords=nphi;
1087 }
1088
1089
1090
1091
1092 int nEntries = source->GetEntries();
1093 for (int i = 0; i < nEntries; i++)
1094 {
1095
1096
1097 int rem=i%(source->GetEntries()/10);
1098 int quo=i/(source->GetEntries()/10);
1099 if(rem==0 && quo>0){
1100 printf("loadField: %d0%%\n", quo);
1101 }
1102
1103
1104 source->GetEntry(i);
1105 float zval = *zptr * zsign;
1106
1107 float rval=*rptr;
1108 float phival;
1109
1110 float fzval = *fzptr * fieldunit * zsign;
1111 float fphival = *fphiptr * fieldunit*zsign;
1112 float frval = *frptr * fieldunit;
1113 TVector3 rphizField(frval, fphival, fzval);
1114
1115
1116
1117
1118 if (!phiSymmetry)
1119 {
1120 assert(phiptr);
1121 phiCoords[0]=*phiptr;
1122 }
1123 for (int j = 0; j < nPhiCoords; j++){
1124 phival=phiCoords[j];
1125
1126
1127 TVector3 fieldMapPos(rval,0,zval);
1128 fieldMapPos.SetPhi(phival);
1129
1130
1131 TVector3 globalField=rphizField;
1132 globalField.RotateZ(phival);
1133
1134
1135 TVector3 tpcPos=fieldMapPos-origin;
1136
1137 TVector3 tpcField=GetLocalFieldComponents(globalField,fieldMapPos,origin);
1138
1139
1140 rval= tpcPos.Perp();
1141 phival = FilterPhiPos(tpcPos.Phi());
1142 zval = tpcPos.Z();
1143
1144
1145 frval = tpcField.X();
1146 fphival = tpcField.Y();
1147 fzval = tpcField.Z();
1148
1149 htEntries->Fill(phival,rval, zval);
1150 htSum[0]->Fill(phival,rval, zval, frval );
1151 htSum[1]->Fill(phival,rval, zval, fphival );
1152 htSum[2]->Fill(phival,rval, zval, fzval );
1153 htEntriesLow->Fill(phival,rval, zval);
1154 htSumLow[0]->Fill(phival,rval, zval, frval );
1155 htSumLow[1]->Fill(phival,rval, zval, fphival );
1156 htSumLow[2]->Fill(phival,rval, zval, fzval );
1157 }
1158 }
1159
1160 int nemptybins = 0;
1161 for (int i = 0; i < nphi; i++)
1162 {
1163 for (int j = 0; j < nr; j++)
1164 {
1165 for (int k = 0; k < nz; k++)
1166 {
1167 TVector3 cellcenter = GetCellCenter(j, i, k);
1168 int bin = htEntries->FindBin(FilterPhiPos(cellcenter.Phi()), cellcenter.Perp(), cellcenter.Z());
1169 TVector3 fieldvec(htSum[0]->GetBinContent(bin), htSum[1]->GetBinContent(bin), htSum[2]->GetBinContent(bin));
1170 if (htEntries->GetBinContent(bin) < 0.99)
1171 {
1172
1173 nemptybins++;
1174 } else{
1175 fieldvec = fieldvec * (1.0 / htEntries->GetBinContent(bin));
1176 }
1177
1178
1179
1180 fieldvec.RotateZ(FilterPhiPos(cellcenter.Phi()));
1181 (*field)->Set(j, i, k, fieldvec);
1182 }
1183 }
1184 }
1185 if (nemptybins > 0)
1186 {
1187 std::cout << boost::str(boost::format("found %d empty bins when constructing %s. Filling with lower resolution.") % nemptybins % ((*field == Bfield) ? "Bfield" : "Eexternal")) << std::endl;
1188
1189
1190 for (int j=0; j<htEntriesLow->GetNbinsY(); j++){
1191 for (int k=0; k<htEntriesLow->GetNbinsZ(); k++){
1192 int lowbin=htEntriesLow->GetBin(1,j,k);
1193 int highbin=htEntriesLow->GetBin(htEntriesLow->GetNbinsX()-1,j,k);
1194 htEntriesLow->SetBinContent(lowbin,
1195 htEntriesLow->GetBinContent(htEntriesLow->GetBin(htEntriesLow->GetNbinsX()-2,j,k)));
1196
1197 for (int i=0; i<3; i++){
1198 htSumLow[i]->SetBinContent(lowbin,
1199 htSumLow[i]->GetBinContent(htSumLow[i]->GetBin(htEntriesLow->GetNbinsX()-2,j,k)));
1200 }
1201
1202 htEntriesLow->SetBinContent(highbin,
1203 htEntriesLow->GetBinContent(htEntriesLow->GetBin(2,j,k)));
1204 for (int i=0; i<3; i++){
1205 htSumLow[i]->SetBinContent(highbin,
1206 htSumLow[i]->GetBinContent(htSumLow[i]->GetBin(2,j,k)));
1207 }
1208 }
1209 }
1210
1211
1212 for (int i = 0; i < nphi; i++)
1213 {
1214 for (int j = 0; j < nr; j++)
1215 {
1216 for (int k = 0; k < nz; k++)
1217 {
1218 TVector3 cellcenter = GetCellCenter(j, i, k);
1219 int bin = htEntries->FindBin(FilterPhiPos(cellcenter.Phi()), cellcenter.Perp(), cellcenter.Z());
1220 if (htEntries->GetBinContent(bin) == 0)
1221 {
1222 if(0){
1223 printf("Filling coordinates p%f,r%f,z%f, (cell p%d r%d z%d) with lowres field\n", FilterPhiPos(cellcenter.Phi()), cellcenter.Perp(), cellcenter.Z(), i,j,k);
1224 printf(" sanity: htEntries->FindBins(p%2.2f,r%2.2f,z%2.2f)=(p%d,r%d,z%d)=%d, content=%f\n", FilterPhiPos(cellcenter.Phi()), cellcenter.Perp(), cellcenter.Z(),
1225 htEntries->GetXaxis()->FindBin(FilterPhiPos(cellcenter.Phi())),
1226 htEntries->GetYaxis()->FindBin(cellcenter.Perp()),
1227 htEntries->GetZaxis()->FindBin(cellcenter.Z()), bin, htEntries->GetBinContent(bin));
1228
1229 TVector3 globalPos= cellcenter+origin;
1230
1231 float tr_low=htEntries->GetYaxis()->GetBinLowEdge(htEntries->GetYaxis()->FindBin(cellcenter.Perp()));
1232 float tr_high=htEntries->GetYaxis()->GetBinUpEdge(htEntries->GetYaxis()->FindBin(cellcenter.Perp()));
1233 float tz_low=htEntries->GetZaxis()->GetBinLowEdge(htEntries->GetZaxis()->FindBin(cellcenter.Z()));
1234 float tz_high=htEntries->GetZaxis()->GetBinUpEdge(htEntries->GetZaxis()->FindBin(cellcenter.Z()));
1235 float tphi_low=htEntries->GetXaxis()->GetBinLowEdge(htEntries->GetXaxis()->FindBin(FilterPhiPos(cellcenter.Phi())));
1236 float tphi_high=htEntries->GetXaxis()->GetBinUpEdge(htEntries->GetXaxis()->FindBin(FilterPhiPos(cellcenter.Phi())));
1237 TVector3 tlow(tr_low, 0, tz_low);
1238 tlow.RotateZ(tphi_low);
1239 TVector3 thigh(tr_high, 0, tz_high);
1240 thigh.RotateZ(tphi_high);
1241 tlow=tlow+origin;
1242 thigh=thigh+origin;
1243 if (phiSymmetry){
1244 printf("this corresponds to (r,phi,z)=(%f,%f,%f) in the input map coordinates, which has bounds roughly (r>%1.1f && r<%1.1f && z> %1.1f && z<%1.1f)\n",globalPos.Perp(),globalPos.Phi(),globalPos.Z(),tlow.Perp(),thigh.Perp(),tlow.Z(),thigh.Z());
1245 }else{
1246
1247 printf("this corresponds to (r,phi,z)=(%f,%f,%f) in the input map coordinates, which has bounds roughly (r>%1.1f && r<%1.1f && phi>%1.1f && phi<%1.1f && z> %1.1f && z<%1.1f)\n",globalPos.Perp(),globalPos.Phi(),globalPos.Z(),tlow.Perp(),thigh.Perp(),tlow.Phi(),thigh.Phi(),tlow.Z(),thigh.Z());
1248 }
1249 }
1250
1251 TVector3 fieldvec(htSumLow[0]->Interpolate(FilterPhiPos(cellcenter.Phi()), cellcenter.Perp(), cellcenter.Z()),
1252 htSumLow[1]->Interpolate(FilterPhiPos(cellcenter.Phi()), cellcenter.Perp(), cellcenter.Z()),
1253 htSumLow[2]->Interpolate(FilterPhiPos(cellcenter.Phi()), cellcenter.Perp(), cellcenter.Z()));
1254 int lowbin = htEntriesLow->FindBin(FilterPhiPos(cellcenter.Phi()), cellcenter.Perp(), cellcenter.Z());
1255
1256
1257 if (htEntriesLow->GetBinContent(lowbin) < 0.99)
1258 {
1259 std::cout << boost::str(boost::format("not enough entries in source to fill fieldmap, even using the lower res fall-back. Value near r=%2.2f, phi=%2.2f, z=%2.2f is %f, (with range of %2.3f,%2.3f,%2.3f) Pick lower granularity!") % cellcenter.Perp() % FilterPhiPos(cellcenter.Phi()) % cellcenter.Z()% htEntriesLow->GetBinContent(lowbin) % r_lowres_step % phi_lowres_step % z_lowres_step) << std::endl;
1260 printf("Saving fieldmaps to debug.hist.root\n");
1261 TFile *debugfile = new TFile("debug.hist.root", "RECREATE");
1262 htEntries->Write();
1263 htEntriesLow->Write();
1264 for (int ii = 0; ii < 3; ii++)
1265 {
1266 htSum[ii]->Write();
1267 htSumLow[ii]->Write();
1268 }
1269 debugfile->Close();
1270 exit(1);
1271 } else {
1272 fieldvec = fieldvec * (1.0 / htEntriesLow->GetBinContent(lowbin));
1273 }
1274
1275 fieldvec.RotateZ(FilterPhiPos(cellcenter.Phi()));
1276 (*field)->Set(j, i, k, fieldvec);
1277 }
1278 }
1279 }
1280 }
1281 }
1282
1283 return;
1284 }
1285
1286 void AnnularFieldSim::load_spacecharge(const std::string &filename, const std::string &histname, float zoffset, float chargescale, float cmscale, bool isChargeDensity)
1287 {
1288 TFile *f = TFile::Open(filename.c_str());
1289 TH3 *scmap;
1290 f->GetObject(histname.c_str(), scmap);
1291 std::cout << "Loading spacecharge from '" << filename
1292 << "'. Seeking histname '" << histname << "'" << std::endl;
1293 chargesourcename = filename + ":" + histname;
1294 load_spacecharge(scmap, zoffset, chargescale, cmscale, isChargeDensity, chargesourcename.c_str());
1295 f->Close();
1296 return;
1297 }
1298
1299 void AnnularFieldSim::load_and_resample_spacecharge(int new_nphi, int new_nr, int new_nz, const std::string &filename, const std::string &histname, float zoffset, float chargescale, float cmscale, bool isChargeDensity)
1300 {
1301 TFile *f = TFile::Open(filename.c_str());
1302 TH3 *scmap;
1303 f->GetObject(histname.c_str(), scmap);
1304 std::cout << "Resampling spacecharge from '" << filename
1305 << "'. Seeking histname '" << histname << "'" << std::endl;
1306 chargesourcename = filename + ":" + histname;
1307 load_and_resample_spacecharge(new_nphi, new_nr, new_nz, scmap, zoffset, chargescale, cmscale, isChargeDensity);
1308 f->Close();
1309 return;
1310 }
1311
1312 void AnnularFieldSim::load_and_resample_spacecharge(int new_nphi, int new_nr, int new_nz, TH3 *hist, float zoffset, float chargescale, float cmscale, bool isChargeDensity)
1313 {
1314
1315
1316
1317
1318
1319
1320
1321 float hrmin = hist->GetYaxis()->GetXmin();
1322 float hrmax = hist->GetYaxis()->GetXmax();
1323 float hphimin = hist->GetXaxis()->GetXmin();
1324 float hphimax = hist->GetXaxis()->GetXmax();
1325 float hzmin = hist->GetZaxis()->GetXmin();
1326 float hzmax = hist->GetZaxis()->GetXmax();
1327
1328
1329 int hrn = hist->GetNbinsY();
1330 int hphin = hist->GetNbinsX();
1331 int hzn = hist->GetNbinsZ();
1332 std::cout << boost::str(boost::format("From histogram, native r dimensions: %f<r<%f, hrn (Y axis)=%d") % hrmin % hrmax % hrn) << std::endl;
1333 std::cout << boost::str(boost::format("From histogram, native phi dimensions: %f<phi<%f, hrn (X axis)=%d") % hphimin % hphimax % hphin) << std::endl;
1334 std::cout << boost::str(boost::format("From histogram, native z dimensions: %f<z<%f, hrn (Z axis)=%d") % hzmin % hzmax % hzn) << std::endl;
1335
1336
1337 float hrstep = (hrmax - hrmin) / hrn;
1338 float hphistep = (hphimax - hphimin) / hphin;
1339 float hzstep = (hzmax - hzmin) / hzn;
1340 float halfrstep = hrstep * 0.5;
1341 float halfphistep = hphistep * 0.5;
1342 float halfzstep = hzstep * 0.5;
1343
1344
1345
1346
1347 if (!isChargeDensity)
1348 {
1349 for (int i = 0; i < hphin; i++)
1350 {
1351 float phi = hphimin + hphistep * i;
1352 for (int j = 0; j < hrn; j++)
1353 {
1354 float r = hrmin + hrstep * j;
1355 for (int k = 0; k < hzn; k++)
1356 {
1357 float z = hzmin + hzstep * k;
1358 int bin = hist->FindBin(phi + halfphistep, r + halfrstep, z + halfzstep);
1359 double vol = hzstep * hphistep * (r + halfrstep) * hrstep;
1360 hist->SetBinContent(bin, hist->GetBinContent(bin) / vol);
1361 }
1362 }
1363 }
1364 }
1365
1366 TH3F *resampled = new TH3F("resampled", "resampled charge", new_nphi, hphimin, hphimax, new_nr, hrmin, hrmax, new_nz, hzmin, hzmax);
1367 float new_phistep = (hphimax - hphimin) / new_nphi;
1368 float new_rstep = (hrmax - hrmin) / new_nr;
1369 float new_zstep = (hzmax - hzmin) / new_nz;
1370
1371
1372 for (int i = 0; i < new_nphi; i++)
1373 {
1374 float phi = hphimin + new_phistep * (i + 0.5);
1375 float hphi = (phi - hphimin) / hphistep;
1376 bool phisafe = ((hphi - 0.75) > 0) && ((hphi + 0.75) < hphin);
1377 for (int j = 0; j < new_nr; j++)
1378 {
1379 float r = hrmin + new_rstep * (j + 0.5);
1380 float hr = (r - hrmin) / hrstep;
1381 bool rsafe = ((hr - 0.5) > 0) && ((hr + 0.5) < hrn);
1382 for (int k = 0; k < new_nz; k++)
1383 {
1384 float z = hzmin + new_zstep * (k + 0.5);
1385 float hz = (z - hzmin) / hzstep;
1386 bool zsafe = ((hz - 0.5) > 0) && ((hz + 0.5) < hzn);
1387
1388 if (phisafe && rsafe && zsafe)
1389 {
1390
1391 resampled->Fill(phi, r, z, hist->Interpolate(phi, r, z));
1392 }
1393 else
1394 {
1395 int bin = hist->FindBin(phi, r, z);
1396 resampled->Fill(phi, r, z, hist->GetBinContent(bin));
1397 }
1398 }
1399 }
1400 }
1401 std::cout << "here in load_and_resample_spacecharge, I am going to call load_spacecharge." << std::endl;
1402 load_spacecharge(resampled, zoffset, chargescale, cmscale, true);
1403 }
1404
1405 void AnnularFieldSim::load_spacecharge(TH3 *hist, float zoffset, float chargescale, float cmscale, bool isChargeDensity, const std::string &inputchargestring)
1406 {
1407
1408 if (std::abs(zoffset) > 0.001)
1409 {
1410 std::cout << boost::str(boost::format("nonzero zoffset given (%E) but new spacecharge loader can't deal with that. Failing.") % zoffset) << std::endl;
1411 assert(false);
1412 }
1413 if (isChargeDensity)
1414 {
1415 std::cout << "Input dataset is flagged as recording density not total charge, but new loader can't deal with that Failing.." << std::endl;
1416 assert(false);
1417 }
1418 q->ReadSourceCharge(hist, cmscale, chargescale);
1419
1420 chargestring = "SC loaded externally: " + inputchargestring + ".";
1421 return;
1422 }
1423
1424 void AnnularFieldSim::load_digital_current(TH3 *hist, TH2 *gainHist, float chargescale, float cmscale, const std::string &inputchargestring)
1425 {
1426 q->ReadSourceAdc(hist, gainHist, cmscale, chargescale);
1427
1428 chargestring = "SC loaded externally: " + inputchargestring + ".";
1429 return;
1430 }
1431
1432 void AnnularFieldSim::save_spacecharge(const std::string &filename)
1433 {
1434
1435 TH3F *hsc = new TH3F("hInternalSpaceCharge", "Internal Charge Histogram;phi(rad);r(cm);z(cm)", nphi, 0, phispan, nr, rmin, rmax, nz, zmin, zmax);
1436 for (int i = 0; i < nphi; i++)
1437 {
1438 float phi = 0 + step.Phi() * (i + 0.5);
1439 for (int j = 0; j < nr; j++)
1440 {
1441 float r = rmin + step.Perp() * (j + 0.5);
1442 for (int k = 0; k < nz; k++)
1443 {
1444 float z = zmin + step.Z() * (k + 0.5);
1445 hsc->Fill(phi, r, z, q->GetChargeAtPosition(r, phi, z));
1446
1447 }
1448 }
1449 }
1450 hsc->SaveAs(filename.c_str());
1451 return;
1452 }
1453
1454 void AnnularFieldSim::add_testcharge(float r, float phi, float z, float coulombs)
1455 {
1456 q->AddChargeAtPosition(r, phi, z, coulombs * C);
1457 return;
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485 }
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508 void AnnularFieldSim::populate_fieldmap()
1509 {
1510
1511
1512 std::cout << boost::str(boost::format("in pop_fieldmap, n=(%d,%d,%d)") % nr % nphi % nz) << std::endl;
1513
1514 std::cout << boost::str(boost::format("populating fieldmap for (%dx%dx%d) grid with (%dx%dx%d) source ") % nr_roi % nphi_roi % nz_roi % nr % nphi % nz) << std::endl;
1515 if (truncation_length > 0)
1516 {
1517 std::cout << boost::str(boost::format(" ==> truncating anything more than %d cells away") % truncation_length) << std::endl;
1518 }
1519 unsigned long long totalelements = nr_roi;
1520 totalelements *= nphi_roi;
1521 totalelements *= nz_roi;
1522 unsigned long long percent = totalelements / 100 * debug_npercent;
1523 std::cout << boost::str(boost::format("total elements = %llu") % (totalelements * nr * nphi * nz)) << std::endl;
1524
1525 int el = 0;
1526
1527 TVector3 localF;
1528 for (int ir = rmin_roi; ir < rmax_roi; ir++)
1529 {
1530 for (int iphi = phimin_roi; iphi < phimax_roi; iphi++)
1531 {
1532 for (int iz = zmin_roi; iz < zmax_roi; iz++)
1533 {
1534 localF = sum_field_at(ir, iphi, iz);
1535 if (!(el % percent))
1536 {
1537 std::cout << boost::str(boost::format("populate_fieldmap %llu%%: ") % ((uint64_t) (debug_npercent) *el / percent));
1538 std::cout << boost::str(boost::format("sum_field_at (ir=%d,iphi=%d,iz=%d) gives (%E,%E,%E)") % ir % iphi % iz % localF.X() % localF.Y() % localF.Z()) << std::endl;
1539 }
1540 el++;
1541
1542 Efield->Set(ir - rmin_roi, iphi - phimin_roi, iz - zmin_roi, localF);
1543
1544
1545 }
1546 }
1547 }
1548 return;
1549 }
1550
1551 void AnnularFieldSim::populate_lookup()
1552 {
1553
1554
1555
1556
1557
1558 if (lookupCase == Full3D)
1559 {
1560 std::cout << "lookupCase==Full3D" << std::endl;
1561
1562 populate_full3d_lookup();
1563 }
1564 else if (lookupCase == HybridRes)
1565 {
1566 std::cout << "lookupCase==HybridRes" << std::endl;
1567 populate_highres_lookup();
1568 populate_lowres_lookup();
1569 }
1570 else if (lookupCase == PhiSlice)
1571 {
1572 std::cout << "Populating lookup: lookupCase==PhiSlice" << std::endl;
1573 populate_phislice_lookup();
1574 }
1575 else if (lookupCase == Analytic)
1576 {
1577 std::cout << "Populating lookup: lookupCase==Analytic ===> skipping!" << std::endl;
1578 }
1579 else if (lookupCase == NoLookup)
1580 {
1581 std::cout << "Populating lookup: lookupCase==NoLookup ===> skipping!" << std::endl;
1582 }
1583 else
1584 {
1585 exit(1);
1586 }
1587 return;
1588 }
1589
1590 void AnnularFieldSim::populate_full3d_lookup()
1591 {
1592
1593
1594
1595 std::cout << boost::str(boost::format("populating full lookup table for (%dx%dx%d)x(%dx%dx%d) grid") % (rmax_roi - rmin_roi) % (phimax_roi - phimin_roi) % (zmax_roi - zmin_roi) % nr % nphi % nz) << std::endl;
1596 unsigned long long totalelements = (rmax_roi - rmin_roi);
1597 totalelements *= (phimax_roi - phimin_roi);
1598 totalelements *= (zmax_roi - zmin_roi);
1599 totalelements *= nr;
1600 totalelements *= nphi;
1601 totalelements *= nz;
1602 unsigned long long percent = totalelements / 100 * debug_npercent;
1603 std::cout << boost::str(boost::format("total elements = %llu") % totalelements) << std::endl;
1604 TVector3 at(1, 0, 0);
1605 TVector3 from(1, 0, 0);
1606 TVector3 zero(0, 0, 0);
1607
1608 int el = 0;
1609 for (int ifr = rmin_roi; ifr < rmax_roi; ifr++)
1610 {
1611 for (int ifphi = phimin_roi; ifphi < phimax_roi; ifphi++)
1612 {
1613 for (int ifz = zmin_roi; ifz < zmax_roi; ifz++)
1614 {
1615 at = GetCellCenter(ifr, ifphi, ifz);
1616 for (int ior = 0; ior < nr; ior++)
1617 {
1618 for (int iophi = 0; iophi < nphi; iophi++)
1619 {
1620 for (int ioz = 0; ioz < nz; ioz++)
1621 {
1622 el++;
1623 if (!(el % percent))
1624 {
1625 std::cout << boost::str(boost::format("populate_full3d_lookup %d%%") % ((uint64_t) (debug_npercent) *el / percent)) << std::endl;
1626 }
1627 from = GetCellCenter(ior, iophi, ioz);
1628
1629
1630
1631 if (ifr == ior && ifphi == iophi && ifz == ioz)
1632 {
1633 Epartial->Set(ifr - rmin_roi, ifphi - phimin_roi, ifz - zmin_roi, ior, iophi, ioz, zero);
1634 }
1635 else
1636 {
1637 Epartial->Set(ifr - rmin_roi, ifphi - phimin_roi, ifz - zmin_roi, ior, iophi, ioz, calc_unit_field(at, from));
1638 }
1639 }
1640 }
1641 }
1642 }
1643 }
1644 }
1645 return;
1646 }
1647
1648 void AnnularFieldSim::populate_highres_lookup()
1649 {
1650 TVector3 at(1, 0, 0);
1651 TVector3 from(1, 0, 0);
1652 TVector3 zero(0, 0, 0);
1653
1654
1655 int r_highres_dist = (nr_high - 1) / 2;
1656 int phi_highres_dist = (nphi_high - 1) / 2;
1657 int z_highres_dist = (nz_high - 1) / 2;
1658
1659
1660 static int nfbinsin[3][3][3];
1661 for (auto &i : nfbinsin)
1662 {
1663 for (auto &j : i)
1664 {
1665 for (int &k : j)
1666 {
1667 k = 0;
1668 }
1669 }
1670 }
1671
1672
1673
1674
1675 TVector3 currentf, newf;
1676 for (int ifr = rmin_roi; ifr < rmax_roi; ifr++)
1677 {
1678 int r_parentlow = std::floor((ifr - r_highres_dist) / (r_spacing * 1.0));
1679 int r_parenthigh = std::floor((ifr + r_highres_dist) / (r_spacing * 1.0)) + 1;
1680 int r_startpoint = r_parentlow * r_spacing;
1681 int r_endpoint = r_parenthigh * r_spacing;
1682
1683 for (int ifphi = phimin_roi; ifphi < phimax_roi; ifphi++)
1684 {
1685 int phi_parentlow = std::floor(FilterPhiIndex(ifphi - phi_highres_dist) / (phi_spacing * 1.0));
1686 bool phi_parentlow_wrapped = (ifphi - phi_highres_dist < 0);
1687 int phi_startpoint = phi_parentlow * phi_spacing;
1688 if (phi_parentlow_wrapped)
1689 {
1690 phi_startpoint -= nphi;
1691 }
1692
1693 int phi_parenthigh = std::floor(FilterPhiIndex(ifphi + phi_highres_dist) / (phi_spacing * 1.0)) + 1;
1694 bool phi_parenthigh_wrapped = (ifphi + phi_highres_dist >= nphi);
1695 int phi_endpoint = phi_parenthigh * phi_spacing;
1696 if (phi_parenthigh_wrapped)
1697 {
1698 phi_endpoint += nphi;
1699 }
1700
1701 for (int ifz = zmin_roi; ifz < zmax_roi; ifz++)
1702 {
1703
1704
1705 int z_parentlow = std::floor((ifz - z_highres_dist) / (z_spacing * 1.0));
1706 int z_parenthigh = std::floor((ifz + z_highres_dist) / (z_spacing * 1.0)) + 1;
1707 int z_startpoint = z_parentlow * z_spacing;
1708 int z_endpoint = z_parenthigh * z_spacing;
1709
1710
1711 at = GetCellCenter(ifr, ifphi, ifz);
1712
1713
1714
1715
1716
1717
1718
1719 for (int ir = r_startpoint; ir < r_endpoint; ir++)
1720 {
1721
1722
1723 if (ir < 0)
1724 {
1725 ir = 0;
1726 }
1727 if (ir >= nr)
1728 {
1729 break;
1730 }
1731
1732 int rbin = (ir - ifr) + r_highres_dist;
1733 int rcell = 1;
1734 if (rbin <= 0)
1735 {
1736 rbin = 0;
1737 rcell = 0;
1738 }
1739 if (rbin >= nr_high)
1740 {
1741 rbin = nr_high - 1;
1742 rcell = 2;
1743 }
1744
1745 for (int iphi = phi_startpoint; iphi < phi_endpoint; iphi++)
1746 {
1747
1748 int phiFilt = FilterPhiIndex(iphi);
1749 int phibin = (iphi - ifphi) + phi_highres_dist;
1750 int phicell = 1;
1751 if (phibin <= 0)
1752 {
1753 phibin = 0;
1754 phicell = 0;
1755 }
1756 if (phibin >= nphi_high)
1757 {
1758 phibin = nphi_high - 1;
1759 phicell = 2;
1760 }
1761 for (int iz = z_startpoint; iz < z_endpoint; iz++)
1762 {
1763 if (iz < 0)
1764 {
1765 iz = 0;
1766 }
1767 if (iz >= nz)
1768 {
1769 break;
1770 }
1771 int zbin = (iz - ifz) + z_highres_dist;
1772 int zcell = 1;
1773 if (zbin <= 0)
1774 {
1775 zbin = 0;
1776 zcell = 0;
1777 }
1778 if (zbin >= nz_high)
1779 {
1780 zbin = nz_high - 1;
1781 zcell = 2;
1782 }
1783
1784 from = GetCellCenter(ir, phiFilt, iz);
1785
1786 nfbinsin[rcell][phicell][zcell]++;
1787 int nf = nfbinsin[rcell][phicell][zcell];
1788
1789 int ir_rel = ifr - rmin_roi;
1790 int iphi_rel = ifphi - phimin_roi;
1791 int iz_rel = ifz - zmin_roi;
1792 if (zcell != 1 || rcell != 1 || phicell != 1)
1793 {
1794
1795
1796 if (iphi_rel < 0)
1797 {
1798 std::cout << boost::str(boost::format("%d: Getting with phi=%d") % __LINE__ % iphi_rel) << std::endl;
1799 }
1800 currentf = Epartial_highres->Get(ir_rel, iphi_rel, iz_rel, rbin, phibin, zbin);
1801
1802
1803 newf = (currentf * (nf - 1) + calc_unit_field(at, from)) * (1 / (nf * 1.0));
1804 Epartial_highres->Set(ir_rel, iphi_rel, iz_rel, rbin, phibin, zbin, newf);
1805 }
1806 else
1807 {
1808
1809
1810 if (ifr == rbin && ifphi == phibin && ifz == zbin)
1811 {
1812 Epartial_highres->Set(ir_rel, iphi_rel, iz_rel, rbin, phibin, zbin, zero);
1813 }
1814 else
1815 {
1816 newf = calc_unit_field(at, from);
1817 Epartial_highres->Set(ir_rel, iphi_rel, iz_rel, rbin, phibin, zbin, newf);
1818 }
1819 }
1820 }
1821 }
1822 }
1823 }
1824 }
1825 }
1826 return;
1827 }
1828
1829 void AnnularFieldSim::populate_lowres_lookup()
1830 {
1831 TVector3 at(1, 0, 0);
1832 TVector3 from(1, 0, 0);
1833 TVector3 zero(0, 0, 0);
1834 int fphi_low, fphi_high, fz_low, fz_high;
1835 int r_low, r_high, phi_low, phi_high, z_low, z_high;
1836
1837
1838 for (int ifr = rmin_roi_low; ifr < rmax_roi_low; ifr++)
1839 {
1840 int fr_low = ifr * r_spacing;
1841 int fr_high = fr_low + r_spacing - 1;
1842 if (fr_high >= nr)
1843 {
1844 fr_high = nr - 1;
1845 }
1846 for (int ifphi = phimin_roi_low; ifphi < phimax_roi_low; ifphi++)
1847 {
1848 fphi_low = ifphi * phi_spacing;
1849 fphi_high = fphi_low + phi_spacing - 1;
1850 if (fphi_high >= nphi)
1851 {
1852 fphi_high = nphi - 1;
1853 }
1854 for (int ifz = zmin_roi_low; ifz < zmax_roi_low; ifz++)
1855 {
1856 fz_low = ifz * z_spacing;
1857 fz_high = fz_low + z_spacing - 1;
1858 if (fz_high >= nz)
1859 {
1860 fz_high = nz - 1;
1861 }
1862 at = GetGroupCellCenter(fr_low, fr_high, fphi_low, fphi_high, fz_low, fz_high);
1863
1864
1865
1866 for (int ior = 0; ior < nr_low; ior++)
1867 {
1868 r_low = ior * r_spacing;
1869 r_high = r_low + r_spacing - 1;
1870 int ir_rel = ifr - rmin_roi_low;
1871
1872 if (r_high >= nr)
1873 {
1874 r_high = nr - 1;
1875 }
1876 for (int iophi = 0; iophi < nphi_low; iophi++)
1877 {
1878 phi_low = iophi * phi_spacing;
1879 phi_high = phi_low + phi_spacing - 1;
1880 if (phi_high >= nphi)
1881 {
1882 phi_high = nphi - 1;
1883 }
1884 int iphi_rel = ifphi - phimin_roi_low;
1885 for (int ioz = 0; ioz < nz_low; ioz++)
1886 {
1887 z_low = ioz * z_spacing;
1888 z_high = z_low + z_spacing - 1;
1889 if (z_high >= nz)
1890 {
1891 z_high = nz - 1;
1892 }
1893 int iz_rel = ifz - zmin_roi_low;
1894 from = GetGroupCellCenter(r_low, r_high, phi_low, phi_high, z_low, z_high);
1895
1896 if (ifr == ior && ifphi == iophi && ifz == ioz)
1897 {
1898 Epartial_lowres->Set(ir_rel, iphi_rel, iz_rel, ior, iophi, ioz, zero);
1899 }
1900 else
1901 {
1902 Epartial_lowres->Set(ir_rel, iphi_rel, iz_rel, ior, iophi, ioz, calc_unit_field(at, from));
1903 }
1904
1905
1906
1907
1908 }
1909 }
1910 }
1911 }
1912 }
1913 }
1914 return;
1915 }
1916
1917 void AnnularFieldSim::populate_phislice_lookup()
1918 {
1919
1920
1921
1922 std::cout << boost::str(boost::format("populating phislice lookup for (%dx%dx%d)x(%dx%dx%d) grid") % nr_roi % 1 % nz_roi % nr % nphi % nz) << std::endl;
1923 unsigned long long totalelements = nr;
1924 totalelements *= nphi;
1925 totalelements *= nz;
1926 totalelements *= nr_roi;
1927 totalelements *= nz_roi;
1928 unsigned long long percent = totalelements / 100 * debug_npercent;
1929 std::cout << boost::str(boost::format("total elements = %llu") % totalelements) << std::endl;
1930 TVector3 at(1, 0, 0);
1931 TVector3 from(1, 0, 0);
1932 TVector3 zero(0, 0, 0);
1933
1934 int el = 0;
1935 for (int ifr = rmin_roi; ifr < rmax_roi; ifr++)
1936 {
1937 for (int ifz = zmin_roi; ifz < zmax_roi; ifz++)
1938 {
1939 at = GetCellCenter(ifr, 0, ifz);
1940 for (int ior = 0; ior < nr; ior++)
1941 {
1942 for (int iophi = 0; iophi < nphi; iophi++)
1943 {
1944 for (int ioz = 0; ioz < nz; ioz++)
1945 {
1946 el++;
1947 from = GetCellCenter(ior, iophi, ioz);
1948
1949
1950 if (ifr == ior && 0 == iophi && ifz == ioz)
1951 {
1952 if (!(el % percent))
1953 {
1954 std::cout << boost::str(boost::format("populate_phislice_lookup %llu%%: ") % ((uint64_t) (debug_npercent) *el / percent));
1955 std::cout << boost::str(boost::format("self-to-self is zero (ir=%d,iphi=%d,iz=%d) to (or=%d,ophi=0,oz=%d) gives (%E,%E,%E)") % ior % iophi % ioz % ifr % ifz % zero.X() % zero.Y() % zero.Z()) << std::endl;
1956 }
1957 Epartial_phislice->Set(ifr - rmin_roi, 0, ifz - zmin_roi, ior, iophi, ioz, zero);
1958 }
1959 else
1960 {
1961 TVector3 unitf = calc_unit_field(at, from);
1962 if (true)
1963 {
1964 if (!(el % percent))
1965 {
1966 std::cout << boost::str(boost::format("populate_phislice_lookup %llu%%: ") % ((uint64_t) (debug_npercent) *el / percent));
1967 std::cout << boost::str(boost::format("calc_unit_field (ir=%d,iphi=%d,iz=%d) to (or=%d,ophi=0,oz=%d) gives (%E,%E,%E)") % ior % iophi % ioz % ifr % ifz % unitf.X() % unitf.Y() % unitf.Z()) << std::endl;
1968 }
1969 }
1970
1971 Epartial_phislice->Set(ifr - rmin_roi, 0, ifz - zmin_roi, ior, iophi, ioz, unitf);
1972 }
1973 }
1974 }
1975 }
1976 }
1977 }
1978 return;
1979 }
1980
1981 void AnnularFieldSim::load_phislice_lookup(const std::string &sourcefile)
1982 {
1983 std::cout << boost::str(boost::format("loading phislice lookup for (%dx%dx%d)x(%dx%dx%d) grid from %s") % nr_roi % 1 % nz_roi % nr % nphi % nz % sourcefile) << std::endl;
1984 unsigned long long totalelements = nr;
1985 totalelements *= nphi;
1986 totalelements *= nz;
1987 totalelements *= nr_roi;
1988 totalelements *= nz_roi;
1989 unsigned long long percent = totalelements / 100 * debug_npercent;
1990 std::cout << boost::str(boost::format("total elements = %llu") % totalelements) << std::endl;
1991
1992 TFile *input = TFile::Open(sourcefile.c_str(), "READ");
1993 TTree *tInfo;
1994 input->GetObject("info", tInfo);
1995 assert(tInfo);
1996
1997 float file_rmin, file_rmax, file_zmin, file_zmax;
1998 int file_rmin_roi, file_rmax_roi, file_zmin_roi, file_zmax_roi;
1999 int file_nr, file_np, file_nz;
2000 tInfo->SetBranchAddress("rmin", &file_rmin);
2001 tInfo->SetBranchAddress("rmax", &file_rmax);
2002 tInfo->SetBranchAddress("zmin", &file_zmin);
2003 tInfo->SetBranchAddress("zmax", &file_zmax);
2004 tInfo->SetBranchAddress("rmin_roi_index", &file_rmin_roi);
2005 tInfo->SetBranchAddress("rmax_roi_index", &file_rmax_roi);
2006 tInfo->SetBranchAddress("zmin_roi_index", &file_zmin_roi);
2007 tInfo->SetBranchAddress("zmax_roi_index", &file_zmax_roi);
2008 tInfo->SetBranchAddress("nr", &file_nr);
2009 tInfo->SetBranchAddress("nphi", &file_np);
2010 tInfo->SetBranchAddress("nz", &file_nz);
2011 tInfo->GetEntry(0);
2012
2013 std::cout << "param\tobj\tfile" << std::endl;
2014 ;
2015 std::cout << boost::str(boost::format("nr\t%d\t%d") % nr % file_nr) << std::endl;
2016 std::cout << boost::str(boost::format("np\t%d\t%d") % nphi % file_np) << std::endl;
2017 std::cout << boost::str(boost::format("nz\t%d\t%d") % nz % file_nz) << std::endl;
2018 std::cout << boost::str(boost::format("rmin\t%2.2f\t%2.2f") % rmin % file_rmin) << std::endl;
2019 std::cout << boost::str(boost::format("rmax\t%2.2f\t%2.2f") % rmax % file_rmax) << std::endl;
2020 std::cout << boost::str(boost::format("zmin\t%2.2f\t%2.2f") % zmin % file_zmin) << std::endl;
2021 std::cout << boost::str(boost::format("zmax\t%2.2f\t%2.2f") % zmax % file_zmax) << std::endl;
2022 std::cout << boost::str(boost::format("rmin_roi\t%d\t%d") % rmin_roi % file_rmin_roi) << std::endl;
2023 std::cout << boost::str(boost::format("rmax_roi\t%d\t%d") % rmax_roi % file_rmax_roi) << std::endl;
2024 std::cout << boost::str(boost::format("zmin_roi\t%d\t%d") % zmin_roi % file_zmin_roi) << std::endl;
2025 std::cout << boost::str(boost::format("zmax_roi\t%d\t%d") % zmax_roi % file_zmax_roi) << std::endl;
2026
2027 if (file_rmin != rmin || file_rmax != rmax ||
2028 file_zmin != zmin || file_zmax != zmax ||
2029 file_rmin_roi != rmin_roi || file_rmax_roi != rmax_roi ||
2030 file_zmin_roi != zmin_roi || file_zmax_roi != zmax_roi ||
2031 file_nr != nr || file_np != nphi || file_nz != nz)
2032 {
2033 std::cout << "file parameters do not match fieldsim parameters:" << std::endl;
2034 ;
2035
2036 exit(1);
2037 }
2038
2039 TTree *tLookup;
2040 input->GetObject("phislice", tLookup);
2041 assert(tLookup);
2042 int ior, ifr, iophi, ioz, ifz;
2043 TVector3 *unitf = nullptr;
2044 tLookup->SetBranchAddress("ir_source", &ior);
2045 tLookup->SetBranchAddress("ir_target", &ifr);
2046 tLookup->SetBranchAddress("ip_source", &iophi);
2047
2048 tLookup->SetBranchAddress("iz_source", &ioz);
2049 tLookup->SetBranchAddress("iz_target", &ifz);
2050 tLookup->SetBranchAddress("Evec", &unitf);
2051
2052 int el = 0;
2053 std::cout << boost::str(boost::format("%s has %lld entries") % sourcefile % tLookup->GetEntries());
2054 for (int i = 0; i < (int) totalelements; i++)
2055 {
2056 el++;
2057 tLookup->GetEntry(i);
2058
2059 Epartial_phislice->Set(ifr - rmin_roi, 0, ifz - zmin_roi, ior, iophi, ioz, (*unitf) * (-1.0) * (V / (cm * C)));
2060
2061 if (!(el % percent))
2062 {
2063 std::cout << boost::str(boost::format("load_phislice_lookup %llu%%: ") % ((uint64_t) (debug_npercent) *el / percent));
2064 std::cout << boost::str(boost::format("field from (ir=%d,iphi=%d,iz=%d) to (or=%d,ophi=0,oz=%d) is (%E,%E,%E)") % ior % iophi % ioz % ifr % ifz % unitf->X() % unitf->Y() % unitf->Z()) << std::endl;
2065 }
2066 }
2067
2068 input->Close();
2069 return;
2070 }
2071
2072 void AnnularFieldSim::save_phislice_lookup(const std::string &destfile)
2073 {
2074 std::cout << boost::str(boost::format("saving phislice lookup for (%dx%dx%d)x(%dx%dx%d) grid to %s") % nr_roi % 1 % nz_roi % nr % nphi % nz % destfile) << std::endl;
2075 unsigned long long totalelements = nr;
2076 totalelements *= nphi;
2077 totalelements *= nz;
2078 totalelements *= nr_roi;
2079 totalelements *= nz_roi;
2080 unsigned long long percent = totalelements / 100 * debug_npercent;
2081 std::cout << boost::str(boost::format("total elements = %llu") % totalelements) << std::endl;
2082
2083 TFile *output = TFile::Open(destfile.c_str(), "RECREATE");
2084 output->cd();
2085
2086 TTree *tInfo = new TTree("info", "Information about Lookup Table");
2087 tInfo->Branch("rmin", &rmin);
2088 tInfo->Branch("rmax", &rmax);
2089 tInfo->Branch("zmin", &zmin);
2090 tInfo->Branch("zmax", &zmax);
2091 tInfo->Branch("rmin_roi_index", &rmin_roi);
2092 tInfo->Branch("rmax_roi_index", &rmax_roi);
2093 tInfo->Branch("zmin_roi_index", &zmin_roi);
2094 tInfo->Branch("zmax_roi_index", &zmax_roi);
2095 tInfo->Branch("nr", &nr);
2096 tInfo->Branch("nphi", &nphi);
2097 tInfo->Branch("nz", &nz);
2098 tInfo->Fill();
2099 std::cout << "info tree built." << std::endl;
2100 ;
2101
2102 TTree *tLookup = new TTree("phislice", "Phislice Lookup Table");
2103 int ior, ifr, iophi, ioz, ifz;
2104 TVector3 unitf;
2105 tLookup->Branch("ir_source", &ior);
2106 tLookup->Branch("ir_target", &ifr);
2107 tLookup->Branch("ip_source", &iophi);
2108
2109 tLookup->Branch("iz_source", &ioz);
2110 tLookup->Branch("iz_target", &ifz);
2111 tLookup->Branch("Evec", &unitf);
2112 std::cout << "lookup tree built." << std::endl;
2113 ;
2114
2115 int el = 0;
2116 for (ifr = rmin_roi; ifr < rmax_roi; ifr++)
2117 {
2118 for (ifz = zmin_roi; ifz < zmax_roi; ifz++)
2119 {
2120 for (ior = 0; ior < nr; ior++)
2121 {
2122 for (iophi = 0; iophi < nphi; iophi++)
2123 {
2124 for (ioz = 0; ioz < nz; ioz++)
2125 {
2126 el++;
2127 unitf = Epartial_phislice->Get(ifr - rmin_roi, 0, ifz - zmin_roi, ior, iophi, ioz) * (-1 / (V / (C * cm)));
2128 if (true)
2129 {
2130 if (!(el % percent))
2131 {
2132 std::cout << boost::str(boost::format("save_phislice_lookup %llu%%: ") % ((uint64_t) (debug_npercent) *el / percent));
2133 std::cout << boost::str(boost::format("field from (ir=%d,iphi=%d,iz=%d) to (or=%d,ophi=0,oz=%d) is (%E,%E,%E)") % ior % iophi % ioz % ifr % ifz % unitf.X() % unitf.Y() % unitf.Z()) << std::endl;
2134 }
2135 }
2136
2137 tLookup->Fill();
2138 }
2139 }
2140 }
2141 }
2142 }
2143 output->cd();
2144 tInfo->Write();
2145 tLookup->Write();
2146
2147 output->Close();
2148 return;
2149 }
2150
2151 void AnnularFieldSim::setFlatFields(float B, float E)
2152 {
2153
2154 std::cout << boost::str(boost::format("AnnularFieldSim::setFlatFields(B=%f Tesla,E=%f V/cm)") % B % E) << std::endl;
2155 std::cout << boost::str(boost::format("lengths: Eext=%d, Bfie=%d") % Eexternal->Length() % Bfield->Length()) << std::endl;
2156 Efieldname = "E:Flat:" + std::to_string(E);
2157 Bfieldname = "B:Flat:" + std::to_string(B);
2158
2159 Enominal = E * (V / cm);
2160 Bnominal = B * Tesla;
2161 for (int i = 0; i < Eexternal->Length(); i++)
2162 {
2163 Eexternal->GetFlat(i)->SetXYZ(0, 0, Enominal);
2164 }
2165 for (int i = 0; i < Bfield->Length(); i++)
2166 {
2167 Bfield->GetFlat(i)->SetXYZ(0, 0, Bnominal);
2168 }
2169 UpdateOmegaTau();
2170 return;
2171 }
2172
2173 TVector3 AnnularFieldSim::sum_field_at(int r, int phi, int z)
2174 {
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187 TVector3 sum(0, 0, 0);
2188 if (lookupCase == Full3D)
2189 {
2190 sum += sum_full3d_field_at(r, phi, z);
2191 }
2192 else if (lookupCase == HybridRes)
2193 {
2194 sum += sum_local_field_at(r, phi, z);
2195 sum += sum_nonlocal_field_at(r, phi, z);
2196 }
2197 else if (lookupCase == PhiSlice)
2198 {
2199 sum += sum_phislice_field_at(r, phi, z);
2200 }
2201 else if (lookupCase == Analytic)
2202 {
2203 sum += aliceModel->E(GetCellCenter(r, phi, z));
2204 }
2205 else if (lookupCase == NoLookup)
2206 {
2207
2208 }
2209 sum += Eexternal->Get(r - rmin_roi, phi - phimin_roi, z - zmin_roi);
2210 if (debugFlag())
2211 {
2212 std::cout << boost::str(boost::format("summed field at (%d,%d,%d)=(%f,%f,%f)") % r % phi % z % sum.X() % sum.Y() % sum.Z()) << std::endl;
2213 }
2214
2215 return sum;
2216 }
2217
2218 TVector3 AnnularFieldSim::sum_full3d_field_at(int r, int phi, int z)
2219 {
2220
2221
2222
2223 TVector3 sum(0, 0, 0);
2224 float rdist, phidist, zdist, remdist;
2225 for (int ir = 0; ir < nr; ir++)
2226 {
2227 if (truncation_length > 0)
2228 {
2229 rdist = std::abs(ir - r);
2230 remdist = sqrt(truncation_length * truncation_length - rdist * rdist);
2231 if (remdist < 0)
2232 {
2233 continue;
2234 }
2235 }
2236 for (int iphi = 0; iphi < nphi; iphi++)
2237 {
2238 if (truncation_length > 0)
2239 {
2240 phidist = fmin(std::abs(iphi - phi), std::abs(std::abs(iphi - phi) - nphi));
2241 remdist = sqrt(truncation_length * truncation_length - phidist * phidist);
2242 if (remdist < 0)
2243 {
2244 continue;
2245 }
2246 }
2247 for (int iz = 0; iz < nz; iz++)
2248 {
2249 if (truncation_length > 0)
2250 {
2251 zdist = std::abs(iz - z);
2252 remdist = sqrt(truncation_length * truncation_length - zdist * zdist);
2253 if (remdist < 0)
2254 {
2255 continue;
2256 }
2257 }
2258
2259 if (r == ir && phi == iphi && z == iz)
2260 {
2261 continue;
2262 }
2263 sum += Epartial->Get(r - rmin_roi, phi - phimin_roi, z - zmin_roi, ir, iphi, iz) * q->GetChargeInBin(ir, iphi, iz);
2264 }
2265 }
2266 }
2267
2268 return sum;
2269 }
2270
2271 TVector3 AnnularFieldSim::sum_local_field_at(int r, int phi, int z)
2272 {
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292 int r_highres_dist = (nr_high - 1) / 2;
2293 int phi_highres_dist = (nphi_high - 1) / 2;
2294 int z_highres_dist = (nz_high - 1) / 2;
2295
2296 int r_parentlow = std::floor((r - r_highres_dist) / (r_spacing * 1.0));
2297 int r_parenthigh = std::floor((r + r_highres_dist) / (r_spacing * 1.0)) + 1;
2298 int phi_parentlow = std::floor((phi - phi_highres_dist) / (phi_spacing * 1.0));
2299 int phi_parenthigh = std::floor((phi + phi_highres_dist) / (phi_spacing * 1.0)) + 1;
2300 int z_parentlow = std::floor((z - z_highres_dist) / (z_spacing * 1.0));
2301 int z_parenthigh = std::floor((z + z_highres_dist) / (z_spacing * 1.0)) + 1;
2302 std::cout << boost::str(boost::format("AnnularFieldSim::sum_local_field_at parents: rlow=%d,philow=%d,zlow=%d,rhigh=%d,phihigh=%d,zhigh=%d") % r_parentlow % phi_parentlow % z_parentlow % r_parenthigh % phi_parenthigh % z_parenthigh) << std::endl;
2303
2304
2305 for (int i = 0; i < q_local->Length(); i++)
2306 {
2307 *(q_local->GetFlat(i)) = 0;
2308 }
2309
2310
2311 for (int ir = r_parentlow * r_spacing; ir < r_parenthigh * r_spacing; ir++)
2312 {
2313 if (ir < 0)
2314 {
2315 ir = 0;
2316 }
2317 if (ir >= nr)
2318 {
2319 break;
2320 }
2321 int rbin = (ir - r) + r_highres_dist;
2322 if (rbin < 0)
2323 {
2324 rbin = 0;
2325 }
2326 if (rbin >= nr_high)
2327 {
2328 rbin = nr_high - 1;
2329 }
2330 for (int iphi = phi_parentlow * phi_spacing; iphi < phi_parenthigh * phi_spacing; iphi++)
2331 {
2332
2333 int phiFilt = FilterPhiIndex(iphi);
2334 int phibin = (iphi - phi) + phi_highres_dist;
2335 if (phibin < 0)
2336 {
2337 phibin = 0;
2338 }
2339 if (phibin >= nphi_high)
2340 {
2341 phibin = nphi_high - 1;
2342 }
2343 for (int iz = z_parentlow * z_spacing; iz < z_parenthigh * z_spacing; iz++)
2344 {
2345 if (iz < 0)
2346 {
2347 iz = 0;
2348 }
2349 if (iz >= nz)
2350 {
2351 break;
2352 }
2353
2354
2355 int zbin = (iz - z) + z_highres_dist;
2356 if (zbin < 0)
2357 {
2358 zbin = 0;
2359 }
2360 if (zbin >= nz_high)
2361 {
2362 zbin = nz_high - 1;
2363 }
2364
2365 q_local->Add(rbin, phibin, zbin, q->GetChargeInBin(ir, phiFilt, iz));
2366
2367 }
2368 }
2369 }
2370
2371
2372
2373
2374
2375 TVector3 sum(0, 0, 0);
2376
2377
2378
2379
2380
2381
2382
2383 for (int ir = 0; ir < nr_high; ir++)
2384 {
2385 for (int iphi = 0; iphi < nphi_high; iphi++)
2386 {
2387 for (int iz = 0; iz < nz_high; iz++)
2388 {
2389
2390 if (phi - phimin_roi < 0)
2391 {
2392 std::cout << boost::str(boost::format("%d: Getting with phi=%d") % __LINE__ % (phi - phimin_roi)) << std::endl;
2393 }
2394 sum += Epartial_highres->Get(r - rmin_roi, phi - phimin_roi, z - zmin_roi, ir, iphi, iz) * q_local->Get(ir, iphi, iz);
2395 }
2396 }
2397 }
2398
2399 return sum;
2400 }
2401
2402 TVector3 AnnularFieldSim::sum_nonlocal_field_at(int r, int phi, int z)
2403 {
2404
2405
2406
2407
2408
2409 bool skip[] = {false, false, false, false, false, false, false, false};
2410
2411 float r0 = r / (1.0 * r_spacing) - 0.5 - rmin_roi_low;
2412 int r0i = std::floor(r0);
2413 float r0d = r0 - r0i;
2414
2415 int ri[2];
2416 ri[0] = r0i;
2417 ri[1] = r0i + 1;
2418 float rw[2];
2419 rw[0] = 1 - r0d;
2420 rw[1] = r0d;
2421
2422
2423 if (ri[0] < 0)
2424 {
2425 for (int i = 0; i < 8; i++)
2426 {
2427 if ((i / 4) % 2 == 0)
2428 {
2429 skip[i] = true;
2430 }
2431 }
2432 rw[1] = 1;
2433 }
2434 if (ri[1] >= nr_roi_low)
2435 {
2436 for (int i = 0; i < 8; i++)
2437 {
2438 if ((i / 4) % 2 == 1)
2439 {
2440 skip[i] = true;
2441 }
2442 }
2443 rw[0] = 1;
2444 }
2445
2446
2447
2448 float p0 = phi / (1.0 * phi_spacing) - 0.5 - phimin_roi_low;
2449
2450
2451 int p0i = std::floor(p0);
2452 float p0d = p0 - p0i;
2453 int pi[4];
2454
2455
2456
2457
2458 pi[0] = FilterPhiIndex(p0i, nphi_low);
2459 pi[1] = FilterPhiIndex(p0i + 1, nphi_low);
2460
2461
2462
2463 float pw[2];
2464 pw[0] = 1 - p0d;
2465 pw[1] = p0d;
2466
2467
2468
2469 if (pi[0] >= nphi_roi_low)
2470 {
2471 for (int i = 0; i < 8; i++)
2472 {
2473 if ((i / 2) % 2 == 0)
2474 {
2475 skip[i] = true;
2476 }
2477 }
2478 pw[1] = 1;
2479 }
2480 if (pi[1] >= nphi_roi_low)
2481 {
2482 for (int i = 0; i < 8; i++)
2483 {
2484 if ((i / 2) % 2 == 1)
2485 {
2486 skip[i] = true;
2487 }
2488 }
2489 pw[0] = 1;
2490 }
2491
2492
2493
2494 float z0 = z / (1.0 * z_spacing) - 0.5 - zmin_roi_low;
2495 int z0i = std::floor(z0);
2496 float z0d = z0 - z0i;
2497
2498 int zi[2];
2499 zi[0] = z0i;
2500 zi[1] = z0i + 1;
2501 float zw[2];
2502 zw[0] = 1 - z0d;
2503 zw[1] = z0d;
2504
2505 if (zi[0] < 0)
2506 {
2507 for (int i = 0; i < 8; i++)
2508 {
2509 if ((i) % 2 == 0)
2510 {
2511 skip[i] = true;
2512 }
2513 }
2514 zw[1] = 1;
2515 }
2516 if (zi[1] >= nz_roi_low)
2517 {
2518 for (int i = 0; i < 8; i++)
2519 {
2520 if ((i) % 2 == 1)
2521 {
2522 skip[i] = true;
2523 }
2524 }
2525 zw[0] = 1;
2526 }
2527
2528 TVector3 sum(0, 0, 0);
2529
2530
2531 int lBinEdge[2];
2532 int hRegionEdge[2];
2533 bool overlapsPhi, overlapsZ;
2534
2535 int r_highres_dist = (nr_high - 1) / 2;
2536 int phi_highres_dist = (nphi_high - 1) / 2;
2537 int z_highres_dist = (nz_high - 1) / 2;
2538
2539 for (int ir = 0; ir < nr_low; ir++)
2540 {
2541 lBinEdge[0] = ir * r_spacing;
2542 lBinEdge[1] = (ir + 1) * r_spacing - 1;
2543 hRegionEdge[0] = r - r_highres_dist;
2544 hRegionEdge[1] = r + r_highres_dist;
2545 bool overlapsR = (lBinEdge[0] <= hRegionEdge[1] && hRegionEdge[0] <= lBinEdge[1]);
2546 for (int iphi = 0; iphi < nphi_low; iphi++)
2547 {
2548 lBinEdge[0] = iphi * phi_spacing;
2549 lBinEdge[1] = (iphi + 1) * phi_spacing - 1;
2550 hRegionEdge[0] = phi - phi_highres_dist;
2551 hRegionEdge[1] = phi + phi_highres_dist;
2552 overlapsPhi = (lBinEdge[0] <= hRegionEdge[1] && hRegionEdge[0] <= lBinEdge[1]);
2553 for (int iz = 0; iz < nz_low; iz++)
2554 {
2555 lBinEdge[0] = iz * z_spacing;
2556 lBinEdge[1] = (iz + 1) * z_spacing - 1;
2557 hRegionEdge[0] = z - z_highres_dist;
2558 hRegionEdge[1] = z + z_highres_dist;
2559 overlapsZ = (lBinEdge[0] <= hRegionEdge[1] && hRegionEdge[0] <= lBinEdge[1]);
2560
2561
2562
2563 if (overlapsR && overlapsPhi && overlapsZ)
2564 {
2565
2566 continue;
2567 }
2568 else
2569 {
2570
2571
2572 for (int i = 0; i < 8; i++)
2573 {
2574 if (skip[i])
2575 {
2576 continue;
2577 }
2578 if (ri[(i / 4) % 2] + rmin_roi_low == ir && pi[(i / 2) % 2] + phimin_roi_low == iphi && zi[(i) % 2] + zmin_roi_low == iz)
2579 {
2580 std::cout << boost::str(boost::format("considering an l-bins effect on itself, r=%d,phi=%d,z=%d (matches i=%d, not skipped), means we're not interpolating fairly") % ir % iphi % iz % i) << std::endl;
2581 exit(1);
2582 }
2583
2584
2585 if (pi[(i / 2) % 2] < 0)
2586 {
2587 std::cout << boost::str(boost::format("%d: Getting with phi=%d") % __LINE__ % (pi[(i / 2) % 2])) << std::endl;
2588 }
2589 sum += (Epartial_lowres->Get(ri[(i / 4) % 2], pi[(i / 2) % 2], zi[(i) % 2], ir, iphi, iz) * q_lowres->Get(ir, iphi, iz)) * zw[(i) % 2] * pw[(i / 2) % 2] * rw[(i / 4) % 2];
2590 }
2591 }
2592 }
2593 }
2594 }
2595
2596 return sum;
2597 }
2598
2599 TVector3 AnnularFieldSim::sum_phislice_field_at(int r, int phi, int z)
2600 {
2601
2602
2603
2604 TVector3 pos = GetRoiCellCenter(r - rmin_roi, phi - phimin_roi, z - zmin_roi);
2605 TVector3 slicepos = GetRoiCellCenter(r - rmin_roi, 0, z - zmin_roi);
2606 float rotphi = pos.Phi() - slicepos.Phi();
2607
2608
2609
2610
2611
2612
2613
2614 TVector3 sum(0, 0, 0);
2615 TVector3 unrotatedField(0, 0, 0);
2616 TVector3 unitField(0, 0, 0);
2617 int phirel;
2618 for (int ir = 0; ir < nr; ir++)
2619 {
2620 for (int iphi = 0; iphi < nphi; iphi++)
2621 {
2622 for (int iz = 0; iz < nz; iz++)
2623 {
2624
2625 if (r == ir && phi == iphi && z == iz)
2626 {
2627 continue;
2628 }
2629 phirel = FilterPhiIndex(iphi - phi);
2630 unitField = Epartial_phislice->Get(r - rmin_roi, 0, z - zmin_roi, ir, phirel, iz);
2631 unitField.RotateZ(rotphi);
2632
2633 sum += unitField * q->GetChargeInBin(ir, iphi, iz);
2634 ;
2635
2636
2637
2638
2639
2640
2641
2642
2643 }
2644 }
2645 }
2646
2647 return sum;
2648 }
2649
2650 TVector3 AnnularFieldSim::swimToInAnalyticSteps(float zdest, TVector3 start, int steps = 1, int *goodToStep = nullptr)
2651 {
2652
2653 double zdist = (zdest - start.Z()) * cm;
2654 double zstep = zdist / steps;
2655 start = start * cm;
2656
2657 TVector3 ret = start;
2658 TVector3 accumulated_distortion(0, 0, 0);
2659 TVector3 accumulated_drift(0, 0, 0);
2660 TVector3 drift_step(0, 0, zstep);
2661
2662 int rt, pt, zt;
2663 BoundsCase zBound;
2664 for (int i = 0; i < steps; i++)
2665 {
2666 zBound = GetZindexAndCheckBounds(ret.Z(), &zt);
2667 if (zBound == OnLowEdge)
2668 {
2669
2670 ret.SetZ(ret.Z() + ALMOST_ZERO);
2671 }
2672 if (GetRindexAndCheckBounds(ret.Perp(), &rt) != InBounds || GetPhiIndexAndCheckBounds(FilterPhiPos(ret.Phi()), &pt) != InBounds || (zBound == OutOfBounds))
2673 {
2674 std::cout << boost::str(boost::format(
2675 "AnnularFieldSim::swimToInAnalyticSteps at step %d asked to swim particle from (%f,%f,%f)(cm) (rphiz)=(%fcm,%frad,%fcm)which is outside the ROI.") %
2676 i % (ret.X() / cm) % (ret.Y() / cm) % (ret.Z() / cm) % (ret.Perp() / cm) % ret.Phi() % (ret.Z() / cm))
2677 << std::endl;
2678 std::cout << boost::str(boost::format(" -- %f <= r < %f \t%f <= phi < %f \t%f <= z < %f ") % (rmin_roi * step.Perp() + rmin) % (rmax_roi * step.Perp() + rmin) % (phimin_roi * step.Phi()) % (phimax_roi * step.Phi()) % (zmin_roi * step.Z()) % (zmax_roi * step.Z())) << std::endl;
2679 std::cout << "Returning last valid position." << std::endl;
2680 ;
2681 if (!(goodToStep == nullptr))
2682 {
2683 *goodToStep = i - 1;
2684 }
2685 return ret * (1.0 / cm);
2686 }
2687
2688
2689 accumulated_distortion += GetStepDistortion(ret.Z() + zstep, ret, true, true);
2690
2691 accumulated_drift += drift_step;
2692
2693
2694 ret = start + accumulated_distortion + accumulated_drift;
2695 }
2696
2697 return ret * (1.0 / cm);
2698 }
2699
2700 TVector3 AnnularFieldSim::swimToInSteps(float zdest, const TVector3 &start, int steps = 1, bool interpolate = false, int *goodToStep = nullptr)
2701 {
2702 int *success = nullptr;
2703 TVector3 straightline(start.X(), start.Y(), zdest);
2704 TVector3 distortion = GetTotalDistortion(zdest, start, steps, interpolate, goodToStep, success);
2705 return straightline + distortion;
2706 }
2707
2708
2709 TVector3 AnnularFieldSim::GetTotalDistortion(float zdest, const TVector3 &start, int steps, bool interpolate, int *goodToStep, int *success)
2710 {
2711
2712
2713
2714
2715
2716 int rt, pt, zt;
2717 BoundsCase zBound;
2718 zBound = GetZindexAndCheckBounds(zdest, &zt);
2719 bool rdrswitch = RdeltaRswitch;
2720 if (success)
2721 {
2722 *success = 0;
2723 }
2724 if (zBound == OutOfBounds)
2725 {
2726 if (hasTwin)
2727 {
2728 zBound = GetZindexAndCheckBounds(-zdest, &zt);
2729 if (zBound == InBounds || zBound == OnLowEdge)
2730 {
2731
2732 return twin->GetTotalDistortion(zdest, start, steps, interpolate, goodToStep, success);
2733 }
2734 }
2735
2736 std::cout << boost::str(boost::format("AnnularFieldSim::GetTotalDistortion starting at (%f,%f,%f)=(r%f,p%f,z%f) asked to drift to z=%f, which is outside the ROI. hasTwin= %d. Returning zero_vector.") % start.X() % start.Y() % start.Z() % start.Perp() % FilterPhiPos(start.Phi()) % start.Z() % zdest % (int) hasTwin) << std::endl;
2737 std::cout << boost::str(boost::format(" -- %f <= r < %f \t%f <= phi < %f \t%f <= z < %f ") % (rmin_roi * step.Perp() + rmin) % (rmax_roi * step.Perp() + rmin) % (phimin_roi * step.Phi()) % (phimax_roi * step.Phi()) % (zmin_roi * step.Z()) % (zmax_roi * step.Z())) << std::endl;
2738 *goodToStep = 0;
2739 *success = 0;
2740 return zero_vector;
2741 }
2742 else if (zBound == OnLowEdge)
2743 {
2744
2745 zdest += ALMOST_ZERO;
2746 }
2747 zBound = GetZindexAndCheckBounds(start.Z(), &zt);
2748 if (zBound == OutOfBounds)
2749 {
2750 std::cout << boost::str(boost::format("AnnularFieldSim::GetTotalDistortion starting at (%f,%f,%f)=(r%f,p%f,z%f) asked to drift from z=%f, which is outside the ROI. Returning zero_vector.") % start.X() % start.Y() % start.Z() % start.Perp() % FilterPhiPos(start.Phi()) % start.Z() % start.Z()) << std::endl;
2751 std::cout << boost::str(boost::format(" -- %f <= r < %f \t%f <= phi < %f \t%f <= z < %f ") % (rmin_roi * step.Perp() + rmin) % (rmax_roi * step.Perp() + rmin) % (phimin_roi * step.Phi()) % (phimax_roi * step.Phi()) % (zmin_roi * step.Z()) % (zmax_roi * step.Z())) << std::endl;
2752 *goodToStep = 0;
2753 *success = 0;
2754 return zero_vector;
2755 }
2756 else if (zBound == OnLowEdge)
2757 {
2758
2759 zdest += ALMOST_ZERO;
2760 }
2761
2762
2763
2764 double zstep = (zmax - zmin) / steps;
2765
2766
2767
2768
2769 if ((zdest - start.Z()) < 0)
2770 {
2771 zstep = -zstep;
2772 }
2773 int integernumbersteps = (zdest - start.Z()) / zstep;
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784 TVector3 position = start;
2785 TVector3 accumulated_distortion(0, 0, 0);
2786 TVector3 accumulated_drift(0, 0, 0);
2787 TVector3 drift_step(0, 0, zstep);
2788
2789
2790
2791
2792
2793
2794
2795 accumulated_distortion += GetStepDistortion(zdest - (integernumbersteps * zstep), position, true, false);
2796
2797
2798
2799 position.SetX(start.X() + accumulated_distortion.X());
2800 position.SetY(start.Y() + accumulated_distortion.Y());
2801 position.SetZ(zdest - (integernumbersteps * zstep));
2802
2803 float StartR, FinalR;
2804 float DeltaR;
2805 for (int i = 0; i < integernumbersteps; i++)
2806 {
2807 if (GetRindexAndCheckBounds(position.Perp(), &rt) != InBounds || GetPhiIndexAndCheckBounds(FilterPhiPos(position.Phi()), &pt) != InBounds || (zBound == OutOfBounds))
2808 {
2809
2810
2811
2812 if (!(goodToStep == nullptr))
2813 {
2814 *goodToStep = i - 1, *success = 0;
2815 }
2816
2817 return (accumulated_distortion);
2818 }
2819
2820 StartR = position.Perp();
2821
2822 accumulated_distortion += GetStepDistortion(position.Z() + zstep, position, true, false);
2823 position.SetX(start.X() + accumulated_distortion.X());
2824 position.SetY(start.Y() + accumulated_distortion.Y());
2825 FinalR = position.Perp();
2826
2827
2828
2829
2830 DeltaR = FinalR - StartR;
2831 if (rdrswitch)
2832 {
2833 hRdeltaRComponent->Fill(StartR, DeltaR);
2834 }
2835 position.SetZ(position.Z() + zstep);
2836 }
2837 if (GetRindexAndCheckBounds(position.Perp(), &rt) != InBounds || GetPhiIndexAndCheckBounds(FilterPhiPos(position.Phi()), &pt) != InBounds || (zBound == OutOfBounds))
2838 {
2839 *goodToStep = integernumbersteps - 1;
2840 *success = 0;
2841 return (accumulated_distortion);
2842 }
2843 *goodToStep = integernumbersteps;
2844 *success = 1;
2845 return accumulated_distortion;
2846 }
2847
2848 void AnnularFieldSim::PlotFieldSlices(const std::string &filebase, const TVector3 &pos, char which)
2849 {
2850 bool mapEfield = true;
2851 if (which == 'B')
2852 {
2853 mapEfield = false;
2854 }
2855 which = mapEfield ? 'E' : 'B';
2856 std::string units;
2857 if (mapEfield)
2858 {
2859 units = "V/cm";
2860 }
2861 else
2862 {
2863 units = "T";
2864 }
2865
2866 std::cout << boost::str(boost::format("plotting field slices for %c field, slicing at (%1.2F,%1.2f,%1.2f)...") % which % pos.Perp() % FilterPhiPos(pos.Phi()) % pos.Z()) << std::endl;
2867 std::cout << "file=" << filebase << std::endl;
2868 ;
2869 std::string plotfilename = filebase + "." + which + "field_slices.pdf";
2870 TVector3 inner = GetInnerEdge();
2871 TVector3 outer = GetOuterEdge();
2872 TVector3 steplocal = GetFieldStep();
2873
2874 TCanvas *c;
2875
2876 TH2F *hEfield[3][3];
2877 TH2F *hCharge[3];
2878 TH1F *hEfieldComp[3][3];
2879 std::string axis[] = {"r", "p", "z", "r", "p", "z"};
2880 float axisval[] = {(float) pos.Perp(), (float) FilterPhiPos(pos.Phi()), (float) pos.Z(), (float) pos.Perp(), (float) FilterPhiPos(pos.Phi()), (float) pos.Z()};
2881 int axn[] = {nr_roi, nphi_roi, nz_roi, nr_roi, nphi_roi, nz_roi};
2882 float axtop[] = {(float) outer.Perp(), 2 * M_PI, (float) outer.Z(), (float) outer.Perp(), 2 * M_PI, (float) outer.Z()};
2883 float axbot[] = {(float) inner.Perp(), 0, (float) inner.Z(), (float) inner.Perp(), 0, (float) inner.Z()};
2884
2885
2886 if (hasTwin)
2887 {
2888
2889 axbot[2] = axbot[5] = (float) (twin->GetInnerEdge().Z());
2890 }
2891 std::cout << boost::str(boost::format("rpz bounds are %f<r%f\t %f<phi%f\t %f<z%f") % axbot[0] % axtop[0] % axbot[1] % axtop[1] % axbot[2] % axtop[2]) << std::endl;
2892 float axstep[6];
2893 for (int i = 0; i < 6; i++)
2894 {
2895 axstep[i] = (axtop[i] - axbot[i]) / (1.0 * axn[i]);
2896 }
2897 TVector3 field;
2898 TVector3 lpos;
2899
2900
2901 for (int ax = 0; ax < 3; ax++)
2902 {
2903
2904 hCharge[ax] = new TH2F(std::string("hCharge" + axis[ax]).c_str(),
2905 boost::str(boost::format("Spacecharge Distribution in the %s%s plane at %s=%2.3f (C/cm^3);%s;%s") % axis[ax + 1] % axis[ax + 2] % axis[ax] % axisval[ax] % axis[ax + 1] % axis[ax + 2]).c_str(),
2906 axn[ax + 1], axbot[ax + 1], axtop[ax + 1],
2907 axn[ax + 2], axbot[ax + 2], axtop[ax + 2]);
2908 for (int i = 0; i < 3; i++)
2909 {
2910
2911 hEfield[ax][i] = new TH2F(boost::str(boost::format("h%sfield%s_%s%s") % which % axis[i] % axis[ax + 1] % axis[ax + 2]).c_str(),
2912 boost::str(boost::format("%s component of %s Field in the %s%s plane at %s=%2.3f (%s);%s;%s") % axis[i] % which % axis[ax + 1] % axis[ax + 2] % axis[ax] % axisval[ax] % units.c_str() % axis[ax + 1] % axis[ax + 2]).c_str(),
2913 axn[ax + 1], axbot[ax + 1], axtop[ax + 1],
2914 axn[ax + 2], axbot[ax + 2], axtop[ax + 2]);
2915 hEfieldComp[ax][i] = new TH1F(boost::str(boost::format("h%sfieldComp%s_%s%s") % which % axis[i] % axis[ax + 1] % axis[ax + 2]).c_str(),
2916 boost::str(boost::format("Log Magnitude of %s component of %s Field in the %s%s plane at %s=%2.3f;log10(mag)") % axis[i] % which % axis[ax + 1] % axis[ax + 2] % axis[ax] % axisval[ax]).c_str(),
2917 200, -5, 5);
2918 }
2919 }
2920
2921 float rpz_coord[3];
2922 for (int ax = 0; ax < 3; ax++)
2923 {
2924 rpz_coord[ax] = axisval[ax] + axstep[ax] / 2;
2925 for (int i = 0; i < axn[ax + 1]; i++)
2926 {
2927 rpz_coord[(ax + 1) % 3] = axbot[ax + 1] + (i + 0.5) * axstep[ax + 1];
2928 for (int j = 0; j < axn[ax + 2]; j++)
2929 {
2930 rpz_coord[(ax + 2) % 3] = axbot[ax + 2] + (j + 0.5) * axstep[ax + 2];
2931 lpos.SetXYZ(rpz_coord[0], 0, rpz_coord[2]);
2932 lpos.SetPhi(rpz_coord[1]);
2933 if (false && ax == 0)
2934 {
2935 std::cout << boost::str(boost::format("sampling rpz=(%f,%f,%f)=(%f,%f,%f) after conversion to xyz=(%f,%f,%f)") % rpz_coord[0] % rpz_coord[1] % rpz_coord[2] % lpos.Perp() % (FilterPhiPos(lpos.Phi())) % lpos.Z() % lpos.X() % lpos.Y() % lpos.Z()) << std::endl;
2936 }
2937 if (mapEfield)
2938 {
2939
2940 field = GetFieldAt(lpos) * (1.0 * cm / V);
2941 }
2942 else
2943 {
2944 field = GetBFieldAt(lpos) * (1.0 / Tesla);
2945
2946 }
2947 field.RotateZ(-rpz_coord[1]);
2948
2949 hEfield[ax][0]->Fill(rpz_coord[(ax + 1) % 3], rpz_coord[(ax + 2) % 3], field.X());
2950 hEfield[ax][1]->Fill(rpz_coord[(ax + 1) % 3], rpz_coord[(ax + 2) % 3], field.Y());
2951 hEfield[ax][2]->Fill(rpz_coord[(ax + 1) % 3], rpz_coord[(ax + 2) % 3], field.Z());
2952 hCharge[ax]->Fill(rpz_coord[(ax + 1) % 3], rpz_coord[(ax + 2) % 3], GetChargeAt(lpos));
2953 hEfieldComp[ax][0]->Fill((std::abs(field.X())));
2954 hEfieldComp[ax][1]->Fill((std::abs(field.Y())));
2955 hEfieldComp[ax][2]->Fill((std::abs(field.Z())));
2956 }
2957 }
2958 }
2959
2960 c = new TCanvas("cfieldslices", "electric field", 1200, 800);
2961 c->Divide(4, 3);
2962 gStyle->SetOptStat();
2963 for (int ax = 0; ax < 3; ax++)
2964 {
2965 for (int i = 0; i < 3; i++)
2966 {
2967 c->cd(ax * 4 + i + 1);
2968 gPad->SetRightMargin(0.15);
2969 hEfield[ax][i]->SetStats(false);
2970 hEfield[ax][i]->Draw("colz");
2971
2972 gPad->Modified();
2973
2974 }
2975 c->cd(ax * 4 + 4);
2976 gPad->SetRightMargin(0.15);
2977 hCharge[ax]->SetStats(false);
2978 hCharge[ax]->Draw("colz");
2979
2980 if (false)
2981 {
2982
2983
2984 gPad->Modified();
2985 }
2986 }
2987 c->SaveAs(plotfilename.c_str());
2988 std::cout << "after plotting field slices..." << std::endl;
2989 std::cout << "file=" << filebase << std::endl;
2990
2991 return;
2992 }
2993
2994 void AnnularFieldSim::GenerateSeparateDistortionMaps(const std::string &filebase, int nSteps, int r_subsamples, int p_subsamples, int z_subsamples, int , bool andCartesian)
2995 {
2996
2997
2998
2999
3000 TVector3 steplocal(step.Perp() / r_subsamples, 0, step.Z() / z_subsamples);
3001 steplocal.SetPhi(step.Phi() / p_subsamples);
3002 float deltar = steplocal.Perp();
3003 float deltap = steplocal.Phi();
3004 float deltaz = steplocal.Z();
3005 bool rdrswitch = RdeltaRswitch;
3006 TVector3 stepzvec(0, 0, deltaz);
3007
3008
3009
3010 int nSides = 1;
3011 if (hasTwin)
3012 {
3013 nSides = 2;
3014 }
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024 TVector3 lowerEdge = GetRoiCellCenter(rmin_roi, phimin_roi, zmin_roi);
3025 TVector3 upperEdge = GetRoiCellCenter(rmax_roi - 1, phimax_roi - 1, zmax_roi - 1);
3026 int nph = nphi * p_subsamples + 2;
3027 int nrh = nr * r_subsamples + 2;
3028 int nzh = nz * z_subsamples + 2;
3029
3030 float rih = lowerEdge.Perp() - 0.5 * step.Perp() - steplocal.Perp();
3031 float rfh = upperEdge.Perp() + 0.5 * step.Perp() + steplocal.Perp();
3032 float pih = FilterPhiPos(lowerEdge.Phi()) - 0.5 * step.Phi() - steplocal.Phi();
3033 float pfh = FilterPhiPos(upperEdge.Phi()) + 0.5 * step.Phi() + steplocal.Phi();
3034 float zih = lowerEdge.Z() - 0.5 * step.Z() - steplocal.Z();
3035 float zfh = upperEdge.Z() + 0.5 * step.Z() + steplocal.Z();
3036 float z_readout = upperEdge.Z() + 0.5 * step.Z();
3037
3038 std::cout << "generating distortion map..." << std::endl;
3039 std::cout << "file=" << filebase << std::endl;
3040 std::cout << boost::str(boost::format("Phi: %d steps from %f to %f (field has %d steps)") % nph % pih % pfh % GetFieldStepsPhi()) << std::endl;
3041 std::cout << boost::str(boost::format("R: %d steps from %f to %f (field has %d steps)") % nrh % rih % rfh % GetFieldStepsR()) << std::endl;
3042 std::cout << boost::str(boost::format("Z: %d steps from %f to %f (field has %d steps)") % nzh % zih % zfh % GetFieldStepsZ()) << std::endl;
3043 std::string distortionFilename = filebase + ".distortion_map.hist.root";
3044 std::string summaryFilename = filebase + "distortion_summary.pdf";
3045 std::string diffSummaryFilename = filebase + "differential_summary.pdf";
3046
3047 TFile *outf = TFile::Open(distortionFilename.c_str(), "RECREATE");
3048 outf->cd();
3049
3050
3051
3052 TH3F *hDistortionR = new TH3F("hDistortionR", "Per-z-bin Distortion in the R direction as a function of (phi,r,z) (centered in r,phi, z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3053 TH3F *hDistortionP = new TH3F("hDistortionP", "Per-z-bin Distortion in the RPhi direction as a function of (phi,r,z) (centered in r,phi, z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3054 TH3F *hDistortionZ = new TH3F("hDistortionZ", "Per-z-bin Distortion in the Z direction as a function of (phi,r,z) (centered in r,phi, z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3055 TH3F *hIntDistortionR = new TH3F("hIntDistortionR", "Integrated R Distortion from (phi,r,z) to z=0 (centered in r,phi, and z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3056 TH3F *hIntDistortionP = new TH3F("hIntDistortionP", "Integrated R Distortion from (phi,r,z) to z=0 (centered in r,phi, and z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3057 TH3F *hIntDistortionZ = new TH3F("hIntDistortionZ", "Integrated R Distortion from (phi,r,z) to z=0 (centered in r,phi, and z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3058
3059 TH3F *hIntDistortionX = new TH3F("hIntDistortionX", "Integrated X Distortion from (phi,r,z) to z=0 (centered in r,phi, and z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3060 TH3F *hIntDistortionY = new TH3F("hIntDistortionY", "Integrated Y Distortion from (phi,r,z) to z=0 (centered in r,phi, and z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3061
3062 const int nMapComponents = 6;
3063 TH3F *hSeparatedMapComponent[2][6];
3064 TH3F *hValidToStepComponent[2];
3065 TH3F *hReachesReadout[2];
3066 std::string side[2];
3067 side[0] = "soloz";
3068 if (hasTwin)
3069 {
3070 side[0] = "posz";
3071 side[1] = "negz";
3072 }
3073 std::string sepAxis[] = {"X", "Y", "Z", "R", "P", "RPhi"};
3074 float zlower, zupper;
3075 for (int i = 0; i < nSides; i++)
3076 {
3077 if (i == 0)
3078 {
3079 zlower = fmin(zih, zfh);
3080 zupper = fmax(zih, zfh);
3081 }
3082 else
3083 {
3084 zlower = -1 * fmax(zih, zfh);
3085 zupper = -1 * fmin(zih, zfh);
3086 }
3087 for (int j = 0; j < nMapComponents; j++)
3088 {
3089 hSeparatedMapComponent[i][j] = new TH3F(std::string("hIntDistortion" + sepAxis[j] + "_" + side[i]).c_str(),
3090 std::string("Integrated" + sepAxis[j] + " Deflection drifting from (phi,r,z) to z=endcap;phi;r;z (" + side[i] + " side)").c_str(),
3091 nph, pih, pfh, nrh, rih, rfh, nzh, zlower, zupper);
3092 }
3093 hValidToStepComponent[i] = new TH3F(std::string("hValidToStep_" + side[i]).c_str(),
3094 std::string("Step before out of bounds drifting from (phi,r,z) to z=endcap;phi;r;z (" + side[i] + " side)").c_str(),
3095 nph, pih, pfh, nrh, rih, rfh, nzh, zlower, zupper);
3096 hReachesReadout[i] = new TH3F(std::string("hReachesReadout_" + side[i]).c_str(),
3097 std::string("Bool value for checking if successfuly drifting from (phi,r,z) to z=endcap and reaches the readout;phi;r;z (" + side[i] + " side)").c_str(),
3098 nph, pih, pfh, nrh, rih, rfh, nzh, zlower, zupper);
3099 }
3100 if (rdrswitch)
3101 {
3102 hRdeltaRComponent = new TH2F("hRdeltaR", "Bool value of input for a 2D R_versus_deltaR plot from Zstart to Zend;R;deltaR", nrh, rih, rfh, 10 * nrh, rih - 70, rfh + 170);
3103
3104 twin->hRdeltaRComponent = hRdeltaRComponent;
3105 }
3106
3107
3108
3109 TVector3 pos(((int) (nrh / 2) + 0.5) * steplocal.Perp() + rih, 0, zmin + ((int) (nz / 2) + 0.5) * step.Z());
3110 float posphi = ((int) (nph / 2) + 0.5) * steplocal.Phi() + pih;
3111 pos.SetPhi(posphi);
3112
3113 int xi[3] = {(int) std::floor((pos.Perp() - rih) / steplocal.Perp()), (int) std::floor((posphi - pih) / steplocal.Phi()), (int) std::floor((pos.Z() - zih) / steplocal.Z())};
3114 if (!hasTwin)
3115 {
3116 std::cout << boost::str(boost::format("rpz slice indices= (%d,%d,%d) (no twin)") % xi[0] % xi[1] % xi[2]) << std::endl;
3117 }
3118 int twinz = (-pos.Z() - zih) / steplocal.Z();
3119 if (hasTwin)
3120 {
3121 std::cout << boost::str(boost::format("rpz slice indices= (%d,%d,%d) twinz=%d") % xi[0] % xi[1] % xi[2] % twinz) << std::endl;
3122 }
3123
3124 const std::string axname[] = {"r", "p", "z", "r", "p", "z"};
3125 int axn[] = {nrh, nph, nzh, nrh, nph, nzh};
3126 float axval[] = {(float) pos.Perp(), (float) pos.Phi(), (float) pos.Z(), (float) pos.Perp(), (float) pos.Phi(), (float) pos.Z()};
3127 float axbot[] = {rih, pih, zih, rih, pih, zih};
3128 float axtop[] = {rfh, pfh, zfh, rfh, pfh, zfh};
3129 TH2F *hIntDist[3][3];
3130 TH1F *hRDist[2][3];
3131 TH2F *hDiffDist[3][3];
3132 TH1F *hRDiffDist[2][3];
3133 for (int i = 0; i < 3; i++)
3134 {
3135
3136 for (int ax = 0; ax < 3; ax++)
3137 {
3138
3139 hDiffDist[ax][i] = new TH2F(std::string("hDiffDist" + axname[i] + "_" + axname[ax + 1] + axname[ax + 2]).c_str(),
3140 boost::str(boost::format("%s component of diff. distortion in %s%s plane at %s=%2.3f;%s;%s") % axname[i] % axname[ax + 1] % axname[ax + 2] % axname[ax] % axval[ax] % axname[ax + 1] % axname[ax + 2]).c_str(),
3141 axn[ax + 1], axbot[ax + 1], axtop[ax + 1],
3142 axn[ax + 2], axbot[ax + 2], axtop[ax + 2]);
3143 hIntDist[ax][i] = new TH2F(std::string("hIntDist" + axname[i] + "_" + axname[ax + 1] + axname[ax + 2]).c_str(),
3144 boost::str(boost::format("%s component of int. distortion in %s%s plane at %s=%2.3f;%s;%s") % axname[i] % axname[ax + 1] % axname[ax + 2] % axname[ax] % axval[ax] % axname[ax + 1] % axname[ax + 2]).c_str(),
3145 axn[ax + 1], axbot[ax + 1], axtop[ax + 1],
3146 axn[ax + 2], axbot[ax + 2], axtop[ax + 2]);
3147 }
3148 hRDist[0][i] = new TH1F(std::string("hRDist" + axname[i]).c_str(),
3149 boost::str(boost::format("%s component of int. distortion vs r with %s=%2.3f and %s=%2.3f;r(cm);#delta (cm)") % axname[i] % axname[1] % axval[1] % axname[2] % axval[2]).c_str(),
3150 axn[0], axbot[0], axtop[0]);
3151 hRDist[1][i] = new TH1F(std::string("hRDist" + axname[i] + "Neg").c_str(),
3152 boost::str(boost::format("%s component of int. distortion vs r with %s=%2.3f and %s=-%2.3f;r(cm);#delta (cm)") % axname[i] % axname[1] % axval[1] % axname[2] % axval[2]).c_str(),
3153 axn[0], axbot[0], axtop[0]);
3154 hRDiffDist[0][i] = new TH1F(std::string("hRDiffDist" + axname[i]).c_str(),
3155 boost::str(boost::format("%s component of diff. distortion vs r with %s=%2.3f and %s=%2.3f;r(cm);#delta (cm)") % axname[i] % axname[1] % axval[1] % axname[2] % axval[2]).c_str(),
3156 axn[0], axbot[0], axtop[0]);
3157 hRDiffDist[1][i] = new TH1F(std::string("hRDiffDist" + axname[i] + "Neg").c_str(),
3158 boost::str(boost::format("%s component of diff. distortion vs r with %s=%2.3f and %s=-%2.3f;r(cm);#delta (cm)") % axname[i] % axname[1] % axval[1] % axname[2] % axval[2]).c_str(),
3159 axn[0], axbot[0], axtop[0]);
3160 }
3161
3162 TVector3 inpart, outpart;
3163 TVector3 diffdistort, distort;
3164 int validToStep;
3165 int successCheck;
3166
3167
3168 float partR, partP, partZ;
3169 int ir, ip, iz;
3170 float distortR, distortP, distortZ;
3171 float distortX, distortY;
3172 float diffdistR, diffdistP, diffdistZ;
3173 TTree *dTree = new TTree("dTree", "Distortion per step z");
3174 dTree->Branch("r", &partR);
3175 dTree->Branch("p", &partP);
3176 dTree->Branch("z", &partZ);
3177 dTree->Branch("ir", &ir);
3178 dTree->Branch("ip", &ip);
3179 dTree->Branch("iz", &iz);
3180 dTree->Branch("dr", &distortR);
3181 dTree->Branch("drp", &distortP);
3182 dTree->Branch("dz", &distortZ);
3183
3184 std::cout << boost::str(boost::format("generating separated distortion map with (%dx%dx%d) grid ") % nrh % nph % nzh) << std::endl;
3185 unsigned long long totalelements = nrh;
3186 totalelements *= nph;
3187 totalelements *= nzh;
3188 if (hasTwin)
3189 {
3190 totalelements *= 2;
3191 }
3192
3193 unsigned long long percent = totalelements / 100;
3194 unsigned long long waypoint = percent * debug_npercent;
3195 std::cout << boost::str(boost::format("total elements = %llu") % totalelements) << std::endl;
3196
3197 int el = 0;
3198
3199
3200
3201
3202
3203
3204
3205
3206 inpart.SetXYZ(1, 0, 0);
3207 for (ir = 0; ir < nrh; ir++)
3208 {
3209 partR = (ir + 0.5) * deltar + rih;
3210 if (ir == 0)
3211 {
3212 inpart.SetPerp(partR + deltar);
3213 }
3214 else if (ir == nrh - 1)
3215 {
3216 inpart.SetPerp(partR - deltar);
3217 }
3218 else
3219 {
3220 inpart.SetPerp(partR);
3221 }
3222 for (ip = 0; ip < nph; ip++)
3223 {
3224 partP = (ip + 0.5) * deltap + pih;
3225 inpart.SetPhi(partP);
3226
3227 for (iz = 0; iz < nzh; iz++)
3228 {
3229 partZ = (iz) *deltaz + zih;
3230 if (iz == 0)
3231 {
3232 inpart.SetZ(partZ + deltaz);
3233 }
3234 else if (iz == nzh - 1)
3235 {
3236 inpart.SetZ(partZ - deltaz);
3237 }
3238 else
3239 {
3240 inpart.SetZ(partZ);
3241 }
3242 partZ += 0.5 * deltaz;
3243 for (int localside = 0; localside < nSides; localside++)
3244 {
3245 if (localside == 0)
3246 {
3247 diffdistort = zero_vector;
3248 distort = GetTotalDistortion(z_readout, inpart, nSteps, true, &validToStep, &successCheck);
3249 }
3250 else
3251 {
3252
3253
3254 partZ *= -1;
3255 inpart.SetZ(-1 * inpart.Z());
3256 diffdistort = zero_vector;
3257 distort = twin->GetTotalDistortion(-z_readout, inpart, nSteps, true, &validToStep, &successCheck);
3258 }
3259
3260 diffdistort.RotateZ(-inpart.Phi());
3261 diffdistP = diffdistort.Y();
3262 diffdistR = diffdistort.X();
3263 diffdistZ = diffdistort.Z();
3264
3265 distortX = distort.X();
3266 distortY = distort.Y();
3267 distort.RotateZ(-inpart.Phi());
3268 distortP = distort.Y();
3269 distortR = distort.X();
3270 distortZ = distort.Z();
3271
3272 float distComp[nMapComponents];
3273 distComp[0] = distortX;
3274 distComp[1] = distortY;
3275 distComp[2] = distortZ;
3276 distComp[3] = distortR;
3277 distComp[4] = distortP / partR;
3278 distComp[5] = distortP;
3279
3280 for (int c = 0; c < nMapComponents; c++)
3281 {
3282 hSeparatedMapComponent[localside][c]->Fill(partP, partR, partZ, distComp[c]);
3283 }
3284
3285 hValidToStepComponent[localside]->Fill(partP, partR, partZ, validToStep);
3286 hReachesReadout[localside]->Fill(partP, partR, partZ, successCheck);
3287
3288
3289
3290
3291
3292 hIntDistortionR->Fill(partP, partR, partZ, distortR);
3293 hIntDistortionP->Fill(partP, partR, partZ, distortP);
3294 hIntDistortionZ->Fill(partP, partR, partZ, distortZ);
3295
3296 if (andCartesian)
3297 {
3298 hIntDistortionX->Fill(partP, partR, partZ, distortX);
3299 hIntDistortionY->Fill(partP, partR, partZ, distortY);
3300 }
3301
3302
3303 if (ir == xi[0] && localside == 0)
3304 {
3305
3306 hIntDist[0][0]->Fill(partP, partZ, distortR);
3307 hIntDist[0][1]->Fill(partP, partZ, distortP);
3308 hIntDist[0][2]->Fill(partP, partZ, distortZ);
3309 hDiffDist[0][0]->Fill(partP, partZ, diffdistR);
3310 hDiffDist[0][1]->Fill(partP, partZ, diffdistP);
3311 hDiffDist[0][2]->Fill(partP, partZ, diffdistZ);
3312 }
3313 if (ip == xi[1] && localside == 0)
3314 {
3315
3316 hIntDist[1][0]->Fill(partZ, partR, distortR);
3317 hIntDist[1][1]->Fill(partZ, partR, distortP);
3318 hIntDist[1][2]->Fill(partZ, partR, distortZ);
3319 hDiffDist[1][0]->Fill(partZ, partR, diffdistR);
3320 hDiffDist[1][1]->Fill(partZ, partR, diffdistP);
3321 hDiffDist[1][2]->Fill(partZ, partR, diffdistZ);
3322
3323 if (iz == xi[2] && localside == 0)
3324 {
3325 hRDist[0][0]->Fill(partR, distortR);
3326 hRDist[0][1]->Fill(partR, distortP);
3327 hRDist[0][2]->Fill(partR, distortZ);
3328 hRDiffDist[0][0]->Fill(partR, diffdistR);
3329 hRDiffDist[0][1]->Fill(partR, diffdistP);
3330 hRDiffDist[0][2]->Fill(partR, diffdistZ);
3331 }
3332 if (hasTwin && iz == twinz && localside == 1)
3333 {
3334 hRDist[1][0]->Fill(partR, distortR);
3335 hRDist[1][1]->Fill(partR, distortP);
3336 hRDist[1][2]->Fill(partR, distortZ);
3337 hRDiffDist[1][0]->Fill(partR, diffdistR);
3338 hRDiffDist[1][1]->Fill(partR, diffdistP);
3339 hRDiffDist[1][2]->Fill(partR, diffdistZ);
3340 }
3341 }
3342 if (iz == xi[2] && localside == 0)
3343 {
3344
3345
3346 hIntDist[2][0]->Fill(partR, partP, distortR);
3347 hIntDist[2][1]->Fill(partR, partP, distortP);
3348 hIntDist[2][2]->Fill(partR, partP, distortZ);
3349 hDiffDist[2][0]->Fill(partR, partP, diffdistR);
3350 hDiffDist[2][1]->Fill(partR, partP, diffdistP);
3351 hDiffDist[2][2]->Fill(partR, partP, diffdistZ);
3352 }
3353
3354 if (!(el % waypoint))
3355 {
3356 std::cout << boost::str(boost::format("generating distortions %d%%: ") % ((int) (el / percent)));
3357 std::cout << boost::str(boost::format("distortion at (ir=%d,ip=%d,iz=%d) is (%E,%E,%E)") % ir % ip % iz % distortR % distortP % distortZ) << std::endl;
3358 }
3359 el++;
3360 }
3361 }
3362 }
3363 }
3364 std::cout << "Completed distortion generation. Saving outputs..." << std::endl;
3365
3366 TCanvas *canvas = new TCanvas("cdistort", "distortion integrals", 1200, 800);
3367
3368 std::cout << "was able to make a tcanvas" << std::endl;
3369 canvas->cd();
3370 TPad *c = new TPad("cplots", "distortion integral plots", 0, 0.2, 1, 1);
3371 canvas->cd();
3372 TPad *textpad = new TPad("ctext", "distortion integral plots", 0, 0.0, 1, 0.2);
3373 std::cout << "was able to make some tpads" << std::endl;
3374
3375 c->Divide(4, 3);
3376 gStyle->SetOptStat();
3377 std::cout << "was able to interact with gStyle" << std::endl;
3378
3379 for (int i = 0; i < 3; i++)
3380 {
3381
3382 for (int ax = 0; ax < 3; ax++)
3383 {
3384 std::cout << boost::str(boost::format("looping over components i=%d ax=%d") % i % ax) << std::endl;
3385
3386
3387 c->cd(i * 4 + ax + 1);
3388 gPad->SetRightMargin(0.15);
3389 hIntDist[ax][i]->SetStats(false);
3390 hIntDist[ax][i]->Draw("colz");
3391 }
3392
3393 std::cout << "drawing R profile " << i << std::endl;
3394
3395 c->cd(i * 4 + 4);
3396 hRDist[0][i]->SetStats(false);
3397 hRDist[0][i]->SetFillColor(kRed);
3398 hRDist[0][i]->Draw("hist");
3399 if (hasTwin)
3400 {
3401 std::cout << "drawing R profile twin " << i << std::endl;
3402 hRDist[1][i]->SetStats(false);
3403 hRDist[1][i]->SetLineColor(kBlue);
3404 hRDist[1][i]->Draw("hist,same");
3405 }
3406 }
3407 std::cout << "switching to textpad" << std::endl;
3408
3409 textpad->cd();
3410 float texpos = 0.9;
3411 float texshift = 0.12;
3412 TLatex *tex = new TLatex(0.0, texpos, "Fill Me In");
3413 std::cout << "built TLatex" << std::endl;
3414
3415 tex->SetTextSize(texshift * 0.8);
3416 tex->DrawLatex(0.05, texpos, GetFieldString().c_str());
3417 texpos -= texshift;
3418 tex->DrawLatex(0.05, texpos, GetChargeString().c_str());
3419 texpos -= texshift;
3420
3421 tex->DrawLatex(0.05, texpos, boost::str(boost::format("Drifting grid of (rp)=(%d x %d) electrons with %d steps") % nrh % nph % nSteps).c_str());
3422 texpos -= texshift;
3423 tex->DrawLatex(0.05, texpos, GetLookupString().c_str());
3424 texpos -= texshift;
3425 tex->DrawLatex(0.05, texpos, GetGasString().c_str());
3426 texpos -= texshift;
3427 if (debug_distortionScale.Mag() > 0)
3428 {
3429 tex->DrawLatex(0.05, texpos, boost::str(boost::format("Distortion scaled by (r,p,z)=(%2.2f,%2.2f,%2.2f)") % debug_distortionScale.X() % debug_distortionScale.Y() % debug_distortionScale.Z()).c_str());
3430 texpos -= texshift;
3431 }
3432 texpos = 0.9;
3433 std::cout << "cd'ing to canvas:" << std::endl;
3434
3435 canvas->cd();
3436 std::cout << "draw1" << std::endl;
3437
3438 c->Draw();
3439 canvas->cd();
3440 std::cout << "draw2" << std::endl;
3441 textpad->Draw();
3442 std::cout << "was able to complete drawing on both pads" << std::endl;
3443
3444 canvas->SaveAs(summaryFilename.c_str());
3445
3446
3447
3448
3449
3450
3451
3452 for (int i = 0; i < 3; i++)
3453 {
3454
3455 for (int ax = 0; ax < 3; ax++)
3456 {
3457
3458 c->cd(i * 4 + ax + 1);
3459 gPad->SetRightMargin(0.15);
3460 hDiffDist[ax][i]->SetStats(false);
3461 hDiffDist[ax][i]->Draw("colz");
3462 }
3463 c->cd(i * 4 + 4);
3464 hRDiffDist[0][i]->SetStats(false);
3465 hRDiffDist[0][i]->SetFillColor(kRed);
3466 hRDiffDist[0][i]->Draw("hist");
3467 if (hasTwin)
3468 {
3469 hRDiffDist[1][i]->SetStats(false);
3470 hRDiffDist[1][i]->SetLineColor(kBlue);
3471 hRDiffDist[1][i]->Draw("hist same");
3472 }
3473 }
3474 textpad->cd();
3475 texpos = 0.9;
3476 texshift = 0.12;
3477 tex->SetTextSize(texshift * 0.8);
3478 tex->DrawLatex(0.05, texpos, GetFieldString().c_str());
3479 texpos -= texshift;
3480 tex->DrawLatex(0.05, texpos, GetChargeString().c_str());
3481 texpos -= texshift;
3482
3483 tex->DrawLatex(0.05, texpos, boost::str(boost::format("Drifting grid of (rp)=(%d x %d) electrons with %d steps") % nrh % nph % nSteps).c_str());
3484 texpos -= texshift;
3485 tex->DrawLatex(0.05, texpos, GetLookupString().c_str());
3486 texpos -= texshift;
3487 tex->DrawLatex(0.05, texpos, GetGasString().c_str());
3488 texpos -= texshift;
3489 tex->DrawLatex(0.05, texpos, "Differential Plots");
3490 texpos -= texshift;
3491 if (debug_distortionScale.Mag() > 0)
3492 {
3493 tex->DrawLatex(0.05, texpos, boost::str(boost::format("Distortion scaled by (r,p,z)=(%2.2f,%2.2f,%2.2f)") % debug_distortionScale.X() % debug_distortionScale.Y() % debug_distortionScale.Z()).c_str());
3494 texpos -= texshift;
3495 }
3496 texpos = 0.9;
3497
3498 canvas->cd();
3499 c->Draw();
3500 canvas->cd();
3501 textpad->Draw();
3502 canvas->SaveAs(diffSummaryFilename.c_str());
3503
3504 std::cout << "saving map histograms to:" << distortionFilename << std::endl;
3505
3506 outf->cd();
3507 for (int i = 0; i < nSides; i++)
3508 {
3509 std::cout << "Saving side " << side[i] << std::endl;
3510 for (int j = 0; j < nMapComponents; j++)
3511 {
3512 hSeparatedMapComponent[i][j]->GetSumw2()->Set(0);
3513 hSeparatedMapComponent[i][j]->Write();
3514 }
3515 hValidToStepComponent[i]->GetSumw2()->Set(0);
3516 hValidToStepComponent[i]->Write();
3517
3518 hReachesReadout[i]->GetSumw2()->Set(0);
3519 hReachesReadout[i]->Write();
3520 }
3521 if (rdrswitch)
3522 {
3523 hRdeltaRComponent->GetSumw2()->Set(0);
3524 hRdeltaRComponent->Write();
3525 }
3526
3527 hDistortionR->GetSumw2()->Set(0);
3528 hDistortionP->GetSumw2()->Set(0);
3529 hDistortionZ->GetSumw2()->Set(0);
3530 hIntDistortionR->GetSumw2()->Set(0);
3531 hIntDistortionP->GetSumw2()->Set(0);
3532 hIntDistortionZ->GetSumw2()->Set(0);
3533 if (andCartesian)
3534 {
3535 hIntDistortionX->GetSumw2()->Set(0);
3536 hIntDistortionY->GetSumw2()->Set(0);
3537 }
3538 hDistortionR->Write();
3539 hDistortionP->Write();
3540 hDistortionZ->Write();
3541 hIntDistortionR->Write();
3542 hIntDistortionP->Write();
3543 hIntDistortionZ->Write();
3544 if (false && andCartesian)
3545 {
3546 hIntDistortionX->Write();
3547 hIntDistortionY->Write();
3548 }
3549 std::cout << "finished writing histograms" << std::endl;
3550
3551
3552 outf->Close();
3553
3554
3555 std::cout << "wrote separated map and summary to " << filebase << std::endl;
3556 std::cout << "map: " << distortionFilename << std::endl;
3557 std::cout << "summary: " << summaryFilename << std::endl;
3558
3559 return;
3560 }
3561
3562 void AnnularFieldSim::GenerateDistortionMaps(const std::string &filebase, int r_subsamples, int p_subsamples, int z_subsamples, int , bool andCartesian)
3563 {
3564
3565
3566
3567 std::cout << "WARNING: You called the version of the distortion generator that generates a unified map. Are you sure you meant to do this?" << std::endl;
3568
3569
3570 bool makeUnifiedMap = true;
3571
3572 TVector3 steplocal(step.Perp() / r_subsamples, 0, step.Z() / z_subsamples);
3573 steplocal.SetPhi(step.Phi() / p_subsamples);
3574 float deltar = steplocal.Perp();
3575 float deltap = steplocal.Phi();
3576 float deltaz = steplocal.Z();
3577 TVector3 stepzvec(0, 0, deltaz);
3578 int nSteps = 500;
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589 TVector3 lowerEdge = GetRoiCellCenter(rmin_roi, phimin_roi, zmin_roi);
3590 TVector3 upperEdge = GetRoiCellCenter(rmax_roi - 1, phimax_roi - 1, zmax_roi - 1);
3591 int nph = nphi * p_subsamples + 2;
3592 int nrh = nr * r_subsamples + 2;
3593 int nzh = nz * z_subsamples + 2;
3594 int successCheck;
3595
3596 if (hasTwin && makeUnifiedMap)
3597 {
3598 lowerEdge.SetZ(-1 * upperEdge.Z());
3599 nzh += nz * z_subsamples;
3600 }
3601
3602 float rih = lowerEdge.Perp() - 0.5 * step.Perp() - steplocal.Perp();
3603 float rfh = upperEdge.Perp() + 0.5 * step.Perp() + steplocal.Perp();
3604 float pih = FilterPhiPos(lowerEdge.Phi()) - 0.5 * step.Phi() - steplocal.Phi();
3605 float pfh = FilterPhiPos(upperEdge.Phi()) + 0.5 * step.Phi() + steplocal.Phi();
3606 float zih = lowerEdge.Z() - 0.5 * step.Z() - steplocal.Z();
3607 float zfh = upperEdge.Z() + 0.5 * step.Z() + steplocal.Z();
3608 float z_readout = upperEdge.Z() + 0.5 * step.Z();
3609
3610 std::cout << "generating distortion map..." << std::endl;
3611 std::cout << "file=" << filebase << std::endl;
3612 std::cout << boost::str(boost::format("Phi: %d steps from %f to %f (field has %d steps)") % nph % pih % pfh % GetFieldStepsPhi()) << std::endl;
3613 std::cout << boost::str(boost::format("R: %d steps from %f to %f (field has %d steps)") % nrh % rih % rfh % GetFieldStepsR()) << std::endl;
3614 std::cout << boost::str(boost::format("Z: %d steps from %f to %f (field has %d steps)") % nzh % zih % zfh % GetFieldStepsZ()) << std::endl;
3615 std::string distortionFilename = filebase + ".distortion_summary.pdf";
3616 std::string summaryFilename = filebase + ".distortion_summary.pdf";
3617 std::string diffSummaryFilename = filebase + ".differential_summary.pdf";
3618
3619 TFile *outf = TFile::Open(distortionFilename.c_str(), "RECREATE");
3620 outf->cd();
3621
3622
3623
3624 TH3F *hDistortionR = new TH3F("hDistortionR", "Per-z-bin Distortion in the R direction as a function of (phi,r,z) (centered in r,phi, z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3625 TH3F *hDistortionP = new TH3F("hDistortionP", "Per-z-bin Distortion in the RPhi direction as a function of (phi,r,z) (centered in r,phi, z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3626 TH3F *hDistortionZ = new TH3F("hDistortionZ", "Per-z-bin Distortion in the Z direction as a function of (phi,r,z) (centered in r,phi, z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3627 TH3F *hIntDistortionR = new TH3F("hIntDistortionR", "Integrated R Distortion from (phi,r,z) to z=0 (centered in r,phi, and z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3628 TH3F *hIntDistortionP = new TH3F("hIntDistortionP", "Integrated R Distortion from (phi,r,z) to z=0 (centered in r,phi, and z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3629 TH3F *hIntDistortionZ = new TH3F("hIntDistortionZ", "Integrated R Distortion from (phi,r,z) to z=0 (centered in r,phi, and z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3630
3631 TH3F *hIntDistortionX = new TH3F("hIntDistortionX", "Integrated X Distortion from (phi,r,z) to z=0 (centered in r,phi, and z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3632 TH3F *hIntDistortionY = new TH3F("hIntDistortionY", "Integrated Y Distortion from (phi,r,z) to z=0 (centered in r,phi, and z);phi;r;z", nph, pih, pfh, nrh, rih, rfh, nzh, zih, zfh);
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647 TVector3 pos(((int) (nrh / 2) + 0.5) * steplocal.Perp() + rih, 0, zmin + ((int) (nz / 2) + 0.5) * step.Z());
3648 float posphi = ((int) (nph / 2) + 0.5) * steplocal.Phi() + pih;
3649 pos.SetPhi(posphi);
3650
3651 int xi[3] = {(int) std::floor((pos.Perp() - rih) / steplocal.Perp()), (int) std::floor((posphi - pih) / steplocal.Phi()), (int) std::floor((pos.Z() - zih) / steplocal.Z())};
3652 if (!hasTwin)
3653 {
3654 std::cout << boost::str(boost::format("rpz slice indices= (%d,%d,%d) (no twin)") % xi[0] % xi[1] % xi[2]) << std::endl;
3655 }
3656 int twinz = 0;
3657 if (hasTwin)
3658 {
3659 twinz = twin->GetZindex(-1 * pos.Z());
3660 std::cout << boost::str(boost::format("rpz slice indices= (%d,%d,%d) twinz=%d") % xi[0] % xi[1] % xi[2] % twinz) << std::endl;
3661 }
3662
3663 const std::string axname[] = {"r", "p", "z", "r", "p", "z"};
3664 int axn[] = {nrh, nph, nzh, nrh, nph, nzh};
3665 float axval[] = {(float) pos.Perp(), (float) pos.Phi(), (float) pos.Z(), (float) pos.Perp(), (float) pos.Phi(), (float) pos.Z()};
3666 float axbot[] = {rih, pih, zih, rih, pih, zih};
3667 float axtop[] = {rfh, pfh, zfh, rfh, pfh, zfh};
3668 TH2F *hIntDist[3][3];
3669 TH1F *hRDist[2][3];
3670 TH2F *hDiffDist[3][3];
3671 TH1F *hRDiffDist[2][3];
3672 for (int i = 0; i < 3; i++)
3673 {
3674
3675 for (int ax = 0; ax < 3; ax++)
3676 {
3677
3678 hDiffDist[ax][i] = new TH2F(std::string("hDiffDist" + axname[i] + "_" + axname[ax + 1] + axname[ax + 2]).c_str(),
3679 boost::str(boost::format("%s component of diff. distortion in %s%s plane at %s=%2.3f;%s;%s") % axname[i] % axname[ax + 1] % axname[ax + 2] % axname[ax] % axval[ax] % axname[ax + 1] % axname[ax + 2]).c_str(),
3680 axn[ax + 1], axbot[ax + 1], axtop[ax + 1],
3681 axn[ax + 2], axbot[ax + 2], axtop[ax + 2]);
3682 hIntDist[ax][i] = new TH2F(std::string("hDIntDist" + axname[i] + "_" + axname[ax + 1] + axname[ax + 2]).c_str(),
3683 boost::str(boost::format("%s component of int. distortion in %s%s plane at %s=%2.3f;%s;%s") % axname[i] % axname[ax + 1] % axname[ax + 2] % axname[ax] % axval[ax] % axname[ax + 1] % axname[ax + 2]).c_str(),
3684 axn[ax + 1], axbot[ax + 1], axtop[ax + 1],
3685 axn[ax + 2], axbot[ax + 2], axtop[ax + 2]);
3686 }
3687 hRDist[0][i] = new TH1F(std::string("hRDist" + axname[i]).c_str(),
3688 boost::str(boost::format("%s component of int. distortion vs r with %s=%2.3f and %s=%2.3f;r(cm);#delta (cm)") % axname[i] % axname[1] % axval[1] % axname[2] % axval[2]).c_str(),
3689 axn[0], axbot[0], axtop[0]);
3690 hRDist[1][i] = new TH1F(std::string("hRDist" + axname[i] + "Neg").c_str(),
3691 boost::str(boost::format("%s component of int. distortion vs r with %s=%2.3f and %s=-%2.3f;r(cm);#delta (cm)") % axname[i] % axname[1] % axval[1] % axname[2] % axval[2]).c_str(),
3692 axn[0], axbot[0], axtop[0]);
3693 hRDiffDist[0][i] = new TH1F(std::string("hRDist" + axname[i]).c_str(),
3694 boost::str(boost::format("%s component of diff. distortion vs r with %s=%2.3f and %s=%2.3f;r(cm);#delta (cm)") % axname[i] % axname[1] % axval[1] % axname[2] % axval[2]).c_str(),
3695 axn[0], axbot[0], axtop[0]);
3696 hRDiffDist[1][i] = new TH1F(std::string("hRDist" + axname[i] + "Neg").c_str(),
3697 boost::str(boost::format("%s component of diff. distortion vs r with %s=%2.3f and %s=-%2.3f;r(cm);#delta (cm)") % axname[i] % axname[1] % axval[1] % axname[2] % axval[2]).c_str(),
3698 axn[0], axbot[0], axtop[0]);
3699 }
3700
3701 TVector3 inpart, outpart;
3702 TVector3 distort;
3703 int validToStep;
3704
3705
3706 float partR, partP, partZ;
3707 int ir, ip, iz;
3708 float distortR, distortP, distortZ;
3709 float distortX, distortY;
3710 float diffdistR, diffdistP, diffdistZ;
3711 TTree *dTree = new TTree("dTree", "Distortion per step z");
3712 dTree->Branch("r", &partR);
3713 dTree->Branch("p", &partP);
3714 dTree->Branch("z", &partZ);
3715 dTree->Branch("ir", &ir);
3716 dTree->Branch("ip", &ip);
3717 dTree->Branch("iz", &iz);
3718 dTree->Branch("dr", &distortR);
3719 dTree->Branch("drp", &distortP);
3720 dTree->Branch("dz", &distortZ);
3721
3722 std::cout << "generating distortion map with (" << nrh << "x" << nph << "x" << nzh << " grid" << std::endl;
3723 unsigned long long totalelements = nrh;
3724 totalelements *= nph;
3725 totalelements *= nzh;
3726 unsigned long long percent = totalelements / 100 * debug_npercent;
3727 std::cout << boost::str(boost::format("total elements = %llu") % totalelements) << std::endl;
3728
3729 int el = 0;
3730
3731
3732
3733
3734
3735
3736
3737
3738 inpart.SetXYZ(1, 0, 0);
3739 for (ir = 0; ir < nrh; ir++)
3740 {
3741 partR = (ir + 0.5) * deltar + rih;
3742 if (ir == 0)
3743 {
3744 inpart.SetPerp(partR + deltar);
3745 }
3746 else if (ir == nrh - 1)
3747 {
3748 inpart.SetPerp(partR - deltar);
3749 }
3750 else
3751 {
3752 inpart.SetPerp(partR);
3753 }
3754 for (ip = 0; ip < nph; ip++)
3755 {
3756 partP = (ip + 0.5) * deltap + pih;
3757 inpart.SetPhi(partP);
3758
3759 for (iz = 0; iz < nzh; iz++)
3760 {
3761 partZ = (iz) *deltaz + zih;
3762 if (iz == 0)
3763 {
3764 inpart.SetZ(partZ + deltaz);
3765 }
3766 else if (iz == nzh - 1)
3767 {
3768 inpart.SetZ(partZ - deltaz);
3769 }
3770 else
3771 {
3772 inpart.SetZ(partZ);
3773 }
3774 partZ += 0.5 * deltaz;
3775
3776
3777
3778
3779
3780 if (hasTwin && inpart.Z() < 0)
3781 {
3782 distort = twin->GetTotalDistortion(inpart.Z(), inpart + stepzvec, nSteps, true, &validToStep, &successCheck);
3783 }
3784 else
3785 {
3786 distort = GetTotalDistortion(inpart.Z() + deltaz, inpart, nSteps, true, &validToStep, &successCheck);
3787 }
3788 distort.RotateZ(-inpart.Phi());
3789 diffdistP = distort.Y();
3790 diffdistR = distort.X();
3791 diffdistZ = distort.Z();
3792 hDistortionR->Fill(partP, partR, partZ, diffdistR);
3793 hDistortionP->Fill(partP, partR, partZ, diffdistP);
3794 hDistortionZ->Fill(partP, partR, partZ, diffdistZ);
3795 dTree->Fill();
3796
3797
3798 if (hasTwin && makeUnifiedMap && inpart.Z() < 0)
3799 {
3800 distort = twin->GetTotalDistortion(-z_readout, inpart + stepzvec, nSteps, true, &validToStep, &successCheck);
3801 }
3802 else
3803 {
3804 distort = GetTotalDistortion(z_readout, inpart, nSteps, true, &validToStep, &successCheck);
3805 }
3806 distortX = distort.X();
3807 distortY = distort.Y();
3808 distort.RotateZ(-inpart.Phi());
3809 distortP = distort.Y();
3810 distortR = distort.X();
3811 distortZ = distort.Z();
3812
3813
3814
3815
3816
3817 hIntDistortionR->Fill(partP, partR, partZ, distortR);
3818 hIntDistortionP->Fill(partP, partR, partZ, distortP);
3819 hIntDistortionZ->Fill(partP, partR, partZ, distortZ);
3820
3821 if (andCartesian)
3822 {
3823 hIntDistortionX->Fill(partP, partR, partZ, distortX);
3824 hIntDistortionY->Fill(partP, partR, partZ, distortY);
3825 }
3826
3827
3828 if (ir == xi[0])
3829 {
3830
3831 hIntDist[0][0]->Fill(partP, partZ, distortR);
3832 hIntDist[0][1]->Fill(partP, partZ, distortP);
3833 hIntDist[0][2]->Fill(partP, partZ, distortZ);
3834 hDiffDist[0][0]->Fill(partP, partZ, diffdistR);
3835 hDiffDist[0][1]->Fill(partP, partZ, diffdistP);
3836 hDiffDist[0][2]->Fill(partP, partZ, diffdistZ);
3837 }
3838 if (ip == xi[1])
3839 {
3840
3841 hIntDist[1][0]->Fill(partZ, partR, distortR);
3842 hIntDist[1][1]->Fill(partZ, partR, distortP);
3843 hIntDist[1][2]->Fill(partZ, partR, distortZ);
3844 hDiffDist[1][0]->Fill(partZ, partR, diffdistR);
3845 hDiffDist[1][1]->Fill(partZ, partR, diffdistP);
3846 hDiffDist[1][2]->Fill(partZ, partR, diffdistZ);
3847
3848 if (iz == xi[2])
3849 {
3850 hRDist[0][0]->Fill(partR, distortR);
3851 hRDist[0][1]->Fill(partR, distortP);
3852 hRDist[0][2]->Fill(partR, distortZ);
3853 hRDiffDist[0][0]->Fill(partR, diffdistR);
3854 hRDiffDist[0][1]->Fill(partR, diffdistP);
3855 hRDiffDist[0][2]->Fill(partR, diffdistZ);
3856 }
3857 if (hasTwin && iz == twinz)
3858 {
3859 hRDist[1][0]->Fill(partR, distortR);
3860 hRDist[1][1]->Fill(partR, distortP);
3861 hRDist[1][2]->Fill(partR, distortZ);
3862 hRDiffDist[1][0]->Fill(partR, diffdistR);
3863 hRDiffDist[1][1]->Fill(partR, diffdistP);
3864 hRDiffDist[1][2]->Fill(partR, diffdistZ);
3865 }
3866 }
3867 if (iz == xi[2])
3868 {
3869
3870
3871 hIntDist[2][0]->Fill(partR, partP, distortR);
3872 hIntDist[2][1]->Fill(partR, partP, distortP);
3873 hIntDist[2][2]->Fill(partR, partP, distortZ);
3874 hDiffDist[2][0]->Fill(partR, partP, diffdistR);
3875 hDiffDist[2][1]->Fill(partR, partP, diffdistP);
3876 hDiffDist[2][2]->Fill(partR, partP, diffdistZ);
3877 }
3878
3879 if (!(el % percent))
3880 {
3881 std::cout << boost::str(boost::format("generating distortions %d%%: ") % ((int) (debug_npercent * (el / percent))));
3882 std::cout << boost::str(boost::format("distortion at (ir=%d,ip=%d,iz=%d) is (%E,%E,%E)") % ir % ip % iz % distortR % distortP % distortZ) << std::endl;
3883 }
3884 el++;
3885 }
3886 }
3887 }
3888
3889 TCanvas *canvas = new TCanvas("cdistort", "distortion integrals", 1200, 800);
3890
3891 canvas->cd();
3892 TPad *c = new TPad("cplots", "distortion integral plots", 0, 0.2, 1, 1);
3893 canvas->cd();
3894 TPad *textpad = new TPad("ctext", "distortion integral plots", 0, 0.0, 1, 0.2);
3895 c->Divide(4, 3);
3896 gStyle->SetOptStat();
3897 for (int i = 0; i < 3; i++)
3898 {
3899
3900 for (int ax = 0; ax < 3; ax++)
3901 {
3902
3903 c->cd(i * 4 + ax + 1);
3904 gPad->SetRightMargin(0.15);
3905 hIntDist[ax][i]->SetStats(false);
3906 hIntDist[ax][i]->Draw("colz");
3907 }
3908 c->cd(i * 4 + 4);
3909 hRDist[0][i]->SetStats(false);
3910 hRDist[0][i]->SetFillColor(kRed);
3911 hRDist[0][i]->Draw("hist");
3912 if (hasTwin)
3913 {
3914 hRDist[1][i]->SetStats(false);
3915 hRDist[1][i]->SetLineColor(kBlue);
3916 hRDist[1][i]->Draw("hist,same");
3917 }
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932 }
3933 textpad->cd();
3934 float texpos = 0.9;
3935 float texshift = 0.12;
3936 TLatex *tex = new TLatex(0.0, texpos, "Fill Me In");
3937 tex->SetTextSize(texshift * 0.8);
3938 tex->DrawLatex(0.05, texpos, GetFieldString().c_str());
3939 texpos -= texshift;
3940 tex->DrawLatex(0.05, texpos, GetChargeString().c_str());
3941 texpos -= texshift;
3942
3943 tex->DrawLatex(0.05, texpos, boost::str(boost::format("Drifting grid of (rp)=(%d x %d) electrons with %d steps") % nrh % nph % nSteps).c_str());
3944 texpos -= texshift;
3945 tex->DrawLatex(0.05, texpos, GetLookupString().c_str());
3946 texpos -= texshift;
3947 tex->DrawLatex(0.05, texpos, GetGasString().c_str());
3948 texpos -= texshift;
3949 if (debug_distortionScale.Mag() > 0)
3950 {
3951 tex->DrawLatex(0.05, texpos, boost::str(boost::format("Distortion scaled by (r,p,z)=(%2.2f,%2.2f,%2.2f)") % debug_distortionScale.X() % debug_distortionScale.Y() % debug_distortionScale.Z()).c_str());
3952 texpos -= texshift;
3953 }
3954 texpos = 0.9;
3955
3956 canvas->cd();
3957 c->Draw();
3958 canvas->cd();
3959 textpad->Draw();
3960 canvas->SaveAs(summaryFilename.c_str());
3961
3962
3963
3964
3965
3966
3967
3968 for (int i = 0; i < 3; i++)
3969 {
3970
3971 for (int ax = 0; ax < 3; ax++)
3972 {
3973
3974 c->cd(i * 4 + ax + 1);
3975 gPad->SetRightMargin(0.15);
3976 hDiffDist[ax][i]->SetStats(false);
3977 hDiffDist[ax][i]->Draw("colz");
3978 }
3979 c->cd(i * 4 + 4);
3980 hRDiffDist[0][i]->SetStats(false);
3981 hRDiffDist[0][i]->SetFillColor(kRed);
3982 hRDiffDist[0][i]->Draw("hist");
3983 if (hasTwin)
3984 {
3985 hRDiffDist[1][i]->SetStats(false);
3986 hRDiffDist[1][i]->SetLineColor(kBlue);
3987 hRDiffDist[1][i]->Draw("hist same");
3988 }
3989 }
3990 textpad->cd();
3991 texpos = 0.9;
3992 texshift = 0.12;
3993 tex->SetTextSize(texshift * 0.8);
3994 tex->DrawLatex(0.05, texpos, GetFieldString().c_str());
3995 texpos -= texshift;
3996 tex->DrawLatex(0.05, texpos, GetChargeString().c_str());
3997 texpos -= texshift;
3998
3999 tex->DrawLatex(0.05, texpos, boost::str(boost::format("Drifting grid of (rp)=(%d x %d) electrons with %d steps") % nrh % nph % nSteps).c_str());
4000 texpos -= texshift;
4001 tex->DrawLatex(0.05, texpos, GetLookupString().c_str());
4002 texpos -= texshift;
4003 tex->DrawLatex(0.05, texpos, GetGasString().c_str());
4004 texpos -= texshift;
4005 tex->DrawLatex(0.05, texpos, "Differential Plots");
4006 texpos -= texshift;
4007 if (debug_distortionScale.Mag() > 0)
4008 {
4009 tex->DrawLatex(0.05, texpos, boost::str(boost::format("Distortion scaled by (r,p,z)=(%2.2f,%2.2f,%2.2f)") % debug_distortionScale.X() % debug_distortionScale.Y() % debug_distortionScale.Z()).c_str());
4010 texpos -= texshift;
4011 }
4012 texpos = 0.9;
4013
4014 canvas->cd();
4015 c->Draw();
4016 canvas->cd();
4017 textpad->Draw();
4018 canvas->SaveAs(diffSummaryFilename.c_str());
4019
4020
4021
4022 outf->cd();
4023
4024 hDistortionR->Write();
4025 hDistortionP->Write();
4026 hDistortionZ->Write();
4027 hIntDistortionR->Write();
4028 hIntDistortionP->Write();
4029 hIntDistortionZ->Write();
4030 if (andCartesian)
4031 {
4032 hIntDistortionX->Write();
4033 hIntDistortionY->Write();
4034 }
4035 dTree->Write();
4036 outf->Close();
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060 std::cout << "wrote map and summary to " << filebase << std::endl;
4061 std::cout << "map: " << distortionFilename << std::endl;
4062 std::cout << "summary: " << summaryFilename << std::endl;
4063
4064 return;
4065 }
4066
4067 TVector3 AnnularFieldSim::swimTo(float zdest, const TVector3 &start, bool interpolate, bool useAnalytic)
4068 {
4069 int defaultsteps = 100;
4070 int goodtostep = 0;
4071 if (useAnalytic)
4072 {
4073 return swimToInAnalyticSteps(zdest, start, defaultsteps, &goodtostep);
4074 }
4075 return swimToInSteps(zdest, start, defaultsteps, interpolate, &goodtostep);
4076 }
4077
4078 TVector3 AnnularFieldSim::GetStepDistortion(float zdest, const TVector3 &start, bool interpolate, bool useAnalytic)
4079 {
4080
4081
4082
4083
4084 int rt, pt, zt;
4085 BoundsCase zBound = GetZindexAndCheckBounds(start.Z(), &zt);
4086 if (GetRindexAndCheckBounds(start.Perp(), &rt) != InBounds || GetPhiIndexAndCheckBounds(FilterPhiPos(start.Phi()), &pt) != InBounds || (zBound != InBounds && zBound != OnHighEdge))
4087 {
4088
4089
4090
4091 return start;
4092 }
4093
4094
4095
4096 double zdist = zdest - start.Z();
4097
4098
4099
4100 if (std::abs(zdist) < ALMOST_ZERO * step.Z())
4101 {
4102
4103 return zero_vector;
4104 }
4105
4106 TVector3 fieldInt;
4107 TVector3 fieldIntB;
4108
4109
4110 if (useAnalytic)
4111 {
4112 fieldInt = analyticFieldIntegral(zdest, start, Efield);
4113 fieldIntB = analyticFieldIntegral(zdest, start, Bfield);
4114 }
4115 else if (interpolate)
4116 {
4117 fieldInt = interpolatedFieldIntegral(zdest, start, Efield);
4118 fieldIntB = interpolatedFieldIntegral(zdest, start, Bfield);
4119 }
4120 else
4121 {
4122 fieldInt = fieldIntegral(zdest, start, Efield);
4123 fieldIntB = fieldIntegral(zdest, start, Bfield);
4124 }
4125
4126 if (std::abs(fieldInt.Z() / zdist) < ALMOST_ZERO)
4127 {
4128 std::cout << "GetStepDistortion is attempting to swim with no drift field:" << std::endl;
4129 std::cout << boost::str(boost::format("GetStepDistortion: (%2.4f,%2.4f,%2.4f) to z=%2.4f") % start.X() % start.Y() % start.Z() % zdest) << std::endl;
4130 std::cout << boost::str(boost::format("GetStepDistortion: fieldInt=(%E,%E,%E)") % fieldInt.X() % fieldInt.Y() % fieldInt.Z()) << std::endl;
4131 exit(1);
4132 }
4133
4134 double EfieldZ = fieldInt.Z() / zdist;
4135 double BfieldZ = fieldIntB.Z() / zdist;
4136
4137
4138
4139
4140
4141 double omegatau = omegatau_nominal;
4142
4143
4144
4145 double T1om = langevin_T1 * omegatau;
4146 double T2om2 = langevin_T2 * omegatau * langevin_T2 * omegatau;
4147 double c0 = 1 / (1 + T2om2);
4148 double c1 = T1om / (1 + T1om * T1om);
4149 double c2 = T2om2 / (1 + T2om2);
4150
4151 TVector3 EintOverEz = 1 / EfieldZ * fieldInt;
4152 TVector3 BintOverBz = 1 / BfieldZ * fieldIntB;
4153
4154
4155
4156
4157 double deltaX = c0 * EintOverEz.X() + c1 * EintOverEz.Y() - c1 * BintOverBz.Y() + c2 * BintOverBz.X();
4158 double deltaY = c0 * EintOverEz.Y() - c1 * EintOverEz.X() + c1 * BintOverBz.X() + c2 * BintOverBz.Y();
4159
4160
4161 double vprime = (5000 * cm / s) / (100 * V / cm);
4162 double vdoubleprime = 0;
4163
4164
4165
4166
4167 double deltaZ = vprime / vdrift * (fieldInt.Z() - zdist * Enominal) + vdoubleprime / vdrift * (fieldInt.Z() - Enominal * zdist) * (fieldInt.Z() - Enominal * zdist) / (2 * zdist) - 0.5 / zdist * (EintOverEz.X() * EintOverEz.X() + EintOverEz.Y() * EintOverEz.Y()) + c1 / zdist * (EintOverEz.X() * BintOverBz.Y() - EintOverEz.Y() * BintOverBz.X()) + c2 / zdist * (EintOverEz.X() * BintOverBz.X() + EintOverEz.Y() * BintOverBz.Y()) + c2 / zdist * (BintOverBz.X() * BintOverBz.X() + BintOverBz.Y() * BintOverBz.Y());
4168
4169 if (false)
4170 {
4171 std::cout << boost::str(boost::format("GetStepDistortion: (c0,c1,c2)=(%E,%E,%E)") % c0 % c1 % c2) << std::endl;
4172 std::cout << boost::str(boost::format("GetStepDistortion: EintOverEz==(%E,%E,%E)") % EintOverEz.X() % EintOverEz.Y() % EintOverEz.Z()) << std::endl;
4173 std::cout << boost::str(boost::format("GetStepDistortion: BintOverBz==(%E,%E,%E)") % BintOverBz.X() % BintOverBz.Y() % BintOverBz.Z()) << std::endl;
4174 std::cout << boost::str(boost::format("GetStepDistortion: (%2.4f,%2.4f,%2.4f) to z=%2.4f") % start.X() % start.Y() % start.Z() % zdest) << std::endl;
4175 std::cout << boost::str(boost::format("GetStepDistortion: fieldInt=(%E,%E,%E)") % fieldInt.X() % fieldInt.Y() % fieldInt.Z()) << std::endl;
4176 std::cout << boost::str(boost::format("GetStepDistortion: delta=(%E,%E,%E)") % deltaX % deltaY % deltaZ) << std::endl;
4177 }
4178
4179
4180 if (false)
4181 {
4182 std::cout << "GetStepDistortion produced a very large zdistortion!" << std::endl;
4183 std::cout << boost::str(boost::format("GetStepDistortion: zdist=%2.4f, deltaZ=%2.4f, Delta/z=%2.4f") % zdist % deltaZ % (deltaZ / zdist)) << std::endl;
4184 std::cout << boost::str(boost::format("GetStepDistortion: average field Z: Ez=%2.4fV/cm, Bz=%2.4fT") % (EfieldZ / (V / cm)) % (BfieldZ / Tesla)) << std::endl;
4185 std::cout << boost::str(boost::format("GetStepDistortion: (c0,c1,c2)=(%E,%E,%E)") % c0 % c1 % c2) << std::endl;
4186 std::cout << boost::str(boost::format("GetStepDistortion: EintOverEz==(%E,%E,%E)") % EintOverEz.X() % EintOverEz.Y() % EintOverEz.Z()) << std::endl;
4187 std::cout << boost::str(boost::format("GetStepDistortion: BintOverBz==(%E,%E,%E)") % BintOverBz.X() % BintOverBz.Y() % BintOverBz.Z()) << std::endl;
4188 std::cout << boost::str(boost::format("GetStepDistortion: (%2.4f,%2.4f,%2.4f) to z=%2.4f") % start.X() % start.Y() % start.Z() % zdest) << std::endl;
4189 std::cout << boost::str(boost::format("GetStepDistortion: EfieldInt=(%E,%E,%E)") % fieldInt.X() % fieldInt.Y() % fieldInt.Z()) << std::endl;
4190 std::cout << boost::str(boost::format("GetStepDistortion: BfieldInt=(%E,%E,%E)") % fieldIntB.X() % fieldIntB.Y() % fieldIntB.Z()) << std::endl;
4191 std::cout << boost::str(boost::format("GetStepDistortion: delta=(%E,%E,%E)") % deltaX % deltaY % deltaZ) << std::endl;
4192
4193 }
4194
4195 if (std::abs(deltaX) < 1E-20 && !(chargeCase == NoSpacecharge))
4196 {
4197 std::cout << boost::str(boost::format("GetStepDistortion produced a very small deltaX: %E") % deltaX) << std::endl;
4198 std::cout << boost::str(boost::format("GetStepDistortion: (c0,c1,c2)=(%E,%E,%E)") % c0 % c1 % c2) << std::endl;
4199 std::cout << boost::str(boost::format("GetStepDistortion: EintOverEz==(%E,%E,%E)") % EintOverEz.X() % EintOverEz.Y() % EintOverEz.Z()) << std::endl;
4200 std::cout << boost::str(boost::format("GetStepDistortion: BintOverBz==(%E,%E,%E)") % BintOverBz.X() % BintOverBz.Y() % BintOverBz.Z()) << std::endl;
4201 std::cout << boost::str(boost::format("GetStepDistortion: (%2.4f,%2.4f,%2.4f) to z=%2.4f") % start.X() % start.Y() % start.Z() % zdest) << std::endl;
4202 std::cout << boost::str(boost::format("GetStepDistortion: fieldInt=(%E,%E,%E)") % fieldInt.X() % fieldInt.Y() % fieldInt.Z()) << std::endl;
4203 std::cout << boost::str(boost::format("GetStepDistortion: delta=(%E,%E,%E)") % deltaX % deltaY % deltaZ) << std::endl;
4204
4205 }
4206
4207
4208 if (false)
4209 {
4210 std::cout << boost::str(boost::format("GetStepDistortion produced a very large deltaX: %E") % deltaX) << std::endl;
4211 std::cout << boost::str(boost::format("GetStepDistortion: (c0,c1,c2)=(%E,%E,%E)") % c0 % c1 % c2) << std::endl;
4212 std::cout << boost::str(boost::format("GetStepDistortion: EintOverEz==(%E,%E,%E)") % EintOverEz.X() % EintOverEz.Y() % EintOverEz.Z()) << std::endl;
4213 std::cout << boost::str(boost::format("GetStepDistortion: BintOverBz==(%E,%E,%E)") % BintOverBz.X() % BintOverBz.Y() % BintOverBz.Z()) << std::endl;
4214 std::cout << boost::str(boost::format("GetStepDistortion: (%2.4f,%2.4f,%2.4f) (rp)=(%2.4f,%2.4f) to z=%2.4f") % start.X() % start.Y() % start.Z() % start.Perp() % start.Phi() % zdest) << std::endl;
4215 std::cout << boost::str(boost::format("GetStepDistortion: fieldInt=(%E,%E,%E)") % fieldInt.X() % fieldInt.Y() % fieldInt.Z()) << std::endl;
4216 std::cout << boost::str(boost::format("GetStepDistortion: delta=(%E,%E,%E)") % deltaX % deltaY % deltaZ) << std::endl;
4217 exit(1);
4218 }
4219
4220
4221
4222 TVector3 shift(deltaX, deltaY, deltaZ);
4223 if (debug_distortionScale.Mag() > 0)
4224 {
4225 shift.RotateZ(-start.Phi());
4226
4227
4228 shift.SetXYZ(shift.X() * debug_distortionScale.X(), shift.Y() * debug_distortionScale.Y(), shift.Z() * debug_distortionScale.Z());
4229 shift.RotateZ(start.Phi());
4230 }
4231
4232 return shift;
4233 }
4234
4235
4236 const std::string AnnularFieldSim::GetLookupString()
4237 {
4238 if (lookupCase == LookupCase::Full3D)
4239 {
4240 return boost::str(boost::format("Full3D (%d x %d x %d) with (%d x %d x %d) roi") % nr % nphi % nz % nr_roi % nphi_roi % nz_roi);
4241 }
4242
4243 if (lookupCase == LookupCase::PhiSlice)
4244 {
4245 return boost::str(boost::format("PhiSlice (%d x %d x %d) with (%d x 1 x %d) roi") % nr % nphi % nz % nr_roi % nz_roi);
4246 }
4247
4248 return "broken";
4249 }
4250 const std::string AnnularFieldSim::GetGasString()
4251 {
4252 return boost::str(boost::format("vdrift=%2.2fcm/us, Enom=%2.2fV/cm, Bnom=%2.2fT, omtau=%2.4E") % (vdrift / (cm / us)) % (Enominal / (V / cm)) % (Bnominal / Tesla) % omegatau_nominal);
4253 }
4254
4255 const std::string AnnularFieldSim::GetFieldString()
4256 {
4257 return boost::str(boost::format("%s, %s") % Efieldname % Bfieldname);
4258 }
4259
4260
4261 TVector3 AnnularFieldSim::GetFieldAt(const TVector3 &pos)
4262 {
4263
4264
4265 int r, p, z;
4266
4267 if (GetRindexAndCheckBounds(pos.Perp(), &r) == BoundsCase::OutOfBounds)
4268 {
4269 return zero_vector;
4270 }
4271 if (GetPhiIndexAndCheckBounds(FilterPhiPos(pos.Phi()), &p) == BoundsCase::OutOfBounds)
4272 {
4273 return zero_vector;
4274 }
4275 if (GetZindexAndCheckBounds(pos.Z(), &z) == BoundsCase::OutOfBounds)
4276 {
4277 if (hasTwin)
4278 {
4279 return twin->GetFieldAt(pos);
4280 }
4281 return zero_vector;
4282 }
4283 return Efield->Get(r, p, z);
4284 }
4285
4286
4287 TVector3 AnnularFieldSim::GetBFieldAt(const TVector3 &pos)
4288 {
4289
4290
4291 int r, p, z;
4292
4293 if (GetRindexAndCheckBounds(pos.Perp(), &r) == BoundsCase::OutOfBounds)
4294 {
4295 return zero_vector;
4296 }
4297 if (GetPhiIndexAndCheckBounds(FilterPhiPos(pos.Phi()), &p) == BoundsCase::OutOfBounds)
4298 {
4299 return zero_vector;
4300 }
4301 if (GetZindexAndCheckBounds(pos.Z(), &z) == BoundsCase::OutOfBounds)
4302 {
4303 if (hasTwin)
4304 {
4305 return twin->GetBFieldAt(pos);
4306 }
4307 return zero_vector;
4308 }
4309 return Bfield->Get(r, p, z);
4310 }
4311
4312
4313 float AnnularFieldSim::GetChargeAt(const TVector3 &pos)
4314 {
4315 int z;
4316 BoundsCase zbound = GetZindexAndCheckBounds(pos.Z(), &z);
4317 if (zbound == OutOfBounds)
4318 {
4319 if (hasTwin)
4320 {
4321 return twin->GetChargeAt(pos);
4322 }
4323 std::cout << boost::str(boost::format("Caution: tried to read charge at zbin=%d! No twin available to handle this") % z) << std::endl;
4324 return -999;
4325 }
4326
4327 return q->GetChargeAtPosition(pos.Perp(), FilterPhiPos(pos.Phi()), pos.Z());
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341 }