XGCa
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
get_drift_velocity.hpp
Go to the documentation of this file.
1 #ifndef GET_DRIFT_VELOCITY_HPP
2 #define GET_DRIFT_VELOCITY_HPP
3 
4 #include "push_physics.hpp"
5 
6 // Modified from fields_at_point in grid_field_pack. Should consolidate and use GridWeights<Order::Zero>
7 KOKKOS_INLINE_FUNCTION void fields_at_node(const GridFieldPack<DeviceType, PIT_GLOBAL>& gfpack, const PushControls &push_controls, const Grid<DeviceType> &grid, const SimdVector &B, const SimdVector2D &gradpsi, const Simd<int>& global_inds, const SimdGridWeights<Order::One, PIT_GLOBAL> grid_wts, const SimdGyroWeights<KinType::GyroKin>& rho_wts, LocalFields& fld){
8  // Initialize local fields to 0
9  fld.template get<Label::E>().zero();
10 #ifdef EXPLICIT_EM
11  fld.template get<Label::dAh>().zero();
12  fld.template get<Label::dAs>().zero();
13  fld.template get<Label::Ah>().zero();
14  fld.template get<Label::As>().zero();
15  fld.template get<Label::Epar_em>().zero();
16 #endif
17 
18  for (int i_simd = 0; i_simd<SIMD_SIZE; i_simd++){
19  // Field basis correction
20  FieldCorrection field_correction(gradpsi, i_simd);
21 
22  constexpr double wp = 1.0; // No triangle weights since this is on a vertex
23 
24  field_correction.set(i_simd, grid.uses_rz_basis(global_inds[i_simd]), gradpsi);
25 
26  gfpack.gather_all_fields(push_controls, i_simd, global_inds[i_simd], wp, field_correction, grid_wts, rho_wts, fld);
27 
28 #ifdef XGC1
29  // Correct phi component of E-field
30  double Bmag = B.magnitude(i_simd);
31 
32  // Get phi from para
33  gfpack.phi_from_para(fld.template get<Label::E>(), i_simd, B, Bmag);
34 #ifdef EXPLICIT_EM
35  gfpack.phi_from_para(fld.template get<Label::dAh>(), i_simd, B, Bmag);
36  gfpack.phi_from_para(fld.template get<Label::dAs>(), i_simd, B, Bmag);
37 #endif
38 #endif
39  }
40 }
41 
42 // Modified from fields_at_point in grid_field_pack. Should consolidate and use GridWeights<Order::Zero>
44  // Initialize local fields to 0
45  pot_out = 0.0;
46 #ifdef XGC1
47  for (int i_simd = 0; i_simd<SIMD_SIZE; i_simd++){
48  int irho = rho_wts.irho(i_simd);
49  constexpr double wp = 1.0; // No triangle weights since this is on a vertex
50  pot(global_inds[i_simd], irho).gather(pot_out,i_simd, wp, rho_wts, grid_wts.phi_wts, pot(global_inds[i_simd], irho+1));
51  }
52 #endif
53 }
54 
55 // Parallel drift
56 // v_parallel = D*(B_star*dH/dv_p *1/(m*B) + v_p*dB_RMP)
57 // But we move the m/c*u_para*curl(b) part to the magnetic drift term.
58 // The remaining terms form the actual parallel motion along
59 // the perturbed fieldn --> slightly different B_star
60 KOKKOS_INLINE_FUNCTION void get_v_par_drift(double D, const SimdVector& bfield, const SimdVector& tdb, const double (&curl_nb)[3], const LocalFields& fld, double over_B, double cmrho, double gradpsi_r_norm, double gradpsi_z_norm, double (&v_par)[3], int i_simd){
61  // B_star = B+A_s*curl(b) + grad(A)xB
62  double b_star[3];
63  b_star[PIR] = bfield.r[i_simd];
64  b_star[PIZ] = bfield.z[i_simd];
65  b_star[PIP] = bfield.phi[i_simd];
66 #ifdef EXPLICIT_EM
67  const auto& As = fld.template get<Label::As>();
68  const auto& dAs = fld.template get<Label::dAs>();
69  constexpr int NEG_DA = -1; // dAs needs sign reversal!
70  b_star[PIR] += As[i_simd]*curl_nb[PIR] + NEG_DA*(dAs.phi[i_simd]*bfield.z[i_simd] - dAs.z[i_simd]*bfield.phi[i_simd])*over_B;
71  b_star[PIZ] += As[i_simd]*curl_nb[PIZ] + NEG_DA*(dAs.r[i_simd]*bfield.phi[i_simd] - dAs.phi[i_simd]*bfield.r[i_simd])*over_B;
72  b_star[PIP] += As[i_simd]*curl_nb[PIP] + NEG_DA*(dAs.z[i_simd]*bfield.r[i_simd] - dAs.r[i_simd]*bfield.z[i_simd])*over_B;
73 #else
74  // Remove radial component of b_star
75  double rad, theta;
76  rz_2_psitheta(gradpsi_r_norm, gradpsi_z_norm, b_star[PIR], b_star[PIZ], rad, theta);
77  psitheta_2_rz(gradpsi_r_norm, gradpsi_z_norm, 0.0, theta, b_star[PIR], b_star[PIZ]);
78 
79  // Get radial component of tdb and add to b_star
80  double tdb_r_mod, tdb_z_mod;
81  rz_2_psitheta(gradpsi_r_norm, gradpsi_z_norm, tdb.r[i_simd], tdb.z[i_simd], rad, theta);
82  psitheta_2_rz(gradpsi_r_norm, gradpsi_z_norm, rad, 0.0, tdb_r_mod, tdb_z_mod);
83  b_star[PIR] += tdb_r_mod;
84  b_star[PIZ] += tdb_z_mod;
85 #endif
86 
87  // In the EM formalism, the parallel flow is v_para*B_star, i.e., he parallel flow
88  // contribution to the radial flux can come from the vr and dvr --->
89  // Subtract the curl(B) contribution, which is accounted for in v_mag
90  double prefac = D*cmrho;
91  v_par[PIR] = prefac*b_star[PIR];
92  v_par[PIZ] = prefac*b_star[PIZ];
93  v_par[PIP] = prefac*b_star[PIP];
94 }
95 
96 // The magnetic cross-field drifts
97 // Remove the (numerical flux-surface average of the magnetic drifts.
98 // This approximation accepts a small error because the velocity dependence
99 // in "D" is not taken into accound in v_gradb_avg and v_curv_avg.
100 //
101 // v_drift = D*(FxB) = D*(Bxgrad(H))/B^2 !Use all terms except E in grad(H)
102 // f = f_mr + f_pert = f_mr + f_es + f_em
103 // f_mr --> Mirror force
104 // f_es --> Electric field
105 // f_em --> Electromagnetic forces
106 // relevant force f = f_mr + f_em
107 // = -mu/c * grad(B) + (v_para-c/m*Ah)*grad(Ah)
108 // -mu/c*[grad(B)xB]/B^2 --> Apply cancellation law
109 KOKKOS_INLINE_FUNCTION void get_v_mag_drift(double D, double cmrho, double mu, double u, double rho, double c_m, double charge, double inv_r, const double (&curl_B)[3], const double (&grad_B)[3], const LocalFields& fld, const SimdVector& bfield, double B, double over_B2, double gradpsi_r_norm, double gradpsi_z_norm, const Simd<double>& v_curv_rad_fsa, const Simd<double>& v_grad_B_rad_fsa, double (&v_mag)[3], int i_simd){
110  // Convert to r,z
111  double v_curv_r_fsa, v_curv_z_fsa, v_grad_B_r_fsa, v_grad_B_z_fsa;
112  psitheta_2_rz(gradpsi_r_norm, gradpsi_z_norm, v_curv_rad_fsa[i_simd], 0.0, v_curv_r_fsa, v_curv_z_fsa);
113  psitheta_2_rz(gradpsi_r_norm, gradpsi_z_norm, v_grad_B_rad_fsa[i_simd], 0.0, v_grad_B_r_fsa, v_grad_B_z_fsa);
114 
115  double over_c = 1.0/charge;
116 
117  // Grad B drift is Bxgrad(|B|)
118  double grad_B_drift[3];
119  grad_B_drift[PIR] = bfield.phi[i_simd] * grad_B[PIZ] - bfield.z[i_simd] * grad_B[PIP]*inv_r;
120  grad_B_drift[PIZ] = bfield.r[i_simd] * grad_B[PIP]*inv_r - bfield.phi[i_simd] * grad_B[PIR];
121  grad_B_drift[PIP] = bfield.z[i_simd] * grad_B[PIR] - bfield.r[i_simd] * grad_B[PIZ];
122 
123 #ifdef EXPLICIT_EM
124  double over_B = 1.0/B;
125  const auto& Ah = fld.template get<Label::Ah>();
126  const auto& dAh = fld.template get<Label::dAh>();
127  constexpr int NEG_DA = -1; // dAh needs sign reversal!
128  double fr = -mu*over_c*grad_B[PIR] + NEG_DA*u*dAh.r[i_simd];
129  double fz = -mu*over_c*grad_B[PIZ] + NEG_DA*u*dAh.z[i_simd];
130  double fp = -mu*over_c*grad_B[PIP] + NEG_DA*u*dAh.phi[i_simd];
131 #ifdef EXPLICIT_EM_NONLIN_TERMS
132  fr -= NEG_DA*c_m*Ah[i_simd]*dAh.r[i_simd];
133  fz -= NEG_DA*c_m*Ah[i_simd]*dAh.z[i_simd];
134  fp -= NEG_DA*c_m*Ah[i_simd]*dAh.phi[i_simd];
135 #endif
136 
137  // Magnetic drifts in (R,phi,Z) coordinates:
138  v_mag[PIR] = D*(bfield.z[i_simd]*fp - bfield.phi[i_simd]*fz)*over_B2;
139  v_mag[PIZ] = D*(bfield.phi[i_simd]*fr - bfield.r[i_simd]*fp)*over_B2;
140  v_mag[PIP] = D*(bfield.r[i_simd]*fz - bfield.z[i_simd]*fr)*over_B2;
141 
142  // Apply cancellation law of Bxgrad(B)
143  // Also add contribution from curl(b) (removed from B*dH/du)
144  v_mag[PIR] -= D*over_c*over_B2*mu*v_grad_B_r_fsa;
145  v_mag[PIZ] -= D*over_c*over_B2*mu*v_grad_B_z_fsa;
146 
147  v_mag[PIR] += D*over_B*u*rho*(over_B*(grad_B_drift[PIR] - v_grad_B_r_fsa) + (B*curl_B[PIR] - v_curv_r_fsa));
148  v_mag[PIZ] += D*over_B*u*rho*(over_B*(grad_B_drift[PIZ] - v_grad_B_z_fsa) + (B*curl_B[PIZ] - v_curv_z_fsa));
149  v_mag[PIP] += D*over_B*u*rho*(over_B* grad_B_drift[PIP] + B*curl_B[PIP]);
150 #else
151  double cmrho2 = cmrho*rho;
152  double murho2B = (mu + charge*cmrho2*B);
153  double murho2B_c = murho2B*over_c;
154 
155  // The magnetic drifts (curvature + grad_b)
156  // Remove the (numerical flux-surface average of the magnetic drifts.
157  // This approximation accepts a small error because the velocity dependence
158  // in "D" is not taken into accound in v_gradb_avg and v_curv_avg.
159  v_mag[PIR] = D*((grad_B_drift[PIR] - v_grad_B_r_fsa)*murho2B_c*over_B2 + (curl_B[PIR] - v_curv_r_fsa)*cmrho2);
160  v_mag[PIZ] = D*((grad_B_drift[PIZ] - v_grad_B_z_fsa)*murho2B_c*over_B2 + (curl_B[PIZ] - v_curv_z_fsa)*cmrho2);
161  v_mag[PIP] = D*( grad_B_drift[PIP] *murho2B_c*over_B2 + curl_B[PIP] *cmrho2);
162 #endif
163 }
164 
165 
166 //> Evaluates the drift velocities at given inode, imu, ivp
167 // The basic magnetic field quantities necessary for the calculation of the
168 // magnetic drifts are stored in the grid data structure.
169 // To save memory, this could also be shifted to f0_module.
170 //
171 // CAUTION: Although this routine uses the full expression for dR/dt,
172 // it is correct only when using the pullback method and when
173 // in addition, A_h=0, i.e., directly after the pullback operation
174 // because it uses the assumption that u_para=v_para
175 //
176 KOKKOS_INLINE_FUNCTION void get_drift_velocity(const Species<DeviceType>& species, const Simd<double>& vp, const Simd<double>& v_curv_rad_fsa, const Simd<double>& v_grad_B_rad_fsa, const Simd<double>& mu, const SimdVector& bfield, const SimdVector (&jacb)[3], const SimdVector& tdb, const Simd<double>& B_mag, const Simd<double>& inv_r, const Simd<double>& gradpsi_r_norm, const Simd<double>& gradpsi_z_norm, const LocalFields& fld, SimdVector& v_mag, SimdVector& v_exb, SimdVector& v_par){
177 
178  for (int i_simd = 0; i_simd<SIMD_SIZE; i_simd++){
179  const double& B = B_mag[i_simd];
180  double rho = vp[i_simd]/(B*species.c_m);
181 
182  double over_B = 1.0/B;
183  double over_B2 = over_B*over_B;
184  double cmrho = species.c_m*rho;
185 
186  // For clarity, distinguish v_para and u_para
187  double u = vp[i_simd];
188 #ifdef EXPLICIT_EM
189  u += species.c_m*fld.template get<Label::Ah>()[i_simd];
190 #endif
191 
192  double grad_B[3];
193  get_grad_B(bfield, jacb, over_B, grad_B, i_simd);
194 
195  double curl_B[3];
196  get_curl_B(bfield, jacb, inv_r[i_simd], curl_B, i_simd);
197 
198  double curl_nb[3]; // [ curl of normalized vec B ] = curl vec B / B + vec B X grad B / B^2
199  get_curl_nb(bfield, grad_B, over_B, over_B2, curl_B, inv_r[i_simd], curl_nb, i_simd);
200 
201  // Velocity space Jacobian factor
202 #ifdef EXPLICIT_EM
203  const double D = get_vspace_jacb_factor(rho + fld.template get<Label::As>()[i_simd] * over_B, over_B2, bfield, jacb, inv_r[i_simd], i_simd);
204 #else
205  const double D = get_vspace_jacb_factor(rho, over_B2, bfield, jacb, inv_r[i_simd], i_simd);
206 #endif
207 
208  // The ExB drift
209  constexpr double drift_on = 1.0;
210  double yp[3];
211  get_ExB_drift(D, drift_on, bfield, fld.template get<Label::E>(), i_simd, over_B2, inv_r[i_simd], yp);
212  v_exb.r[i_simd] = yp[PIR];
213  v_exb.z[i_simd] = yp[PIZ];
214  v_exb.phi[i_simd] = yp[PIP]/inv_r[i_simd]; // Seems like a bug to have inv_r here? ALS
215 
216  // Magnetic drifts
217  get_v_mag_drift(D, cmrho, mu[i_simd], u, rho, species.c_m, species.charge, inv_r[i_simd], curl_B, grad_B, fld, bfield, B, over_B2, gradpsi_r_norm[i_simd], gradpsi_z_norm[i_simd], v_curv_rad_fsa, v_grad_B_rad_fsa, yp, i_simd);
218  v_mag.r[i_simd] = yp[PIR];
219  v_mag.z[i_simd] = yp[PIZ];
220  v_mag.phi[i_simd] = yp[PIP];
221 
222  // Parallel drift
223  get_v_par_drift(D, bfield, tdb, curl_nb, fld, over_B, cmrho, gradpsi_r_norm[i_simd], gradpsi_z_norm[i_simd], yp, i_simd);
224  v_par.r[i_simd] = yp[PIR];
225  v_par.z[i_simd] = yp[PIZ];
226  v_par.phi[i_simd] = yp[PIP];
227  }
228 }
229 
230 #endif
KOKKOS_INLINE_FUNCTION void set(int i_simd, double basis, const SimdVector2D &gradpsi)
Definition: field.hpp:35
Simd< double > r
Definition: simd.hpp:150
Definition: simd.hpp:149
KOKKOS_INLINE_FUNCTION void get_grad_B(const SimdVector &bfield, const SimdVector(&jacb)[3], double over_B, double(&grad_B)[3], int i_simd)
Definition: push_physics.tpp:155
double c_m
c/m
Definition: species.hpp:86
KOKKOS_INLINE_FUNCTION void gather_all_fields(const PushControls &push_controls, int i_simd, int i_node, double wp, const FieldCorrection &corr, const SimdGridWeights< Order::One, PIT_GLOBAL > &grid_wts, const SimdGyroWeights< DriftKin > &rho_wts, LocalFields &fld) const
Definition: grid_field_pack.hpp:127
Definition: grid_weights.hpp:47
KOKKOS_INLINE_FUNCTION double get_vspace_jacb_factor(double rho_mod, double over_B2, const SimdVector &bfield, const SimdVector(&jacb)[3], double inv_r, int i_simd)
Definition: push_physics.tpp:137
Definition: push_controls.hpp:9
Definition: grid_field_pack.hpp:21
KOKKOS_INLINE_FUNCTION void get_curl_B(const SimdVector &bfield, const SimdVector(&jacb)[3], double inv_r, double(&curl_B)[3], int i_simd)
Definition: push_physics.tpp:102
KOKKOS_INLINE_FUNCTION int uses_rz_basis(const int inode) const
Definition: grid.tpp:251
Definition: local_fields.hpp:33
Definition: grid_field.hpp:22
KOKKOS_INLINE_FUNCTION void get_drift_velocity(const Species< DeviceType > &species, const Simd< double > &vp, const Simd< double > &v_curv_rad_fsa, const Simd< double > &v_grad_B_rad_fsa, const Simd< double > &mu, const SimdVector &bfield, const SimdVector(&jacb)[3], const SimdVector &tdb, const Simd< double > &B_mag, const Simd< double > &inv_r, const Simd< double > &gradpsi_r_norm, const Simd< double > &gradpsi_z_norm, const LocalFields &fld, SimdVector &v_mag, SimdVector &v_exb, SimdVector &v_par)
Definition: get_drift_velocity.hpp:176
KOKKOS_INLINE_FUNCTION void rz_2_psitheta(double dpsidr, double dpsidz, double x_r, double x_z, double &x_rad, double &x_theta)
Definition: basic_physics.hpp:125
Definition: gyro_radius.hpp:24
r coordinate
Definition: globals.hpp:186
KOKKOS_INLINE_FUNCTION void get_v_mag_drift(double D, double cmrho, double mu, double u, double rho, double c_m, double charge, double inv_r, const double(&curl_B)[3], const double(&grad_B)[3], const LocalFields &fld, const SimdVector &bfield, double B, double over_B2, double gradpsi_r_norm, double gradpsi_z_norm, const Simd< double > &v_curv_rad_fsa, const Simd< double > &v_grad_B_rad_fsa, double(&v_mag)[3], int i_simd)
Definition: get_drift_velocity.hpp:109
Definition: field.hpp:23
KOKKOS_INLINE_FUNCTION void phi_from_para(SimdVector &vec, int i_simd, const SimdVector &B, double Bmag) const
Definition: grid_field_pack.hpp:121
double charge
Particle charge.
Definition: species.hpp:84
KOKKOS_INLINE_FUNCTION void get_v_par_drift(double D, const SimdVector &bfield, const SimdVector &tdb, const double(&curl_nb)[3], const LocalFields &fld, double over_B, double cmrho, double gradpsi_r_norm, double gradpsi_z_norm, double(&v_par)[3], int i_simd)
Definition: get_drift_velocity.hpp:60
KOKKOS_INLINE_FUNCTION void pot_rho_at_node(const GridField< DeviceType, VarType::Scalar, PIT_GLOBAL, TorType::OnePlane, KinType::GyroKin > &pot, const Grid< DeviceType > &grid, const Simd< int > &global_inds, const SimdGridWeights< Order::One, PIT_GLOBAL > grid_wts, const SimdGyroWeights< KinType::GyroKin > &rho_wts, Simd< double > &pot_out)
Definition: get_drift_velocity.hpp:43
KOKKOS_INLINE_FUNCTION void psitheta_2_rz(double dpsidr, double dpsidz, double x_rad, double x_theta, double &x_r, double &x_z)
Definition: basic_physics.hpp:139
Simd< double > phi
Definition: simd.hpp:152
Simd< double > z
Definition: simd.hpp:151
KOKKOS_INLINE_FUNCTION void fields_at_node(const GridFieldPack< DeviceType, PIT_GLOBAL > &gfpack, const PushControls &push_controls, const Grid< DeviceType > &grid, const SimdVector &B, const SimdVector2D &gradpsi, const Simd< int > &global_inds, const SimdGridWeights< Order::One, PIT_GLOBAL > grid_wts, const SimdGyroWeights< KinType::GyroKin > &rho_wts, LocalFields &fld)
Definition: get_drift_velocity.hpp:7
Definition: simd.hpp:139
KOKKOS_INLINE_FUNCTION void get_curl_nb(const SimdVector &bfield, const double(&grad_B)[3], double over_B, double over_B2, const double(&curl_B)[3], double inv_r, double(&curl_nb)[3], int i_simd)
Definition: push_physics.tpp:141
phi coordinate
Definition: globals.hpp:188
KOKKOS_INLINE_FUNCTION void get_ExB_drift(double D, double drift_on, const SimdVector &bfield, const SimdVector &E, int i_simd, double over_B2, double inv_r, double(&yp_exb)[3])
Definition: push_physics.tpp:196
Definition: species.hpp:75
KOKKOS_INLINE_FUNCTION double magnitude(const int i_simd) const
Definition: simd.hpp:176
z coordinate
Definition: globals.hpp:187