XGC1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
field_aligned_local_fields.hpp
Go to the documentation of this file.
1 #ifndef FIELD_ALIGNED_LOCAL_FIELDS_HPP
2 #define FIELD_ALIGNED_LOCAL_FIELDS_HPP
3 
4 #include "globals.hpp"
5 #include "push_controls.hpp"
6 #include "grid.hpp"
7 #include "gyro_radius.hpp"
8 #include "electric_field.hpp"
9 #include "grid_field_pack.hpp"
10 
11 
12 /* This class manages how to obtain the local grid field data during the push. It either:
13  * - a) performs a gather operation when the method fields_at_point is used, or
14  * - b) performs a gather operation when initialized, stores those values and
15  * returns them when the fields_at_point method is used.
16  * Option b) is used in XGC1 for ions, because the ion location in an intermediate RK step
17  * might not have a valid associated field since it could be outside of the toroidal sector
18  * for which field information is present.
19  * The generic declaration uses Option a) */
20 template<KinType KT, PhiInterpType PIT, typename GFPT>
22  // No members
23 
24  public:
25 
26  // Nothing to do in constructor
27  template<class Device>
28  KOKKOS_INLINE_FUNCTION FieldAlignedLocalFields(const Grid<Device> &grid, const PushControls &push_controls, const Species<Device> &species,
30 
31  /* Gather fields if calculating for electrons */
32  template<class Device>
33  KOKKOS_INLINE_FUNCTION void fields_at_point(const GridFieldPack<Device, GFPT> fields, const PushControls &push_controls, const Grid<Device> &grid,
34  const SimdVector &B, const SimdVector2D &gradpsi, const SimdGridWeights<Order::One, PIT>& grid_wts,
35  SimdGyroWeights<KT>& rho_wts, LocalFields<GFPT>& fld) const{
36  fields.fields_at_point(push_controls, grid, B,gradpsi,grid_wts,rho_wts, fld);
37  }
38 };
39 
40 /* If using XGC1, then the class specialization on KinType GyroKin stores the field aligned
41  * local field calculated in the constructor, and converts it to cylindrical coordinates in
42  * fields_at_point. */
43 template<typename GFPT>
45  // Simd vectors are hard-coded to (r, z, phi), but here they represent field-aligned coordinates instead
46  // "phi" --> parallel to B-field
48 
49  /* Convert stored electric/magnetic fields to field-aligned coordinates from cylindrical coordinates */
50  KOKKOS_INLINE_FUNCTION void convert_cyl_to_mag(const SimdVector &B, const SimdVector2D &gradpsi, const LocalFields<GFPT>& fld){
51  const auto& fld_E = fld.template get<Label::E>(); // Alias (not a copy)
52 # ifdef EXPLICIT_EM
53  const auto& fld_dAh = fld.template get<Label::dAh>(); // Alias (not a copy)
54  const auto& fld_dAs = fld.template get<Label::dAs>(); // Alias (not a copy)
55 # endif
56  auto& E = fa_fld.template get<Label::E>(); // Alias (not a copy)
57 # ifdef EXPLICIT_EM
58  auto& dAh = fa_fld.template get<Label::dAh>(); // Alias (not a copy)
59  auto& dAs = fa_fld.template get<Label::dAs>(); // Alias (not a copy)
60 # endif
61  for (int i_simd = 0; i_simd<SIMD_SIZE; i_simd++){
62  double Bmag = B.magnitude(i_simd);
63  double Bp = B.poloidal_magnitude(i_simd);
64  double grad2 = gradpsi.r[i_simd]*gradpsi.r[i_simd] + gradpsi.z[i_simd]*gradpsi.z[i_simd];
65 
66  // get E-field in magnetic field-aligned basis
67  E.r[i_simd] = (fld_E.r[i_simd] *gradpsi.r[i_simd] + fld_E.z[i_simd] *gradpsi.z[i_simd])/grad2;
68  E.z[i_simd] = (fld_E.r[i_simd] *B.r[i_simd] + fld_E.z[i_simd] *B.z[i_simd] )/Bp;
69  E.phi[i_simd] = (E.z[i_simd]*Bp + fld_E.phi[i_simd]*B.phi[i_simd] )/Bmag; // parallel field
70 
71 # ifdef EXPLICIT_EM
72  // grad(A_h)
73  dAh.r[i_simd] = (fld_dAh.r[i_simd]*gradpsi.r[i_simd] + fld_dAh.z[i_simd]*gradpsi.z[i_simd])/grad2;
74  dAh.z[i_simd] = (fld_dAh.r[i_simd]*B.r[i_simd] + fld_dAh.z[i_simd]*B.z[i_simd] )/Bp;
75  dAh.phi[i_simd] = (dAh.z[i_simd] *Bp + fld_dAh.phi[i_simd]*B.phi[i_simd] )/Bmag;
76 
77  // These variables are for the mixed-variables formulation.
78  // Make sure that they are initialized to 0 if Hamiltonian
79  // formulation is used.
80  dAs.r[i_simd] = (fld_dAs.r[i_simd]*gradpsi.r[i_simd] + fld_dAs.z[i_simd]*gradpsi.z[i_simd])/grad2;
81  dAs.z[i_simd] = (fld_dAs.r[i_simd]*B.r[i_simd] + fld_dAs.z[i_simd]*B.z[i_simd] )/Bp;
82  dAs.phi[i_simd] = (dAs.z[i_simd] *Bp + fld_dAs.phi[i_simd]*B.phi[i_simd] )/Bmag;
83 # endif
84  }
85  }
86 
87  /* Convert stored electric/magnetic fields from field-aligned coordinates to cylindrical coordinates */
88  KOKKOS_INLINE_FUNCTION void convert_mag_to_cyl(const SimdVector &B, const SimdVector2D &gradpsi, LocalFields<GFPT>& fld) const{
89  auto& fld_E = fld.template get<Label::E>(); // Alias (not a copy)
90 # ifdef EXPLICIT_EM
91  auto& fld_dAh = fld.template get<Label::dAh>(); // Alias (not a copy)
92  auto& fld_dAs = fld.template get<Label::dAs>(); // Alias (not a copy)
93 # endif
94  const auto& E = fa_fld.template get<Label::E>(); // Alias (not a copy)
95 # ifdef EXPLICIT_EM
96  const auto& dAh = fa_fld.template get<Label::dAh>(); // Alias (not a copy)
97  const auto& dAs = fa_fld.template get<Label::dAs>(); // Alias (not a copy)
98 # endif
99  for (int i_simd = 0; i_simd<SIMD_SIZE; i_simd++){
100  double Bmag = B.magnitude(i_simd);
101  double Bp = B.poloidal_magnitude(i_simd);
102  double Br_norm = B.r[i_simd] / Bp;
103  double Bz_norm = B.z[i_simd] / Bp;
104 
105  fld_E.r[i_simd] = E.r[i_simd]*gradpsi.r[i_simd]+E.z[i_simd]*Br_norm;
106  fld_E.z[i_simd] = E.r[i_simd]*gradpsi.z[i_simd]+E.z[i_simd]*Bz_norm;
107  fld_E.phi[i_simd] = (E.phi[i_simd]*Bmag - fld_E.r[i_simd]*B.r[i_simd] - fld_E.z[i_simd]*B.z[i_simd])/B.phi[i_simd];
108 
109 # ifdef EXPLICIT_EM
110  fld_dAh.r[i_simd] = dAh.r[i_simd]*gradpsi.r[i_simd]+dAh.z[i_simd]*Br_norm;
111  fld_dAh.z[i_simd] = dAh.r[i_simd]*gradpsi.z[i_simd]+dAh.z[i_simd]*Bz_norm;
112  fld_dAh.phi[i_simd] = (dAh.phi[i_simd]*Bmag - fld_dAh.r[i_simd]*B.r[i_simd] - fld_dAh.z[i_simd]*B.z[i_simd])/B.phi[i_simd];
113 
114  // The following are for the mixed-variable formulation
115  // Make sure that no all variables are initialized
116  fld_dAs.r[i_simd] = dAs.r[i_simd]*gradpsi.r[i_simd]+dAs.z[i_simd]*Br_norm;
117  fld_dAs.z[i_simd] = dAs.r[i_simd]*gradpsi.z[i_simd]+dAs.z[i_simd]*Bz_norm;
118  fld_dAs.phi[i_simd] = (dAs.phi[i_simd]*Bmag - fld_dAs.r[i_simd]*B.r[i_simd] - fld_dAs.z[i_simd]*B.z[i_simd])/B.phi[i_simd];
119 # endif
120  }
121  }
122 
123  public:
124 
125  /* Gather electric/magnetic fields and convert to field-aligned coordinates for storage */
126  template<class Device>
127  KOKKOS_INLINE_FUNCTION FieldAlignedLocalFields(const Grid<Device> &grid, const PushControls &push_controls, const Species<Device> &species,
129  // Declare arrays returned from B-field
130  SimdVector B;
131  SimdVector jacb[3];
132  Simd<double> psi;
133  SimdVector2D gradpsi;
134  Simd<bool> rz_outside;
135 
136  // obtain B-field information
137  magnetic_field.field(part.ph.v(), B, jacb, psi, gradpsi, rz_outside);
138  part.deactivate(rz_outside);
139 
140  // Get the current field following grid triangle and p weights
141  grid.get_grid_weights(magnetic_field, part.ph.v(), psi, grid_wts);
142 
143  // calculate rho weights
144  SimdGyroWeights<GyroKin> rho_wts(grid, magnetic_field, species, part.ph.v(), part.ct.mu);
145 
146  // get electric field
147  LocalFields<GFPT> fld;
148  gfpack.fields_at_point(push_controls, grid, B,gradpsi,grid_wts,rho_wts, fld);
149 
150  // Convert to field-aligned coordinates and store
151  convert_cyl_to_mag(B, gradpsi, fld);
152 
153  // These fields are not used for ions:
154 //#if defined(DELTAF_CONV) && !defined(EXPLICIT_EM)
155 // fa_fld.template get<Label::E00>() = fld.template get<Label::E00>(); // Should E00 also be field-aligned?
156 // fa_fld.template get<Label::ddpotdt>() = fld.template get<Label::ddpotdt>();
157 //#endif
158  // These get stored without any conversion; Consolidate field_aligned_local_fields with local_fields objects to avoid this copy
159 #ifdef EXPLICIT_EM
160  fa_fld.template get<Label::Ah>() = fld.template get<Label::Ah>();
161  fa_fld.template get<Label::As>() = fld.template get<Label::As>();
162  fa_fld.template get<Label::Epar_em>() = fld.template get<Label::Epar_em>();
163 #endif
164  }
165 
166  /* Return the stored field values for XGC1 ions */
167  template<class Device>
168  KOKKOS_INLINE_FUNCTION void fields_at_point(const GridFieldPack<Device, GFPT> fields, const PushControls &push_controls, const Grid<Device> &grid,
169  const SimdVector &B, const SimdVector2D &gradpsi, const SimdGridWeights<Order::One, PhiInterpType::Planes>& grid_wts,
170  SimdGyroWeights<GyroKin>& rho_wts, LocalFields<GFPT>& fld) const{
171  convert_mag_to_cyl(B, gradpsi, fld);
172 
173  // These fields are not used for ions:
174 //#if defined(DELTAF_CONV) && !defined(EXPLICIT_EM)
175 // fld.template get<Label::E00>()=fa_fld.template get<Label::E00>(); // Should E00 also be field-aligned?
176 // fld.template get<Label::ddpotdt>() = fa_fld.template get<Label::ddpotdt>();
177 //#endif
178  // These get stored without any conversion; Consolidate field_aligned_local_fields with local_fields objects to avoid this copy
179 #ifdef EXPLICIT_EM
180  fld.template get<Label::Ah>() = fa_fld.template get<Label::Ah>();
181  fld.template get<Label::As>() = fa_fld.template get<Label::As>();
182  fld.template get<Label::Epar_em>() = fa_fld.template get<Label::Epar_em>();
183 #endif
184  }
185 };
186 
187 
188 #endif
Simd< double > r
Definition: simd.hpp:150
KOKKOS_INLINE_FUNCTION void fields_at_point(const GridFieldPack< Device, GFPT > fields, const PushControls &push_controls, const Grid< Device > &grid, const SimdVector &B, const SimdVector2D &gradpsi, const SimdGridWeights< Order::One, PhiInterpType::Planes > &grid_wts, SimdGyroWeights< GyroKin > &rho_wts, LocalFields< GFPT > &fld) const
Definition: field_aligned_local_fields.hpp:168
Definition: simd.hpp:149
KOKKOS_INLINE_FUNCTION void field(const SimdVector &v, SimdVector &bvec, SimdVector(&jacb)[3], Simd< double > &psivec, SimdVector2D &gradpsi, Simd< bool > &rz_outside) const
Definition: magnetic_field.tpp:164
KOKKOS_INLINE_FUNCTION FieldAlignedLocalFields(const Grid< Device > &grid, const PushControls &push_controls, const Species< Device > &species, const MagneticField< Device > &magnetic_field, const GridFieldPack< Device, GFPT > &gfpack, SimdParticles &part, SimdGridWeights< Order::One, PIT > &grid_wts)
Definition: field_aligned_local_fields.hpp:28
Definition: grid_weights.hpp:73
LocalFields< GFPT > fa_fld
Definition: field_aligned_local_fields.hpp:47
Definition: grid_weights.hpp:47
Definition: push_controls.hpp:9
Definition: magnetic_field.hpp:12
Definition: grid.hpp:21
Definition: grid_field_pack.hpp:24
KOKKOS_INLINE_FUNCTION void convert_mag_to_cyl(const SimdVector &B, const SimdVector2D &gradpsi, LocalFields< GFPT > &fld) const
Definition: field_aligned_local_fields.hpp:88
KOKKOS_INLINE_FUNCTION void fields_at_point(const GridFieldPack< Device, GFPT > fields, const PushControls &push_controls, const Grid< Device > &grid, const SimdVector &B, const SimdVector2D &gradpsi, const SimdGridWeights< Order::One, PIT > &grid_wts, SimdGyroWeights< KT > &rho_wts, LocalFields< GFPT > &fld) const
Definition: field_aligned_local_fields.hpp:33
KOKKOS_INLINE_FUNCTION void fields_at_point(const PushControls &push_controls, const Grid< Device > &grid, const SimdVector &B, const SimdVector2D &gradpsi, const SimdGridWeights< Order::One, PIT_GLOBAL > &grid_wts, const SimdGyroWeights< PT > &rho_wts, LocalFields< GFPT > &fld) const
Definition: grid_field_pack.hpp:149
KOKKOS_INLINE_FUNCTION double poloidal_magnitude(const int i_simd) const
Definition: simd.hpp:181
PhiInterpType
Definition: globals.hpp:95
Definition: gyro_radius.hpp:24
Definition: gyro_radius.hpp:84
KOKKOS_INLINE_FUNCTION void convert_cyl_to_mag(const SimdVector &B, const SimdVector2D &gradpsi, const LocalFields< GFPT > &fld)
Definition: field_aligned_local_fields.hpp:50
KOKKOS_INLINE_FUNCTION SimdVector & v()
Definition: particles.hpp:39
Simd< double > z
Definition: simd.hpp:141
Definition: globals.hpp:90
SimdPhase ph
Definition: particles.hpp:62
Simd< double > phi
Definition: simd.hpp:152
Definition: particles.hpp:61
Simd< double > z
Definition: simd.hpp:151
Simd< double > r
Definition: simd.hpp:140
Definition: field_aligned_local_fields.hpp:21
Definition: magnetic_field.F90:1
Definition: simd.hpp:139
SimdConstants ct
Definition: particles.hpp:63
Definition: species.hpp:75
KOKKOS_INLINE_FUNCTION void get_grid_weights(const MagneticField< Device > &magnetic_field, const SimdVector &v, const Simd< double > &psi, SimdVector2D &xff, SimdGridWeights< Order::One, PIT > &grid_wts) const
Definition: grid.tpp:32
KOKKOS_INLINE_FUNCTION double magnitude(const int i_simd) const
Definition: simd.hpp:176
Simd< double > mu
m*v_perp^2/(2B)
Definition: particles.hpp:52
KOKKOS_INLINE_FUNCTION FieldAlignedLocalFields(const Grid< Device > &grid, const PushControls &push_controls, const Species< Device > &species, const MagneticField< Device > &magnetic_field, const GridFieldPack< Device, GFPT > &gfpack, SimdParticles &part, SimdGridWeights< Order::One, PhiInterpType::Planes > &grid_wts)
Definition: field_aligned_local_fields.hpp:127
KOKKOS_INLINE_FUNCTION void deactivate(const Simd< bool > &mask)
Definition: particles.hpp:79