LCOV - code coverage report
Current view: top level - src/magneticField - TF17Field.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 196 0.0 %
Date: 2024-04-29 14:43:01 Functions: 0 29 0.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 1.14