LCOV - code coverage report
Current view: top level - src/magneticField - TF17Field.cpp (source / functions) Coverage Total Hit
Test: coverage.info.cleaned Lines: 0.0 % 196 0
Test Date: 2026-06-18 09:49:19 Functions: 0.0 % 29 0

            Line data    Source code
       1              : #include "crpropa/magneticField/TF17Field.h"
       2              : #include "crpropa/Units.h"
       3              : 
       4              : #include <algorithm>
       5              : #include <string>
       6              : 
       7              : namespace crpropa {
       8              : using namespace std;
       9              : 
      10            0 : TF17Field::TF17Field(TF17DiskModel disk_model_, TF17HaloModel halo_model_) {
      11            0 :     disk_model = disk_model_; 
      12            0 :     halo_model = halo_model_;
      13              : 
      14            0 :     useHaloField = true;
      15            0 :     useDiskField = true;
      16              : 
      17            0 :     if ((halo_model == TF17HaloModel::C0) && (disk_model == TF17DiskModel::Ad1)) {
      18              :         // disk parameters
      19            0 :         set_r1_disk(3 * kpc);
      20            0 :         set_B1_disk(19.0 * muG);
      21            0 :         set_H_disk(0.055 * kpc);
      22            0 :         set_phi_star_disk(-54 * M_PI / 180);
      23            0 :         set_a_disk(0.9 / kpc / kpc);
      24              :         // halo parameters
      25            0 :         set_z1_halo(0);
      26            0 :         set_B1_halo(0.36 * muG);
      27            0 :         set_L_halo(3.0 * kpc);
      28            0 :         set_a_halo(1.17 / kpc / kpc);
      29              :         // shared parameters
      30            0 :         set_p0(-7.9 * M_PI / 180);
      31            0 :         set_Hp(5 * kpc);
      32            0 :         set_Lp(50 * kpc); // > 18 kpc
      33              :             
      34            0 :     } else if ((halo_model == TF17HaloModel::C0) && (disk_model == TF17DiskModel::Bd1)) {
      35              :         // disk parameters
      36            0 :         set_r1_disk(3 * kpc);
      37            0 :         set_B1_disk(2.0 * muG);
      38            0 :         set_H_disk(0.32 * kpc);
      39            0 :         set_phi_star_disk(153 * M_PI / 180);
      40              :         // halo parameters
      41            0 :         set_z1_halo(0);
      42            0 :         set_B1_halo(0.29 * muG);
      43            0 :         set_L_halo(3.4 * kpc);
      44            0 :         set_a_halo(0.88 / kpc / kpc);
      45              :         // shared parameters
      46            0 :         set_p0(-7.2 * M_PI / 180);
      47            0 :         set_Hp(9 * kpc);
      48            0 :         set_Lp(50 * kpc); // > 16 kpc
      49              : 
      50            0 :     } else if ((halo_model == TF17HaloModel::C0) && (disk_model == TF17DiskModel::Dd1)) {
      51              :         // disk parameters
      52            0 :         set_z1_disk(1.5 * kpc);
      53            0 :         set_B1_disk(0.065 * muG);
      54            0 :         set_L_disk(9.8 * kpc);
      55            0 :         set_phi_star_disk(14 * M_PI / 180);
      56              :         // halo parameters
      57            0 :         set_z1_halo(0);
      58            0 :         set_B1_halo(0.18 * muG);
      59            0 :         set_L_halo(4.8 * kpc);
      60            0 :         set_a_halo(0.61 / kpc / kpc);
      61              :         // shared parameters
      62            0 :         set_p0(-7.4 * M_PI / 180);
      63            0 :         set_Hp(4.2 * kpc);
      64            0 :         set_Lp(50 * kpc); // > 22 kpc
      65              : 
      66            0 :     } else if ((halo_model == TF17HaloModel::C1) && (disk_model == TF17DiskModel::Ad1)) {
      67              :         // disk parameters
      68            0 :         set_r1_disk(3 * kpc);
      69            0 :         set_B1_disk(32.0 * muG);
      70            0 :         set_H_disk(0.054 * kpc);
      71            0 :         set_phi_star_disk(-31 * M_PI / 180);
      72            0 :         set_a_disk(0.031 / kpc / kpc);
      73              :         // halo parameters
      74            0 :         set_z1_halo(0);
      75            0 :         set_B1_halo(9.0 * muG);
      76            0 :         set_L_halo(2.1 * kpc);
      77            0 :         set_phi_star_halo(198 * M_PI / 180);
      78            0 :         set_a_halo(0.33 / kpc / kpc);
      79              :         // shared parameters
      80            0 :         set_p0(-9.1 * M_PI / 180);
      81            0 :         set_Hp(1.2 * kpc);
      82            0 :         set_Lp(50 * kpc); // > 38 kpc
      83              : 
      84            0 :     } else if ((halo_model == TF17HaloModel::C1) && (disk_model == TF17DiskModel::Bd1)) {
      85              :         // disk parameters
      86            0 :         set_r1_disk(3 * kpc);
      87            0 :         set_B1_disk(24 * muG);
      88            0 :         set_H_disk(0.090 * kpc);
      89            0 :         set_phi_star_disk(-34 * M_PI / 180);
      90              :         // halo parameters
      91            0 :         set_z1_halo(0);
      92            0 :         set_B1_halo(8.2 * muG);
      93            0 :         set_L_halo(2.2 * kpc);
      94            0 :         set_phi_star_halo(197 * M_PI / 180);
      95            0 :         set_a_halo(0.38 / kpc / kpc);
      96              :         // shared parameters
      97            0 :         set_p0(-9.0 * M_PI / 180);
      98            0 :         set_Hp(1.2 * kpc);
      99            0 :         set_Lp(50 * kpc); // > 38 kpc
     100              : 
     101            0 :     } else if ((halo_model == TF17HaloModel::C1) && (disk_model == TF17DiskModel::Dd1)) {
     102              :         // disk parameters
     103            0 :         set_z1_disk(1.5 * kpc);
     104            0 :         set_B1_disk(0.40 * muG);
     105            0 :         set_L_disk(2.9 * kpc);
     106            0 :         set_phi_star_disk(120 * M_PI / 180);
     107              :         // halo parameters
     108            0 :         set_z1_halo(0);
     109            0 :         set_B1_halo(9.5 * muG);
     110            0 :         set_L_halo(2.1 * kpc);
     111            0 :         set_phi_star_halo(179 * M_PI / 180);
     112            0 :         set_a_halo(0.45 / kpc / kpc);
     113              :         // shared parameters
     114            0 :         set_p0(-8.4 * M_PI / 180);
     115            0 :         set_Hp(1.2 * kpc);
     116            0 :         set_Lp(50 * kpc); // > 30 kpc
     117              :     }
     118              : 
     119            0 :     epsilon = std::numeric_limits<double>::epsilon();
     120            0 : }
     121              : 
     122            0 : void TF17Field::setUseDiskField(bool use) {     useDiskField = use; }
     123            0 : void TF17Field::setUseHaloField(bool use) { useHaloField = use; }
     124              : 
     125            0 : bool TF17Field::isUsingDiskField() { return useDiskField; }
     126            0 : bool TF17Field::isUsingHaloField() { return useHaloField; }
     127              : 
     128            0 : void TF17Field::set_B1_disk(const double B1){ B1_disk = B1; }
     129            0 : void TF17Field::set_z1_disk(const double z1){ z1_disk = z1; }
     130            0 : void TF17Field::set_r1_disk(const double r1){ r1_disk = r1; }
     131            0 : void TF17Field::set_H_disk(const double H){ H_disk = H; }
     132            0 : void TF17Field::set_L_disk(const double L){ L_disk = L; }
     133            0 : void TF17Field::set_a_disk(const double a){ a_disk = a; }
     134            0 : void TF17Field::set_phi_star_disk(const double phi){ phi_star_disk = phi; }
     135              : 
     136            0 : void TF17Field::set_B1_halo(const double B1){ B1_halo = B1; }
     137            0 : void TF17Field::set_z1_halo(const double z1){ z1_halo = z1; }
     138            0 : void TF17Field::set_L_halo(const double L){ L_halo = L; }
     139            0 : void TF17Field::set_a_halo(const double a){ a_halo = a; }
     140            0 : void TF17Field::set_phi_star_halo(const double phi){ phi_star_halo = phi; }
     141              : 
     142            0 : void TF17Field::set_Hp(const double H){ H_p = H; }
     143            0 : void TF17Field::set_Lp(const double L){ L_p = L; }
     144            0 : void TF17Field::set_p0(const double p0){ 
     145            0 :     p_0 = p0; 
     146            0 :     cot_p0 = cos(p_0) / sin(p_0);
     147            0 : }
     148              : 
     149            0 : string TF17Field::getDiskModel() const {
     150              :     string model_name;
     151            0 :     switch (disk_model) {
     152              :         case TF17DiskModel::Ad1 : model_name = "Ad1"; break;
     153              :         case TF17DiskModel::Bd1 : model_name = "Bd1"; break;
     154              :         case TF17DiskModel::Dd1 : model_name = "Dd1"; break;
     155              :     }
     156            0 :     return model_name;
     157              : }
     158            0 : string TF17Field::getHaloModel() const {
     159              :     string model_name;
     160            0 :     switch (halo_model) {
     161              :         case TF17HaloModel::C0 : model_name = "C0"; break;
     162              :         case TF17HaloModel::C1 : model_name = "C1"; break;
     163              :     }
     164            0 :     return model_name;
     165              : }
     166              : 
     167              : 
     168            0 : Vector3d TF17Field::getField(const Vector3d& pos) const {
     169            0 :         double r = sqrt(pos.x * pos.x + pos.y * pos.y);  // in-plane radius
     170            0 :         double phi = M_PI - pos.getPhi(); // azimuth in our convention
     171              :         // double cosPhi = pos.x / r;
     172            0 :         double cosPhi = cos(phi);
     173              :         // double sinPhi = pos.y / r;
     174            0 :         double sinPhi = sin(phi);
     175              : 
     176              :         Vector3d b(0.);
     177            0 :         if (useDiskField)
     178            0 :                 b += getDiskField(r, pos.z, phi, sinPhi, cosPhi);       // disk field
     179            0 :         if (useHaloField)
     180            0 :                 b += getHaloField(r, pos.z, phi, sinPhi, cosPhi);       // halo field
     181            0 :         return b;
     182              : }
     183              : 
     184            0 : Vector3d TF17Field::getDiskField(const double& r, const double& z, const double& phi, const double& sinPhi, const double& cosPhi) const {
     185              :         Vector3d b(0.);
     186            0 :     double B_r = 0;
     187              :     double B_phi = 0;
     188            0 :     double B_z = 0;
     189              : 
     190            0 :     if (disk_model == TF17DiskModel::Ad1) { // ==========================================================
     191            0 :         if (r > r1_disk) {
     192            0 :             double z1_disk_z = (1. + a_disk * r1_disk * r1_disk) / (1. + a_disk * r * r); // z1_disk / z
     193              :             // B components in (r, phi, z)
     194            0 :             double B_r0 = radialFieldScale(B1_disk, phi_star_disk, z1_disk_z*z, phi, r, z);
     195            0 :             B_r = (r1_disk / r) * z1_disk_z * B_r0;
     196            0 :             B_z = 2 * a_disk * r1_disk * z1_disk_z*z / (1+ a_disk * r * r) * B_r0;
     197            0 :             B_phi = azimuthalFieldComponent(r, z, B_r, B_z);
     198              :         } else {
     199              :             // within r = r1_disk, the field lines are straight in direction g_phi + phi_star_disk
     200              :             // and thus z = z1
     201            0 :             double phi1_disk = shiftedWindingFunction(r1_disk, z) + phi_star_disk;
     202            0 :             double B_amp = B1_disk * exp(-fabs(z) / H_disk);
     203            0 :             B_r = cos(phi1_disk - phi) * B_amp;
     204            0 :             B_phi = sin(phi1_disk - phi) * B_amp;
     205              :         }
     206              : 
     207            0 :     } else if (disk_model == TF17DiskModel::Bd1) { // ===================================================
     208              :         // for model Bd1, best fit for n = 2 
     209            0 :         if ( r > epsilon ) {
     210            0 :             double r1_disk_r = r1_disk / r;     
     211            0 :             double z1_disk_z = 5. / (r1_disk_r*r1_disk_r + 4./sqrt(r1_disk_r)); // z1_disk / z -> remove z dependancy 
     212            0 :             double B_r0 = radialFieldScale(B1_disk, phi_star_disk, z1_disk_z*z, phi, r, z);
     213            0 :             B_r = r1_disk_r * z1_disk_z * B_r0;
     214            0 :             B_z = -0.4 * r1_disk_r / r * z1_disk_z* z1_disk_z * z * (r1_disk_r*r1_disk_r - 1./sqrt(r1_disk_r)) * B_r0;
     215              :         } else {
     216            0 :             double z1_disk_z = 5. * r*r / (r1_disk*r1_disk); // z1_disk / z -> remove z dependancy 
     217            0 :             double B_r0 = radialFieldScale(B1_disk, phi_star_disk, z1_disk_z*z, phi, r, z);
     218            0 :             B_r = 5. * r / r1_disk * B_r0;
     219            0 :             B_z = -10. * z / r1_disk * B_r0;
     220              :         }
     221            0 :         B_phi = azimuthalFieldComponent(r, z, B_r, B_z);
     222              : 
     223            0 :     } else if (disk_model == TF17DiskModel::Dd1) { // ===================================================
     224              :         // for model Dd1, best fit for n = 0.5 
     225            0 :         double z_sign = z >= 0 ? 1. : -1.; 
     226            0 :         double z_abs = fabs(z); 
     227            0 :         if ( z_abs > epsilon ) {
     228            0 :             double z1_disk_z = z1_disk / z_abs; 
     229            0 :             double r1_disk_r = 1.5 / (sqrt(z1_disk_z) + 0.5/z1_disk_z); // r1_disk / r
     230            0 :             double F_r = r1_disk_r*r  <= L_disk ? 1. : exp(1. - r1_disk_r*r/L_disk);
     231              :         // simplication of the equation in the cosinus
     232            0 :             double B_z0 = z_sign * B1_disk * F_r * cos(phi - shiftedWindingFunction(r, z) - phi_star_disk);
     233            0 :             B_r = -0.5/1.5 * r1_disk_r * r1_disk_r * r1_disk_r * r / z_abs * (sqrt(z1_disk_z) - 1/z1_disk_z) * B_z0;
     234            0 :             B_z = z_sign * r1_disk_r * r1_disk_r * B_z0;
     235              :         } else {
     236            0 :             double z_z1_disk = z_abs / z1_disk; 
     237            0 :             double r1_disk_r = 1.5 * sqrt(z_abs / z1_disk); // r1_disk / r
     238            0 :             double F_r = r1_disk_r*r  <= L_disk ? 1. : exp(1. - r1_disk_r*r/L_disk);
     239            0 :             double B_z0 = z_sign * B1_disk * F_r * cos(phi - shiftedWindingFunction(r, z) - phi_star_disk);
     240            0 :             B_r = -1.125 * r / z1_disk * (1 - 2.5 * z_z1_disk * sqrt(z_z1_disk)) * B_z0;
     241            0 :             B_z = z_sign * r1_disk_r * r1_disk_r * B_z0;
     242              :         }
     243            0 :         B_phi = azimuthalFieldComponent(r, z, B_r, B_z);
     244              :     }
     245              : 
     246              :     // Convert to (x, y, z) components
     247            0 :     b.x = - (B_r * cosPhi - B_phi * sinPhi); // flip x-component at the end
     248            0 :     b.y = B_r * sinPhi + B_phi * cosPhi;
     249            0 :     b.z = B_z;
     250            0 :         return b;
     251              : }
     252              : 
     253            0 : Vector3d TF17Field::getHaloField(const double& r, const double& z, const double& phi, const double& sinPhi, const double& cosPhi) const {
     254              :     int m;
     255              : 
     256              :         Vector3d b(0.);
     257            0 :         double r1_halo_r =  (1. + a_halo * z1_halo * z1_halo) / (1. + a_halo * z * z);
     258              :         // B components in (r, phi, z)
     259              :     double B_z0;
     260              : 
     261            0 :     if (halo_model == TF17HaloModel::C0) { // m = 0
     262            0 :         B_z0 = B1_halo * exp(-r1_halo_r*r / L_halo); 
     263            0 :     } else if (halo_model == TF17HaloModel::C1) { // m = 1
     264              :         // simplication of the equation in the cosinus
     265            0 :         double phi_prime = phi - shiftedWindingFunction(r, z) - phi_star_halo;
     266            0 :         B_z0 = B1_halo * exp(-r1_halo_r*r / L_halo) * cos(phi_prime); 
     267              :     }
     268              : 
     269              :     // Contrary to article, Br has been rewriten to a little bit by replacing
     270              :     // (2 * a * r1**3 * z) / (r**2) by (2 * a * r1**2 * z) / (r * (1+a*z**2))
     271              :     // but that is strictly equivalent except we can reintroduce the z1 in the expression via r1
     272            0 :         double B_r = 2 * a_halo * r1_halo_r * r1_halo_r * r * z / (1. + a_halo * z * z) * B_z0;
     273            0 :         double B_z = r1_halo_r * r1_halo_r * B_z0; 
     274            0 :         double B_phi = azimuthalFieldComponent(r, z, B_r, B_z);
     275              : 
     276              :         // Convert to (x, y, z) components
     277            0 :         b.x = - (B_r * cosPhi - B_phi * sinPhi);        // flip x-component at the end
     278            0 :         b.y = B_r * sinPhi + B_phi * cosPhi;
     279            0 :         b.z = B_z;
     280              : 
     281            0 :         return b;
     282              : }
     283              : 
     284            0 : double TF17Field::azimuthalFieldComponent(const double& r, const double& z, const double& B_r, const double& B_z) const {
     285            0 :         double r_ = r / L_p;
     286            0 :     double rscale = r > epsilon ? r_ * exp(-r_) / (1 - exp(-r_)) : 1 - r_/2. - r_*r_/12. ;
     287            0 :         double B_phi = cot_p0 / zscale(z) * rscale * B_r;
     288            0 :     B_phi = B_phi - 2 * z * r / (H_p * H_p) / zscale(z) * shiftedWindingFunction(r, z) * B_z;
     289            0 :         return B_phi;
     290              : }
     291              : 
     292            0 : double TF17Field::radialFieldScale(const double& B1, const double& phi_star, const double& z1, const double& phi, const double& r, const double& z) const {
     293              :     // simplication of the equation in the cosinus
     294            0 :     double phi_prime = phi - shiftedWindingFunction(r, z) - phi_star;
     295              :         // This term occures is parameterizations of models A and B always bisymmetric (m = 1)
     296            0 :         return B1 * exp(-fabs(z1) / H_disk) * cos(phi_prime);
     297              : }
     298              : 
     299            0 : double TF17Field::shiftedWindingFunction(const double& r, const double& z) const {
     300            0 :     return cot_p0 * log(1 - exp(-r / L_p) + epsilon) / zscale(z);
     301              : }
     302              : 
     303            0 : double TF17Field::zscale(const double& z) const {
     304            0 :         return 1 + z * z / H_p / H_p;
     305              : }
     306              : 
     307              : } // namespace crpropa
        

Generated by: LCOV version 2.0-1