Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-05 08:15:40

0001 #include "Rossegger.h"
0002 
0003 #include <TFile.h>
0004 #include <TMath.h>
0005 #include <TTree.h>
0006 
0007 #pragma GCC diagnostic push
0008 #pragma GCC diagnostic ignored "-Wshadow"
0009 #include <boost/math/special_functions.hpp>  //covers all the special functions.
0010 #pragma GCC diagnostic pop
0011 
0012 #include <boost/format.hpp>
0013 
0014 #include <algorithm>  // for max
0015 #include <cmath>
0016 #include <cstdlib>  // for exit, abs
0017 #include <fstream>
0018 #include <iostream>
0019 #include <sstream>
0020 #include <string>
0021 
0022 // the limu and kimu terms, that i need to think about a little while longer...
0023 extern "C"
0024 {
0025   void dkia_(int *IFAC, double *X, double *A, double *DKI, double *DKID, int *IERRO);
0026   void dlia_(int *IFAC, double *X, double *A, double *DLI, double *DLID, int *IERRO);
0027 }
0028 //
0029 
0030 // Bessel Function J_n(x):
0031 #define jn(order, x) boost::math::cyl_bessel_j(order, x)
0032 // Bessel (Neumann) Function Y_n(x):
0033 #define yn(order, x) boost::math::cyl_neumann(order, x)
0034 // Modified Bessel Function of the first kind I_n(x):
0035 #define in(order, x) boost::math::cyl_bessel_i(order, x)
0036 // Modified Bessel Function of the second kind K_n(x):
0037 #define kn(order, x) boost::math::cyl_bessel_k(order, x)
0038 #define limu(im_order, x) Rossegger::Limu(im_order, x)
0039 #define kimu(im_order, x) Rossegger::Kimu(im_order, x)
0040 
0041 /*
0042   This is a modified/renamed copy of Carlos and Tom's "Spacecharge" class, modified to use boost instead of fortran routines, and with phi terms added.
0043  */
0044 
0045 Rossegger::Rossegger(double InnerRadius, double OuterRadius, double Rdo_Z, double precision)
0046 {
0047   a = InnerRadius;
0048   b = OuterRadius;
0049   L = Rdo_Z;
0050 
0051   epsilon = precision;
0052 
0053   verbosity = 0;
0054   pi = M_PI;
0055 
0056   PrecalcFreeConstants();
0057 
0058   // load the greens functions:
0059   std::string zeroesfilename = boost::str(boost::format("rosseger_zeroes_eps%1.0E_a%2.2f_b%2.2f_L%2.2f.root") % epsilon % a % b % L);
0060   TFile *fileptr = TFile::Open(zeroesfilename.c_str(), "READ");
0061   if (!fileptr)
0062   {  // generate the lookuptable
0063     FindMunk(epsilon);
0064     FindBetamn(epsilon);
0065     SaveZeroes(zeroesfilename);
0066   }
0067   else
0068   {  // load it from a file
0069     fileptr->Close();
0070     LoadZeroes(zeroesfilename);
0071   }
0072 
0073   PrecalcDerivedConstants();
0074 
0075   std::cout << "Rossegger object initialized as follows:" << std::endl;
0076   std::cout << "  Inner Radius = " << a << " cm." << std::endl;
0077   std::cout << "  Outer Radius = " << b << " cm." << std::endl;
0078   std::cout << "  Half  Length = " << L << " cm." << std::endl;
0079 
0080   if (!CheckZeroes(0.01))
0081   {
0082     std::cout << "CheckZeroes(0.01) returned false, exiting" << std::endl;
0083     exit(1);
0084   }
0085   return;
0086 }
0087 
0088 double Rossegger::FindNextZero(double xstart, double localepsilon, int order, double (Rossegger::*func)(int, double))
0089 {
0090   double previous = (this->*func)(order, xstart);
0091   double x = xstart + localepsilon;
0092   double value = previous;
0093 
0094   while (!((value == 0) || (value < 0 && previous > 0) || (value > 0 && previous < 0)))
0095   {
0096     //  Rossegger equation 5.12
0097     value = (this->*func)(order, x);
0098     if (value == 0)
0099     {
0100       std::cout << "hit it exactly!  Go buy a lottery ticket!" << std::endl;
0101     }
0102     if ((value == 0) || (value < 0 && previous > 0) || (value > 0 && previous < 0))
0103     {
0104       // when we go from one sign to the other, we have bracketed the zero
0105       // the following is mathematically equivalent to finding the delta
0106       // between the x of our previous value and the point where we cross the axis
0107       // then returning x0=x_old+delta
0108       double slope = (value - previous) / localepsilon;
0109       double intercept = value - slope * x;
0110       double x0 = -intercept / slope;
0111       if (verbosity > 1)
0112       {
0113         std::cout << " " << x0 << "," << std::endl;
0114       }
0115       double n0 = (this->*func)(order, x - localepsilon);
0116       double n1 = (this->*func)(order, x + localepsilon);
0117       if ((n0 < 0 && n1 < 0) || (n0 > 0 && n1 > 0))
0118       {
0119         std::cout << "neighbors on both sides have the same sign.  Check your function resolution!" << std::endl;
0120       }
0121 
0122       return x0;
0123     }
0124     previous = value;
0125     x += localepsilon;
0126   }
0127   std::cout << "logic break!" << std::endl;
0128   exit(1);
0129 }
0130 
0131 void Rossegger::FindBetamn(double localepsilon)
0132 {
0133   std::cout << "Now filling the Beta[m][n] Array..." << std::endl;
0134   if (verbosity > 5)
0135   {
0136     std::cout << "numberOfOrders= " << NumberOfOrders << std::endl;
0137   }
0138   for (int m = 0; m < NumberOfOrders; m++)
0139   {
0140     if (verbosity)
0141     {
0142       std::cout << "Filling Beta[" << m << "][n]..." << std::endl;
0143     }
0144 
0145     double x = localepsilon;
0146     for (int n = 0; n < NumberOfOrders; n++)
0147     {  //  !!!  Off by one from Rossegger convention  !!!
0148       x = FindNextZero(x, localepsilon, m, &Rossegger::Rmn_for_zeroes);
0149       Betamn[m][n] = x / b;
0150       x += localepsilon;
0151     }
0152   }
0153 
0154   //  Now fill in the N2mn array...
0155   for (int m = 0; m < NumberOfOrders; m++)
0156   {
0157     for (int n = 0; n < NumberOfOrders; n++)
0158     {
0159       //  Rossegger Equation 5.17
0160       //  N^2_mn = 2/(pi * beta)^2 [ {Jm(beta a)/Jm(beta b)}^2 - 1 ]
0161       N2mn[m][n] = 2 / (pi * pi * Betamn[m][n] * Betamn[m][n]);
0162       // N2mn[m][n] *= (jn(m,Betamn[m][n]*a)*jn(m,Betamn[m][n]*a)/jn(m,Betamn[m][n]*b)/jn(m,Betamn[m][n]*b) - 1.0);
0163       double jna_over_jnb = jn(m, Betamn[m][n] * a) / jn(m, Betamn[m][n] * b);
0164       N2mn[m][n] *= (jna_over_jnb * jna_over_jnb - 1.0);
0165       // rcc note!  in eq 5.17, N2nm is set with betamn[m][n], but from context that looks to be a typo.  The order is mn everywhere else
0166       if (verbosity > 1)
0167       {
0168         std::cout << "m: " << m << " n: " << n << " N2[m][n]: " << N2mn[m][n];
0169       }
0170       double step = 0.01;
0171       if (verbosity > 1)
0172       {
0173         double integral = 0.0;
0174         for (double r = a; r < b; r += step)
0175         {
0176           double rmnval = Rmn(m, n, r);
0177 
0178           integral += rmnval * rmnval * r * step;  // Rmn(m,n,r)*Rmn(m,n,r)*r*step;
0179         }
0180         std::cout << " Int: " << integral << std::endl;
0181       }
0182       // N2mn[m][n] = integral;
0183     }
0184   }
0185 
0186   std::cout << "Done." << std::endl;
0187 }
0188 
0189 void Rossegger::FindMunk(double localepsilon)
0190 {
0191   std::cout << "Now filling the Mu[n][k] Array..." << std::endl;
0192   if (verbosity > 5)
0193   {
0194     std::cout << "numberOfOrders= " << NumberOfOrders << std::endl;
0195   }
0196   // We're looking for the zeroes of Rossegger eqn. 5.46:
0197   // R_nk(mu_nk;a,b)=Limu(Beta_n*a)Kimu(Beta_n*b)-Kimu(Beta_n*a)Limu(Beta_n*b)=0
0198   // since a and b are fixed, R_nk is a function solely of mu_nk and n.
0199   // for each 'n' we wish to find the a set of k mu_n's that result in R_nk=0
0200 
0201   // could add an option here to load the munks from file if the dimensions match.
0202 
0203   for (int n = 0; n < NumberOfOrders; n++)  //  !!!  Off by one from Rossegger convention  !!!
0204   {
0205     if (verbosity)
0206     {
0207       std::cout << "Filling Mu[" << n << "][k]..." << std::endl;
0208     }
0209     double x = localepsilon;
0210     for (int k = 0; k < NumberOfOrders; k++)
0211     {
0212       x = FindNextZero(x, localepsilon, n, &Rossegger::Rnk_for_zeroes);
0213       Munk[n][k] = x;
0214       x += localepsilon;
0215       if (verbosity > 0)
0216       {
0217         std::cout << boost::str(boost::format("Mu[%d][%d]=%E") % n % k % Munk[n][k]) << std::endl;
0218         std::cout << boost::str(boost::format("adjacent values are Rnk[mu-localepsilon]=%E\tRnk[mu+localepsilon]=%E") % (Rnk_for_zeroes(n, x - localepsilon)) % (Rnk_for_zeroes(n, x + localepsilon))) << std::endl;
0219         if (verbosity > 100)
0220         {
0221           std::cout << "values of argument to limu and kimu are " << ((n + 1) * pi / L * a)
0222                     << " and " << ((n + 1) * pi / L * b) << std::endl;
0223         }
0224       }
0225     }
0226   }
0227 
0228   //  Now fill in the N2nk array...
0229   for (int n = 0; n < NumberOfOrders; n++)
0230   {
0231     for (int k = 0; k < NumberOfOrders; k++)
0232     {
0233       //  Rossegger Equation 5.48
0234       //  Integral of R_nk(r)*R_ns(r) dr/r= delta_ks*N2nk
0235       //  note that unlike N2mn, there is no convenient shortcut here.
0236       double integral = 0.0;
0237       double step = 0.001;
0238 
0239       for (double r = a; r < b; r += step)
0240       {
0241         double rnkval = Rnk_(n, k, r);  // must used un-optimized.  We don't have those values yet...
0242 
0243         integral += rnkval * rnkval / r * step;
0244       }
0245       if (verbosity > 1)
0246       {
0247         std::cout << " Int: " << integral << std::endl;
0248       }
0249       N2nk[n][k] = integral;
0250       if (verbosity > 1)
0251       {
0252         std::cout << "n: " << n << " k: " << k << " N2nk[n][k]: " << N2nk[n][k];
0253       }
0254     }
0255   }
0256 
0257   std::cout << "Done." << std::endl;
0258   return;
0259 }
0260 
0261 bool Rossegger::CheckZeroes(double localepsilon)
0262 {
0263   // confirm that the tabulated zeroes are all zeroes of their respective functions:
0264   double result;
0265   for (int m = 0; m < NumberOfOrders; m++)
0266   {
0267     for (int n = 0; n < NumberOfOrders; n++)
0268     {  //  !!!  Off by one from Rossegger convention  !!!
0269       result = Rmn_for_zeroes(m, Betamn[m][n] * b);
0270       if (abs(result) > localepsilon)
0271       {
0272         std::cout << boost::str(boost::format("(m=%d,n=%d) Jm(x)Ym(lx)-Jm(lx)Ym(x) = %f for x=b*%f") % m % n % result % Betamn[m][n]) << std::endl;
0273         return false;
0274       }
0275     }
0276   }
0277 
0278   // R_nk(mu_nk;a,b)=Limu(Beta_n*a)Kimu(Beta_n*b)-Kimu(Beta_n*a)Limu(Beta_n*b)=0
0279   for (int n = 0; n < NumberOfOrders; n++)
0280   {
0281     for (int k = 0; k < NumberOfOrders; k++)
0282     {  //  !!!  Off by one from Rossegger convention  !!!
0283       result = Rnk_for_zeroes(n, Munk[n][k]);
0284       if (abs(result) > localepsilon * 100)
0285       {
0286         std::cout << boost::str(boost::format("(n=%d,k=%d) limu(npi*a/L)kimu(npi*b/L)-kimu(npi*a/L)kimu(npi*b/L) = %f (>eps*100) for mu=%f") % n % k % result % Munk[n][k]) << std::endl;
0287         return false;
0288       }
0289     }
0290   }
0291 
0292   return true;
0293 }
0294 
0295 void Rossegger::PrecalcFreeConstants()
0296 {  // Routine used to fill the arrays of other values used repeatedly
0297   // these constants depend only on the geometry of the detector
0298   std::cout << "Precalcing " << (3 * NumberOfOrders + 5 * NumberOfOrders * NumberOfOrders)
0299             << "geometric constants" << std::endl;
0300   for (int n = 0; n < NumberOfOrders; n++)
0301   {
0302     BetaN[n] = (n + 1) * pi / L;  //  BetaN=(n+1)*pi/L as used in eg 5.32, .46
0303     BetaN_a[n] = BetaN[n] * a;    //  BetaN*a as used in eg 5.32, .46
0304     BetaN_b[n] = BetaN[n] * b;    //  BetaN*b as used in eg 5.32, .46
0305     for (int m = 0; m < NumberOfOrders; m++)
0306     {
0307       km_BetaN_a[m][n] = kn(m, BetaN_a[n]);                                                                                                                      // kn(m,BetaN*a) as used in Rossegger 5.32
0308       im_BetaN_a[m][n] = in(m, BetaN_a[n]);                                                                                                                      // in(m,BetaN*a) as used in Rossegger 5.32
0309       km_BetaN_b[m][n] = kn(m, BetaN_b[n]);                                                                                                                      // kn(m,BetaN*b) as used in Rossegger 5.33
0310       im_BetaN_b[m][n] = in(m, BetaN_b[n]);                                                                                                                      // in(m,BetaN*b) as used in Rossegger 5.33
0311       bessel_denominator[m][n] = TMath::BesselI(m, BetaN_a[n]) * TMath::BesselK(m, BetaN_b[n]) - TMath::BesselI(m, BetaN_b[n]) * TMath::BesselK(m, BetaN_a[n]);  // TMath::BesselI(m,BetaN*a)*TMath::BesselK(m,BetaN*b)-TMath::BesselI(m,BetaN*b)*TMath::BesselK(m,BetaN*a) as in Rossegger 5.65
0312     }
0313   }
0314   return;
0315 }
0316 void Rossegger::PrecalcDerivedConstants()
0317 {  // Routine used to fill the arrays of other values used repeatedly
0318    // these constants depend on geometry and the zeroes of special functions
0319   std::cout << "Precalcing " << (6 * NumberOfOrders * NumberOfOrders)
0320             << " geometric constants" << std::endl;
0321 
0322   for (int n = 0; n < NumberOfOrders; n++)
0323   {
0324     for (int m = 0; m < NumberOfOrders; m++)
0325     {
0326       ym_Betamn_a[m][n] = yn(m, Betamn[m][n] * a);   // yn(m,Betamn[m][n]*a) as used in Rossegger 5.11
0327       jm_Betamn_a[m][n] = jn(m, Betamn[m][n] * a);   // jn(m,Betamn[m][n]*a) as used in Rossegger 5.11
0328       sinh_Betamn_L[m][n] = sinh(Betamn[m][n] * L);  // sinh(Betamn[m][n]*L)  as in Rossegger 5.64
0329     }
0330     for (int k = 0; k < NumberOfOrders; k++)
0331     {
0332       liMunk_BetaN_a[n][k] = limu(Munk[n][k], BetaN_a[n]);  // limu(Munk[n][k],BetaN*a) as used in Rossegger 5.45
0333       kiMunk_BetaN_a[n][k] = kimu(Munk[n][k], BetaN_a[n]);  // kimu(Munk[n][k],BetaN*a) as used in Rossegger 5.45
0334       sinh_pi_Munk[n][k] = sinh(pi * Munk[n][k]);           // sinh(pi*Munk[n][k]) as in Rossegger 5.66
0335     }
0336   }
0337   return;
0338 }
0339 
0340 double Rossegger::Limu(double mu, double x)
0341 {
0342   // defined in Rossegger eqn 5.44, also a canonical 'satisfactory companion' to Kimu.
0343   // could use Griddit?
0344   //   Rossegger Equation 5.45
0345   //        Rnk(r) = Limu_nk (BetaN a) Kimu_nk (BetaN r) - Kimu_nk(BetaN a) Limu_nk (BetaN r)
0346 
0347   int IFAC = 1;
0348   double A = mu;
0349   double DLI = 0;
0350   double DERR = 0;
0351   int IERRO = 0;
0352 
0353   double X = x;
0354   dlia_(&IFAC, &X, &A, &DLI, &DERR, &IERRO);
0355   return DLI;
0356 }
0357 double Rossegger::Kimu(double mu, double x)
0358 {
0359   int IFAC = 1;
0360   double A = mu;
0361   double DKI = 0;
0362   double DERR = 0;
0363   int IERRO = 0;
0364 
0365   double X = x;
0366   dkia_(&IFAC, &X, &A, &DKI, &DERR, &IERRO);
0367   return DKI;
0368 }
0369 
0370 double Rossegger::Rmn_for_zeroes(int m, double x)
0371 {
0372   double lx = a * x / b;
0373   //  Rossegger Equation 5.12:
0374 
0375   return jn(m, x) * yn(m, lx) - jn(m, lx) * yn(m, x);
0376 }
0377 
0378 double Rossegger::Rmn(int m, int n, double r)
0379 {
0380   if (verbosity > 100)
0381   {
0382     std::cout << "Determine Rmn(" << m << "," << n << "," << r << ") = ";
0383   }
0384 
0385   //  Check input arguments for sanity...
0386   int error = 0;
0387   if (m < 0 || m >= NumberOfOrders)
0388   {
0389     error = 1;
0390   }
0391   if (n < 0 || n >= NumberOfOrders)
0392   {
0393     error = 1;
0394   }
0395   if (r < a || r > b)
0396   {
0397     error = 1;
0398   }
0399   if (error)
0400   {
0401     std::cout << "Invalid arguments Rmn(" << m << "," << n << "," << r << ")" << std::endl;
0402     ;
0403     return 0;
0404   }
0405 
0406   //  Calculate the function using C-libraries from boost
0407   //  Rossegger Equation 5.11:
0408   //         Rmn(r) = Ym(Beta_mn a)*Jm(Beta_mn r) - Jm(Beta_mn a)*Ym(Beta_mn r)
0409   double R = 0;
0410   R = ym_Betamn_a[m][n] * jn(m, Betamn[m][n] * r) - jm_Betamn_a[m][n] * yn(m, Betamn[m][n] * r);
0411 
0412   if (verbosity > 100)
0413   {
0414     std::cout << R << std::endl;
0415   }
0416   return R;
0417 }
0418 
0419 double Rossegger::Rmn_(int m, int n, double r)
0420 {
0421   if (verbosity > 100)
0422   {
0423     std::cout << "Determine Rmn(" << m << "," << n << "," << r << ") = ";
0424   }
0425 
0426   //  Check input arguments for sanity...
0427   int error = 0;
0428   if (m < 0 || m >= NumberOfOrders)
0429   {
0430     error = 1;
0431   }
0432   if (n < 0 || n >= NumberOfOrders)
0433   {
0434     error = 1;
0435   }
0436   if (r < a || r > b)
0437   {
0438     error = 1;
0439   }
0440   if (error)
0441   {
0442     std::cout << "Invalid arguments Rmn(" << m << "," << n << "," << r << ")" << std::endl;
0443     ;
0444     return 0;
0445   }
0446 
0447   //  Calculate the function using C-libraries from boost
0448   //  Rossegger Equation 5.11:
0449   //         Rmn(r) = Ym(Beta_mn a)*Jm(Beta_mn r) - Jm(Beta_mn a)*Ym(Beta_mn r)
0450   double R = 0;
0451   R = yn(m, Betamn[m][n] * a) * jn(m, Betamn[m][n] * r) - jn(m, Betamn[m][n] * a) * yn(m, Betamn[m][n] * r);
0452 
0453   if (verbosity > 100)
0454   {
0455     std::cout << R << std::endl;
0456   }
0457   return R;
0458 }
0459 
0460 double Rossegger::Rmn1(int m, int n, double r)
0461 {
0462   //  Check input arguments for sanity...
0463   int error = 0;
0464   if (m < 0 || m >= NumberOfOrders)
0465   {
0466     error = 1;
0467   }
0468   if (n < 0 || n >= NumberOfOrders)
0469   {
0470     error = 1;
0471   }
0472   if (r < a || r > b)
0473   {
0474     error = 1;
0475   }
0476   if (error)
0477   {
0478     std::cout << "Invalid arguments Rmn1(" << m << "," << n << "," << r << ")" << std::endl;
0479     ;
0480     return 0;
0481   }
0482 
0483   //  Calculate using the TMath functions from root.
0484   //  Rossegger Equation 5.32
0485   //         Rmn1(r) = Km(BetaN a)Im(BetaN r) - Im(BetaN a) Km(BetaN r)
0486   double R = 0;
0487   R = km_BetaN_a[m][n] * in(m, BetaN[n] * r) - im_BetaN_a[m][n] * kn(m, BetaN[n] * r);
0488 
0489   return R;
0490 }
0491 
0492 double Rossegger::Rmn1_(int m, int n, double r)
0493 {
0494   //  Check input arguments for sanity...
0495   int error = 0;
0496   if (m < 0 || m >= NumberOfOrders)
0497   {
0498     error = 1;
0499   }
0500   if (n < 0 || n >= NumberOfOrders)
0501   {
0502     error = 1;
0503   }
0504   if (r < a || r > b)
0505   {
0506     error = 1;
0507   }
0508   if (error)
0509   {
0510     std::cout << "Invalid arguments Rmn1(" << m << "," << n << "," << r << ")" << std::endl;
0511     ;
0512     return 0;
0513   }
0514 
0515   //  Calculate using the TMath functions from root.
0516   //  Rossegger Equation 5.32
0517   //         Rmn1(r) = Km(BetaN a)Im(BetaN r) - Im(BetaN a) Km(BetaN r)
0518   double R = 0;
0519   double BetaN_ = (n + 1) * pi / L;
0520   R = kn(m, BetaN_ * a) * in(m, BetaN_ * r) - in(m, BetaN_ * a) * kn(m, BetaN_ * r);
0521 
0522   return R;
0523 }
0524 
0525 double Rossegger::Rmn2(int m, int n, double r)
0526 {
0527   //  Check input arguments for sanity...
0528   int error = 0;
0529   if (m < 0 || m >= NumberOfOrders)
0530   {
0531     error = 1;
0532   }
0533   if (n < 0 || n >= NumberOfOrders)
0534   {
0535     error = 1;
0536   }
0537   if (r < a || r > b)
0538   {
0539     error = 1;
0540   }
0541   if (error)
0542   {
0543     std::cout << "Invalid arguments Rmn2(" << m << "," << n << "," << r << ")" << std::endl;
0544     ;
0545     return 0;
0546   }
0547 
0548   //  Calculate using the TMath functions from root.
0549   //  Rossegger Equation 5.33
0550   //         Rmn2(r) = Km(BetaN b)Im(BetaN r) - Im(BetaN b) Km(BetaN r)
0551   double R = 0;
0552   R = km_BetaN_b[m][n] * in(m, BetaN[n] * r) - im_BetaN_b[m][n] * kn(m, BetaN[n] * r);
0553 
0554   return R;
0555 }
0556 
0557 double Rossegger::Rmn2_(int m, int n, double r)
0558 {
0559   //  Check input arguments for sanity...
0560   int error = 0;
0561   if (m < 0 || m >= NumberOfOrders)
0562   {
0563     error = 1;
0564   }
0565   if (n < 0 || n >= NumberOfOrders)
0566   {
0567     error = 1;
0568   }
0569   if (r < a || r > b)
0570   {
0571     error = 1;
0572   }
0573   if (error)
0574   {
0575     std::cout << "Invalid arguments Rmn2(" << m << "," << n << "," << r << ")" << std::endl;
0576     ;
0577     return 0;
0578   }
0579 
0580   //  Calculate using the TMath functions from root.
0581   //  Rossegger Equation 5.33
0582   //         Rmn2(r) = Km(BetaN b)Im(BetaN r) - Im(BetaN b) Km(BetaN r)
0583   double R = 0;
0584   double BetaN_ = (n + 1) * pi / L;
0585   R = kn(m, BetaN_ * b) * in(m, BetaN_ * r) - in(m, BetaN_ * b) * kn(m, BetaN_ * r);
0586 
0587   return R;
0588 }
0589 
0590 double Rossegger::RPrime(int m, int n, double ref, double r)
0591 {
0592   //  Check input arguments for sanity...
0593   int error = 0;
0594   if (m < 0 || m >= NumberOfOrders)
0595   {
0596     error = 1;
0597   }
0598   if (n < 0 || n >= NumberOfOrders)
0599   {
0600     error = 1;
0601   }
0602   if (ref < a || ref > b)
0603   {
0604     error = 1;
0605   }
0606   if (r < a || r > b)
0607   {
0608     error = 1;
0609   }
0610   if (error)
0611   {
0612     std::cout << "Invalid arguments RPrime(" << m << "," << n << "," << ref << "," << r << ")" << std::endl;
0613     ;
0614     return 0;
0615   }
0616 
0617   double R = 0;
0618   //  Calculate using the TMath functions from root.
0619   //  Rossegger Equation 5.65
0620   //         Rmn2(ref,r) = BetaN/2* [   Km(BetaN ref) {Im-1(BetaN r) + Im+1(BetaN r)}
0621   //                                  - Im(BetaN ref) {Km-1(BetaN r) + Km+1(BetaN r)}  ]
0622   //  NOTE:  K-m(z) = Km(z) and I-m(z) = Im(z)... though boost handles negative orders.
0623   //
0624   // with: s -> ref,  t -> r,
0625   double BetaN_ = BetaN[n];
0626   double term1 = kn(m, BetaN_ * ref) * (in(m - 1, BetaN_ * r) + in(m + 1, BetaN_ * r));
0627   double term2 = in(m, BetaN_ * ref) * (kn(m - 1, BetaN_ * r) + kn(m + 1, BetaN_ * r));
0628   R = BetaN_ / 2.0 * (term1 + term2);
0629 
0630   return R;
0631 }
0632 
0633 double Rossegger::RPrime_(int m, int n, double ref, double r)
0634 {
0635   //  Check input arguments for sanity...
0636   int error = 0;
0637   if (m < 0 || m >= NumberOfOrders)
0638   {
0639     error = 1;
0640   }
0641   if (n < 0 || n >= NumberOfOrders)
0642   {
0643     error = 1;
0644   }
0645   if (ref < a || ref > b)
0646   {
0647     error = 1;
0648   }
0649   if (r < a || r > b)
0650   {
0651     error = 1;
0652   }
0653   if (error)
0654   {
0655     std::cout << "Invalid arguments RPrime(" << m << "," << n << "," << ref << "," << r << ")" << std::endl;
0656     ;
0657     return 0;
0658   }
0659 
0660   double R = 0;
0661   //  Rossegger Equation 5.65
0662   //         Rmn2(ref,r) = BetaN/2* [   Km(BetaN ref) {Im-1(BetaN r) + Im+1(BetaN r)}
0663   //                                  - Im(BetaN ref) {Km-1(BetaN r) + Km+1(BetaN r)}  ]
0664   //  NOTE:  K-m(z) = Km(z) and I-m(z) = Im(z)... though boost handles negative orders.
0665   //
0666   // with: s -> ref,  t -> r,
0667   double BetaN_ = (n + 1) * pi / L;
0668   double term1 = kn(m, BetaN_ * ref) * (in(m - 1, BetaN_ * r) + in(m + 1, BetaN_ * r));
0669   double term2 = in(m, BetaN_ * ref) * (kn(m - 1, BetaN_ * r) + kn(m + 1, BetaN_ * r));
0670   R = BetaN_ / 2.0 * (term1 + term2);
0671 
0672   return R;
0673 }
0674 
0675 double Rossegger::Rnk_for_zeroes(int n, double mu)
0676 {
0677   // unlike Rossegger, we count 'k' and 'n' from zero.
0678   if (verbosity > 10)
0679   {
0680     std::cout << "Rnk_for_zeroes called with n=" << n << ",mu=" << mu << std::endl;
0681   }
0682   double betana = BetaN_a[n];
0683   double betanb = BetaN_b[n];
0684   //  Rossegger Equation 5.46
0685   //       Rnk(r) = Limu_nk (BetaN a) Kimu_nk (BetaN b) - Kimu_nk(BetaN a) Limu_nk (BetaN b)
0686 
0687   return limu(mu, betana) * kimu(mu, betanb) - kimu(mu, betana) * limu(mu, betanb);
0688 }
0689 
0690 double Rossegger::Rnk_for_zeroes_(int n, double mu)
0691 {
0692   // unlike Rossegger, we count 'k' and 'n' from zero.
0693   if (verbosity > 10)
0694   {
0695     std::cout << "Rnk_for_zeroes called with n=" << n << ",mu=" << mu << std::endl;
0696   }
0697   double BetaN_ = (n + 1) * pi / L;  // this is defined in the paragraph before 5.46
0698   double betana = BetaN_ * a;
0699   double betanb = BetaN_ * b;
0700   //  Rossegger Equation 5.46
0701   //       Rnk(r) = Limu_nk (BetaN a) Kimu_nk (BetaN b) - Kimu_nk(BetaN a) Limu_nk (BetaN b)
0702 
0703   return limu(mu, betana) * kimu(mu, betanb) - kimu(mu, betana) * limu(mu, betanb);
0704 }
0705 
0706 double Rossegger::Rnk(int n, int k, double r)
0707 {
0708   //  Check input arguments for sanity...
0709   int error = 0;
0710   if (n < 0 || n >= NumberOfOrders)
0711   {
0712     error = 1;
0713   }
0714   if (k < 0 || k >= NumberOfOrders)
0715   {
0716     error = 1;
0717   }
0718   if (r < a || r > b)
0719   {
0720     error = 1;
0721   }
0722   if (error)
0723   {
0724     std::cout << "Invalid arguments Rnk(" << n << "," << k << "," << r << ")" << std::endl;
0725     ;
0726     return 0;
0727   }
0728   //  Rossegger Equation 5.45
0729   //       Rnk(r) = Limu_nk (BetaN a) Kimu_nk (BetaN r) - Kimu_nk(BetaN a) Limu_nk (BetaN r)
0730 
0731   return liMunk_BetaN_a[n][k] * kimu(Munk[n][k], BetaN[n] * r) - kiMunk_BetaN_a[n][k] * limu(Munk[n][k], BetaN[n] * r);
0732 }
0733 
0734 double Rossegger::Rnk_(int n, int k, double r)
0735 {
0736   //  Check input arguments for sanity...
0737   int error = 0;
0738   if (n < 0 || n >= NumberOfOrders)
0739   {
0740     error = 1;
0741   }
0742   if (k < 0 || k >= NumberOfOrders)
0743   {
0744     error = 1;
0745   }
0746   if (r < a || r > b)
0747   {
0748     error = 1;
0749   }
0750   if (error)
0751   {
0752     std::cout << "Invalid arguments Rnk(" << n << "," << k << "," << r << ")" << std::endl;
0753     ;
0754     return 0;
0755   }
0756   double BetaN_ = (n + 1) * pi / L;
0757   //  Rossegger Equation 5.45
0758   //       Rnk(r) = Limu_nk (BetaN a) Kimu_nk (BetaN r) - Kimu_nk(BetaN a) Limu_nk (BetaN r)
0759 
0760   return limu(Munk[n][k], BetaN_ * a) * kimu(Munk[n][k], BetaN_ * r) - kimu(Munk[n][k], BetaN_ * a) * limu(Munk[n][k], BetaN_ * r);
0761 }
0762 
0763 double Rossegger::Ez(double r, double phi, double z, double r1, double phi1, double z1)
0764 {
0765   // rcc streamlined Ez
0766   int error = 0;
0767   if (r < a || r > b)
0768   {
0769     error = 1;
0770   }
0771   if (phi < 0 || phi > 2 * pi)
0772   {
0773     error = 1;
0774   }
0775   if (z < 0 || z > L)
0776   {
0777     error = 1;
0778   }
0779   if (r1 < a || r1 > b)
0780   {
0781     error = 1;
0782   }
0783   if (phi1 < 0 || phi1 > 2 * pi)
0784   {
0785     error = 1;
0786   }
0787   if (z1 < 0 || z1 > L)
0788   {
0789     error = 1;
0790   }
0791   if (error)
0792   {
0793     std::cout << "Invalid arguments Ez(";
0794     std::cout << r << ",";
0795     std::cout << phi << ",";
0796     std::cout << z << ",";
0797     std::cout << r1 << ",";
0798     std::cout << phi1 << ",";
0799     std::cout << z1;
0800     std::cout << ")" << std::endl;
0801     ;
0802     return 0;
0803   }
0804   // Rossegger Equation 5.64
0805   double G = 0;
0806   for (int m = 0; m < NumberOfOrders; m++)
0807   {
0808     if (verbosity > 10)
0809     {
0810       std::cout << std::endl
0811                 << m;
0812     }
0813     for (int n = 0; n < NumberOfOrders; n++)
0814     {
0815       if (verbosity > 10)
0816       {
0817         std::cout << " " << n;
0818       }
0819       double term = 1;  // unitless
0820       if (verbosity > 10)
0821       {
0822         std::cout << " " << term;
0823       }
0824       term *= (2 - ((m == 0) ? 1 : 0)) * cos(m * (phi - phi1));  // unitless
0825       if (verbosity > 10)
0826       {
0827         std::cout << " " << term;
0828       }
0829       term *= Rmn(m, n, r) * Rmn(m, n, r1) / N2mn[m][n];  // units of 1/[L]^2
0830       if (verbosity > 10)
0831       {
0832         std::cout << " " << term;
0833       }
0834       if (z < z1)
0835       {
0836         term *= cosh(Betamn[m][n] * z) * sinh(Betamn[m][n] * (L - z1)) / sinh_Betamn_L[m][n];  // unitless
0837       }
0838       else
0839       {
0840         term *= -cosh(Betamn[m][n] * (L - z)) * sinh(Betamn[m][n] * z1) / sinh_Betamn_L[m][n];  // unitless
0841       }
0842       if (verbosity > 10)
0843       {
0844         std::cout << " " << term;
0845       }
0846       G += term;
0847       if (verbosity > 10)
0848       {
0849         std::cout << " " << term << " " << G << std::endl;
0850       }
0851     }
0852   }
0853 
0854   G = G / (2.0 * pi);
0855   if (verbosity)
0856   {
0857     std::cout << "Ez = " << G << std::endl;
0858   }
0859 
0860   return G;
0861 }
0862 
0863 double Rossegger::Ez_(double r, double phi, double z, double r1, double phi1, double z1)
0864 {
0865   // if(fByFile && fabs(r-r1)>MinimumDR && fabs(z-z1)>MinimumDZ) return ByFileEZ(r,phi,z,r1,phi1,z1);
0866   //   Check input arguments for sanity...
0867   int error = 0;
0868   if (r < a || r > b)
0869   {
0870     error = 1;
0871   }
0872   if (phi < 0 || phi > 2 * pi)
0873   {
0874     error = 1;
0875   }
0876   if (z < 0 || z > L)
0877   {
0878     error = 1;
0879   }
0880   if (r1 < a || r1 > b)
0881   {
0882     error = 1;
0883   }
0884   if (phi1 < 0 || phi1 > 2 * pi)
0885   {
0886     error = 1;
0887   }
0888   if (z1 < 0 || z1 > L)
0889   {
0890     error = 1;
0891   }
0892   if (error)
0893   {
0894     std::cout << "Invalid arguments Ez(";
0895     std::cout << r << ",";
0896     std::cout << phi << ",";
0897     std::cout << z << ",";
0898     std::cout << r1 << ",";
0899     std::cout << phi1 << ",";
0900     std::cout << z1;
0901     std::cout << ")" << std::endl;
0902     ;
0903     return 0;
0904   }
0905 
0906   double G = 0;
0907   for (int m = 0; m < NumberOfOrders; m++)
0908   {
0909     if (verbosity > 10)
0910     {
0911       std::cout << std::endl
0912                 << m;
0913     }
0914     for (int n = 0; n < NumberOfOrders; n++)
0915     {
0916       if (verbosity > 10)
0917       {
0918         std::cout << " " << n;
0919       }
0920       double term = 1 / (2.0 * pi);
0921       if (verbosity > 10)
0922       {
0923         std::cout << " " << term;
0924       }
0925       term *= (2 - ((m == 0) ? 1 : 0)) * cos(m * (phi - phi1));  // unitless
0926       if (verbosity > 10)
0927       {
0928         std::cout << " " << term;
0929       }
0930       term *= Rmn(m, n, r) * Rmn(m, n, r1) / N2mn[m][n];  // units of 1/[L]^2
0931       if (verbosity > 10)
0932       {
0933         std::cout << " " << term;
0934       }
0935       if (z < z1)
0936       {
0937         term *= cosh(Betamn[m][n] * z) * sinh(Betamn[m][n] * (L - z1)) / sinh(Betamn[m][n] * L);
0938       }
0939       else
0940       {
0941         term *= -cosh(Betamn[m][n] * (L - z)) * sinh(Betamn[m][n] * z1) / sinh(Betamn[m][n] * L);
0942         ;
0943       }
0944       if (verbosity > 10)
0945       {
0946         std::cout << " " << term;
0947       }
0948       G += term;
0949       if (verbosity > 10)
0950       {
0951         std::cout << " " << term << " " << G << std::endl;
0952       }
0953     }
0954   }
0955   if (verbosity)
0956   {
0957     std::cout << "Ez = " << G << std::endl;
0958   }
0959 
0960   return G;
0961 }
0962 
0963 double Rossegger::Er(double r, double phi, double z, double r1, double phi1, double z1)
0964 {
0965   // rcc streamlined Er
0966 
0967   // as in Rossegger 5.65
0968   // field at r, phi, z due to unit charge at r1, phi1, z1;
0969   // if(fByFile && fabs(r-r1)>MinimumDR && fabs(z-z1)>MinimumDZ) return ByFileER(r,phi,z,r1,phi1,z1);
0970   //   Check input arguments for sanity...
0971   int error = 0;
0972   if (r < a || r > b)
0973   {
0974     error = 1;
0975   }
0976   if (phi < 0 || phi > 2 * pi)
0977   {
0978     error = 1;
0979   }
0980   if (z < 0 || z > L)
0981   {
0982     error = 1;
0983   }
0984   if (r1 < a || r1 > b)
0985   {
0986     error = 1;
0987   }
0988   if (phi1 < 0 || phi1 > 2 * pi)
0989   {
0990     error = 1;
0991   }
0992   if (z1 < 0 || z1 > L)
0993   {
0994     error = 1;
0995   }
0996   if (error)
0997   {
0998     std::cout << "Invalid arguments Er(";
0999     std::cout << r << ",";
1000     std::cout << phi << ",";
1001     std::cout << z << ",";
1002     std::cout << r1 << ",";
1003     std::cout << phi1 << ",";
1004     std::cout << z1;
1005     std::cout << ")" << std::endl;
1006     ;
1007     return 0;
1008   }
1009 
1010   double part = 0;
1011   double G = 0;
1012   for (int m = 0; m < NumberOfOrders; m++)
1013   {
1014     for (int n = 0; n < NumberOfOrders; n++)
1015     {
1016       double term = 1;
1017       part = (2 - ((m == 0) ? 1 : 0)) * cos(m * (phi - phi1));  // unitless
1018       if (verbosity > 10)
1019       {
1020         std::cout << "(2 - ((m==0)?1:0))*cos(m*(phi-phi1)); = " << part << std::endl;
1021       }
1022       term *= part;
1023       part = sin(BetaN[n] * z) * sin(BetaN[n] * z1);  // unitless
1024       if (verbosity > 10)
1025       {
1026         std::cout << "sin(BetaN[n]*z)*sin(BetaN[n]*z1); = " << part << std::endl;
1027       }
1028       term *= part;
1029 
1030       if (r < r1)
1031       {
1032         term *= RPrime(m, n, a, r) * Rmn2(m, n, r1);  // units of 1/[L]
1033       }
1034       else
1035       {
1036         term *= Rmn1(m, n, r1) * RPrime(m, n, b, r);  // units of 1/[L]
1037       }
1038       term /= bessel_denominator[m][n];  // unitless
1039       G += term;
1040     }
1041   }
1042 
1043   G = G / (L * pi);  // units of 1/[L] -- net is 1/[L]^2
1044   if (verbosity)
1045   {
1046     std::cout << "Er = " << G << std::endl;
1047   }
1048 
1049   return G;
1050 }
1051 
1052 double Rossegger::Er_(double r, double phi, double z, double r1, double phi1, double z1)
1053 {
1054   // doesn't take advantage of precalcs.
1055   // as in Rossegger 5.65
1056   // field at r, phi, z due to unit charge at r1, phi1, z1;
1057   // if(fByFile && fabs(r-r1)>MinimumDR && fabs(z-z1)>MinimumDZ) return ByFileER(r,phi,z,r1,phi1,z1);
1058   //   Check input arguments for sanity...
1059   int error = 0;
1060   if (r < a || r > b)
1061   {
1062     error = 1;
1063   }
1064   if (phi < 0 || phi > 2 * pi)
1065   {
1066     error = 1;
1067   }
1068   if (z < 0 || z > L)
1069   {
1070     error = 1;
1071   }
1072   if (r1 < a || r1 > b)
1073   {
1074     error = 1;
1075   }
1076   if (phi1 < 0 || phi1 > 2 * pi)
1077   {
1078     error = 1;
1079   }
1080   if (z1 < 0 || z1 > L)
1081   {
1082     error = 1;
1083   }
1084   if (error)
1085   {
1086     std::cout << "Invalid arguments Er(";
1087     std::cout << r << ",";
1088     std::cout << phi << ",";
1089     std::cout << z << ",";
1090     std::cout << r1 << ",";
1091     std::cout << phi1 << ",";
1092     std::cout << z1;
1093     std::cout << ")" << std::endl;
1094     ;
1095     return 0;
1096   }
1097 
1098   double G = 0;
1099   for (int m = 0; m < NumberOfOrders; m++)
1100   {
1101     for (int n = 0; n < NumberOfOrders; n++)
1102     {
1103       double term = 1 / (L * pi);
1104       term *= (2 - ((m == 0) ? 1 : 0)) * cos(m * (phi - phi1));
1105       double BetaN_ = (n + 1) * pi / L;
1106       term *= sin(BetaN_ * z) * sin(BetaN_ * z1);
1107       if (r < r1)
1108       {
1109         term *= RPrime_(m, n, a, r) * Rmn2_(m, n, r1);
1110       }
1111       else
1112       {
1113         term *= Rmn1_(m, n, r1) * RPrime_(m, n, b, r);
1114       }
1115 
1116       term /= TMath::BesselI(m, BetaN_ * a) * TMath::BesselK(m, BetaN_ * b) - TMath::BesselI(m, BetaN_ * b) * TMath::BesselK(m, BetaN_ * a);
1117 
1118       G += term;
1119     }
1120   }
1121 
1122   if (verbosity)
1123   {
1124     std::cout << "Er = " << G << std::endl;
1125   }
1126 
1127   return G;
1128 }
1129 
1130 double Rossegger::Ephi(double r, double phi, double z, double r1, double phi1, double z1)
1131 {
1132   // rcc streamlined Ephi term
1133   // compute field at rphiz from charge at r1phi1z1
1134   //   Check input arguments for sanity...
1135   int error = 0;
1136   if (r < a || r > b)
1137   {
1138     error = 1;
1139   }
1140   if (phi < 0 || phi > 2 * pi)
1141   {
1142     error = 1;
1143   }
1144   if (z < 0 || z > L)
1145   {
1146     error = 1;
1147   }
1148   if (r1 < a || r1 > b)
1149   {
1150     error = 1;
1151   }
1152   if (phi1 < 0 || phi1 > 2 * pi)
1153   {
1154     error = 1;
1155   }
1156   if (z1 < 0 || z1 > L)
1157   {
1158     error = 1;
1159   }
1160   if (error)
1161   {
1162     std::cout << "Invalid arguments Ephi(";
1163     std::cout << r << ",";
1164     std::cout << phi << ",";
1165     std::cout << z << ",";
1166     std::cout << r1 << ",";
1167     std::cout << phi1 << ",";
1168     std::cout << z1;
1169     std::cout << ")" << std::endl;
1170     ;
1171     return 0;
1172   }
1173 
1174   double G = 0;
1175   // Rossegger Eqn. 5.66:
1176   for (int k = 0; k < NumberOfOrders; k++)
1177   {
1178     for (int n = 0; n < NumberOfOrders; n++)
1179     {
1180       double term = 1;
1181       term *= sin(BetaN[n] * z) * sin(BetaN[n] * z1);     // unitless
1182       term *= Rnk(n, k, r) * Rnk(n, k, r1) / N2nk[n][k];  // unitless?
1183 
1184       // the derivative of cosh(munk(pi-|phi-phi1|)
1185       if (phi > phi1)
1186       {
1187         term *= -sinh(Munk[n][k] * (pi - (phi - phi1)));  // unitless
1188       }
1189       else
1190       {
1191         term *= sinh(Munk[n][k] * (pi - (phi1 - phi)));  // unitless
1192       }
1193       term *= 1 / sinh_pi_Munk[n][k];  // unitless
1194       G += term;
1195     }
1196   }
1197 
1198   G = G / (L * r);  // units of 1/[L]^2.  r comes from the phi term in cylindrical gradient expression.
1199   if (verbosity)
1200   {
1201     std::cout << "Ephi = " << G << std::endl;
1202   }
1203 
1204   return G;
1205 }
1206 
1207 double Rossegger::Ephi_(double r, double phi, double z, double r1, double phi1, double z1)
1208 {
1209   // compute field at rphiz from charge at r1phi1z1
1210   //   Check input arguments for sanity...
1211   int error = 0;
1212   if (r < a || r > b)
1213   {
1214     error = 1;
1215   }
1216   if (phi < 0 || phi > 2 * pi)
1217   {
1218     error = 1;
1219   }
1220   if (z < 0 || z > L)
1221   {
1222     error = 1;
1223   }
1224   if (r1 < a || r1 > b)
1225   {
1226     error = 1;
1227   }
1228   if (phi1 < 0 || phi1 > 2 * pi)
1229   {
1230     error = 1;
1231   }
1232   if (z1 < 0 || z1 > L)
1233   {
1234     error = 1;
1235   }
1236   if (error)
1237   {
1238     std::cout << "Invalid arguments Ephi(";
1239     std::cout << r << ",";
1240     std::cout << phi << ",";
1241     std::cout << z << ",";
1242     std::cout << r1 << ",";
1243     std::cout << phi1 << ",";
1244     std::cout << z1;
1245     std::cout << ")" << std::endl;
1246     ;
1247     return 0;
1248   }
1249 
1250   verbosity = 1;
1251   double G = 0;
1252   // Rossegger Eqn. 5.66:
1253   for (int k = 0; k < NumberOfOrders; k++)  // off by one from Rossegger convention!
1254   {
1255     if (verbosity)
1256     {
1257       std::cout << "\nk=" << k;
1258     }
1259     for (int n = 0; n < NumberOfOrders; n++)  // off by one from Rossegger convention!
1260     {
1261       if (verbosity)
1262       {
1263         std::cout << " n=" << n;
1264       }
1265       double BetaN_ = (n + 1) * pi / L;
1266       double term = 1 / (L * r);
1267       if (verbosity)
1268       {
1269         std::cout << " 1/L=" << term;
1270       }
1271       term *= sin(BetaN_ * z) * sin(BetaN_ * z1);
1272       if (verbosity)
1273       {
1274         std::cout << " *sinsin=" << term;
1275       }
1276       term *= Rnk_(n, k, r) * Rnk_(n, k, r1);
1277       if (verbosity)
1278       {
1279         std::cout << " *rnkrnk=" << term;
1280       }
1281       term /= N2nk[n][k];
1282       if (verbosity)
1283       {
1284         std::cout << " */nnknnk=" << term;
1285       }
1286 
1287       // the derivative of cosh(munk(pi-|phi-phi1|)
1288       if (phi > phi1)
1289       {
1290         term *= -sinh(Munk[n][k] * (pi - (phi - phi1)));
1291         // term *=  Munk[n][k]*sinh(Munk[n][k]*pi*(phi1-phi));
1292         // this originally has a factor of Munk in front, but that cancels with one in the denominator
1293       }
1294       else
1295       {
1296         term *= sinh(Munk[n][k] * (pi - (phi1 - phi)));
1297         // term *=  -Munk[n][k]*sinh(Munk[n][k]*pi*(phi-phi1));
1298         // this originally has a factor of Munk in front, but that cancels with one in the denominator
1299       }
1300       if (verbosity)
1301       {
1302         std::cout << " *sinh(mu*pi-phi-phi)=" << term;
1303       }
1304       term *= 1 / (sinh(pi * Munk[n][k]));
1305       // term *= 1/(Munk[n][k]*sinh(pi*Munk[n][k]));
1306       // this originally has a factor of Munk in front, but that cancels with one in the numerator
1307       G += term;
1308       if (verbosity)
1309       {
1310         std::cout << "  /sinh=" << term << " G=" << G << std::endl;
1311       }
1312     }
1313   }
1314   if (verbosity)
1315   {
1316     std::cout << "Ephi = " << G << std::endl;
1317   }
1318   verbosity = 0;
1319 
1320   return G;
1321 }
1322 
1323 void Rossegger::SaveZeroes(const std::string &destfile)
1324 {
1325   TFile *output = TFile::Open(destfile.c_str(), "RECREATE");
1326   output->cd();
1327 
1328   TTree *tInfo = new TTree("info", "Mu[n][k] values");
1329   int ord = NumberOfOrders;
1330   tInfo->Branch("order", &ord);
1331   tInfo->Branch("epsilon", &epsilon);
1332   tInfo->Fill();
1333 
1334   int n, k, m;
1335   double munk, betamn;
1336   double n2nk, n2mn;
1337   TTree *tmunk = new TTree("munk", "Mu[n][k] values");
1338   tmunk->Branch("n", &n);
1339   tmunk->Branch("k", &k);
1340   tmunk->Branch("munk", &munk);
1341   tmunk->Branch("n2nk", &n2nk);
1342   for (n = 0; n < ord; n++)
1343   {
1344     for (k = 0; k < ord; k++)
1345     {
1346       munk = Munk[n][k];
1347       n2nk = N2nk[n][k];
1348       tmunk->Fill();
1349     }
1350   }
1351 
1352   TTree *tbetamn = new TTree("betamn", "Beta[m][n] values");
1353   tbetamn->Branch("m", &m);
1354   tbetamn->Branch("n", &n);
1355   tbetamn->Branch("betamn", &betamn);
1356   tbetamn->Branch("n2mn", &n2mn);
1357   for (m = 0; m < ord; m++)
1358   {
1359     for (n = 0; n < ord; n++)
1360     {
1361       betamn = Betamn[m][n];
1362       n2mn = N2mn[m][n];
1363       tbetamn->Fill();
1364     }
1365   }
1366 
1367   tInfo->Write();
1368   tmunk->Write();
1369   tbetamn->Write();
1370   // output->Write();
1371   output->Close();
1372   return;
1373 }
1374 
1375 void Rossegger::LoadZeroes(const std::string &destfile)
1376 {
1377   TFile *f = TFile::Open(destfile.c_str(), "READ");
1378   std::cout << "reading rossegger zeroes from " << destfile << std::endl;
1379   TTree *tInfo = (TTree *) (f->Get("info"));
1380   int ord;
1381   tInfo->SetBranchAddress("order", &ord);
1382   tInfo->SetBranchAddress("epsilon", &epsilon);
1383   tInfo->GetEntry(0);
1384   std::cout << "order=" << ord << ",epsilon=" << epsilon << std::endl;
1385 
1386   int n, k, m;
1387   double munk, betamn;
1388   double n2nk, n2mn;
1389   TTree *tmunk = (TTree *) (f->Get("munk"));
1390   tmunk->SetBranchAddress("n", &n);
1391   tmunk->SetBranchAddress("k", &k);
1392   tmunk->SetBranchAddress("munk", &munk);
1393   tmunk->SetBranchAddress("n2nk", &n2nk);
1394   for (int i = 0; i < tmunk->GetEntries(); i++)
1395   {
1396     tmunk->GetEntry(i);
1397     Munk[n][k] = munk;
1398     N2nk[n][k] = n2nk;
1399   }
1400 
1401   TTree *tbetamn = (TTree *) (f->Get("betamn"));
1402   tbetamn->SetBranchAddress("m", &m);
1403   tbetamn->SetBranchAddress("n", &n);
1404   tbetamn->SetBranchAddress("betamn", &betamn);
1405   tbetamn->SetBranchAddress("n2mn", &n2mn);
1406   for (int i = 0; i < tbetamn->GetEntries(); i++)
1407   {
1408     tbetamn->GetEntry(i);
1409     Betamn[m][n] = betamn;
1410     N2mn[m][n] = n2mn;
1411   }
1412 
1413   f->Close();
1414   return;
1415 }