XGC1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
grid_setup.hpp
Go to the documentation of this file.
1 #ifndef GRID_SETUP_HPP
2 #define GRID_SETUP_HPP
3 
4 #include "globals.hpp"
5 #include "grid.hpp"
6 
7 extern "C" void my_qsort(int left,int right,int* idx,double* psi_surf2_tmp,int npsi_surf2);
8 
9 extern "C" void init_guess_xtable_fort( int* nguess_2, double* grid_guess_max, double* grid_guess_min, double* grid_inv_guess_d, int* ntriangle, int* nnodes, const RZPair* grid_x,
10  Vertex* grid_nd, int* guess_xtable, int* guess_count, int* guess_list_len_in);
11 
12 
13 extern "C" void init_guess_list_fort( int* nguess_2, double* grid_guess_max, double* grid_guess_min, double* grid_inv_guess_d, int* ntriangle, int* nnodes, const RZPair* grid_x,
14  Vertex* grid_nd, int* guess_list, int* guess_xtable, int* guess_count, int* guess_list_len_in);
15 
16 // Provides setup and checks for an analytic example of a grid
17 
18 namespace{
19 
20 // Mapping matrix init
21 void setup_mapping(const View<Vertex*, CLayout, HostType> nd, const View<RZPair*, CLayout, HostType> x, View<VertexMap*, CLayout, HostType>& mapping){
22  Kokkos::parallel_for("setup_mapping", Kokkos::RangePolicy<HostExSpace>(0,mapping.extent(0)), KOKKOS_LAMBDA( const int i ){
23  double dx1r=x[nd[i].vertex[0]-1].r - x[nd[i].vertex[2]-1].r;
24  double dx1z=x[nd[i].vertex[0]-1].z - x[nd[i].vertex[2]-1].z;
25  double dx2r=x[nd[i].vertex[1]-1].r - x[nd[i].vertex[2]-1].r;
26  double dx2z=x[nd[i].vertex[1]-1].z - x[nd[i].vertex[2]-1].z;
27 
28  double det = 1.0/( dx1r*dx2z - dx2r*dx1z);
29 
30  mapping[i].vertex[0].r = dx2z*det;
31  mapping[i].vertex[1].r =-dx2r*det;
32  mapping[i].vertex[0].z =-dx1z*det;
33  mapping[i].vertex[1].z = dx1r*det;
34 
35 
36  mapping[i].vertex[2].r = x[nd[i].vertex[2]-1].r;
37  mapping[i].vertex[2].z = x[nd[i].vertex[2]-1].z;
38  });
39 }
40 
41 // These are the regions designated in the .node file
43  Inside=0,
44  OnWall
45 };
46 
47 // These are the regions used in XGC
48 enum Region{
49  RegionOne=1,
50  RegionTwo,
51  PrivateRegion,
52  Wall=100 // temporary, since 100 is the value used elsewhere
53 };
54 
55 void set_psi(){
56  //for(int i = 0; i<psi.size(); i++){
57  //grid%psi(i)=psi_interpol(grid%x(1,i),grid%x(2,i),0,0);
58 }
59 
60 template<class Device, class GridDevice>
61 void set_rgn(const MagneticField<Device>& bfield, const View<RZPair*,CLayout,GridDevice>& gx_h,
62  const View<double*,CLayout,GridDevice>& psi_h, View<int*, CLayout, GridDevice>& rgn_h){
63 
64  int nnode = gx_h.extent(0);
65  View<RZPair*,CLayout,Device> gx("gx",nnode);
66  View<double*,CLayout,Device> psi("psi",nnode);
67  View<int*,CLayout,Device> rgn("rgn",nnode);
68  Kokkos::deep_copy(gx, gx_h);
69  Kokkos::deep_copy(psi, psi_h);
70  Kokkos::deep_copy(rgn, rgn_h);
71 
72  Kokkos::parallel_for("set_rgn", Kokkos::RangePolicy<typename Device::execution_space>(0,rgn.extent(0)), KOKKOS_LAMBDA( const int i ){
73  if(rgn(i)==Inside){
74  if(bfield.equil.is_in_region_1_or_2(gx(i).r,gx(i).z,psi(i))){
75  if(psi(i) > bfield.equil.xpt_psi - bfield.equil.epsil_psi){
76  rgn(i)=RegionTwo;
77  }else{
78  rgn(i)=RegionOne;
79  }
80  }else{
81  rgn(i)=PrivateRegion;
82  }
83  } else {
84  rgn(i)=Wall;
85  }
86  });
87  Kokkos::fence();
88 
89  Kokkos::deep_copy(gx_h, gx);
90  Kokkos::deep_copy(psi_h, psi);
91  Kokkos::deep_copy(rgn_h, rgn);
92 }
93 
94 // Counts number of wall nodes
95 int get_n_wall_nodes(const View<int*, HostType>& rgn){
96  int count=0;
97  for(int i = 0; i<rgn.size(); i++){
98  if(rgn[i]==Wall) count++;
99  }
100 
101  if (count == 0){
102  // No wall nodes found --> print warning and return
103  printf("\ninit_wall: No wall nodes found!\n");
104  }
105 
106  return count;
107 }
108 
109 void setup_wall(const View<int*, CLayout, HostType>& rgn, View<int*, CLayout, HostType>& wall_nodes, View<int*, CLayout, HostType>& node_to_wall){
110  int count=0;
111  for(int i = 0; i<rgn.size(); i++){
112  if(rgn[i]==Wall){
113  wall_nodes[count]=i + 1; // 1-indexed
114  node_to_wall[i]=count + 1; // 1-indexed
115  count++;
116  }else{
117  node_to_wall[i]=0;
118  }
119  }
120 }
121 
122 
123 template<class Device, class GridDevice>
124 View<double*,CLayout,GridDevice> setup_grid_psi(const MagneticField<Device>& magnetic_field, const View<RZPair*,CLayout,GridDevice>& gx_h){
125  int nnode = gx_h.extent(0);
126  View<RZPair*,CLayout,Device> gx("gx",nnode);
127  Kokkos::deep_copy(gx, gx_h);
128 
129  // Calculate psi at grid points
130  View<double*,CLayout,Device> psi("psi", nnode);
131  Kokkos::parallel_for("psi_calc", Kokkos::RangePolicy<typename Device::execution_space>(0, nnode), KOKKOS_LAMBDA( const int idx ){
132  double psi_local;
133  magnetic_field.psi_bicub.der_zero(gx(idx).r,gx(idx).z, psi_local);
134  psi(idx) = max(1e-70, psi_local);
135  });
136 
137  // Check whether the first vertex is the magnetic axis
138  // If so, set psi exactly to 0. This is needed for 1D
139  // psi search on irregular grid
140  double psi_zero_eps = 5.0e-3;
141  Kokkos::parallel_for("psi_calc_check_first", Kokkos::RangePolicy<typename Device::execution_space>(0, 1), KOKKOS_LAMBDA( const int idx ){
142  double dr = gx(idx).r - magnetic_field.equil.axis_r;
143  double dz = gx(idx).z - magnetic_field.equil.axis_z;
144  if(sqrt(dr*dr + dz*dz) < psi_zero_eps){
145  psi(idx) = 0.0;
146  }
147  });
148 
149  Kokkos::fence();
150 
151  View<double*,CLayout,GridDevice> psi_h("psi", nnode);
152  Kokkos::deep_copy(psi_h, psi);
153 
154  return psi_h;
155 }
156 
157 // Returns volume-weighted average of node psi values along each flux surface
158 template<class Device>
159 View<double*,CLayout,HostType> get_psi_surf(const MagneticField<Device>& magnetic_field,
160  const View<double*,CLayout,HostType>& psi_h,
161  const View<int*, CLayout, HostType>& nnodes_on_surface_h,
162  const View<int**,CLayout,HostType>& surf_idx_h,
163  const View<double*,CLayout,HostType>& node_vol_h){
164 
165  // Copy host views to device
166  View<double*,CLayout,Device> psi(NoInit("psi"), psi_h.layout());
167  View<int*, CLayout,Device> nnodes_on_surface(NoInit("nnodes_on_surface"),nnodes_on_surface_h.layout());
168  View<int**,CLayout,Device> surf_idx(NoInit("surf_idx"),surf_idx_h.layout());
169  View<double*,CLayout,Device> node_vol(NoInit("node_vol"),node_vol_h.layout());
170  Kokkos::deep_copy(psi, psi_h);
171  Kokkos::deep_copy(nnodes_on_surface, nnodes_on_surface_h);
172  Kokkos::deep_copy(node_vol, node_vol_h);
173  Kokkos::deep_copy(surf_idx, surf_idx_h);
174 
175  // Allocate output view
176  View<double*,CLayout,Device> psi_surf(NoInit("psi_surf"), nnodes_on_surface.size());
177 
178  // Loop over surfaces
179  Kokkos::parallel_for("get_psi_surf", Kokkos::RangePolicy<typename Device::execution_space>(0,psi_surf.size()), KOKKOS_LAMBDA( const int i ){
180  double surf_vol = 0.0;
181  double psi_sum = 0.0;
182  for(int j=0; j<nnodes_on_surface(i); j++){
183  int k=surf_idx(i, j)-1; // 1-indexed
184 
185  // Calculate psi_surf by taking a volume-weighted average of psi values along
186  // the nodes of the surface
187  psi_sum += psi(k)*node_vol(k);
188  surf_vol += node_vol(k);
189  }
190  psi_surf(i) = psi_sum/surf_vol;
191  });
192  Kokkos::fence();
193 
194  View<double*,CLayout,HostType> psi_surf_h(NoInit("psi_surf"), psi_surf.layout());
195  Kokkos::deep_copy(psi_surf_h, psi_surf);
196  return psi_surf_h;
197 }
198 
199 /*
200  int nsurfaces;
201  std::vector<int> nnodes_on_surface;
202  int sum_nnodes_on_surfaces;
203  std::vector<int> nodes_of_surfaces;
204  */
205 template<class Device>
206 View<double*,CLayout,HostType> setup_psi_surf2(const MagneticField<Device>& magnetic_field,
207  const View<int*, CLayout, HostType>& nnodes_on_surface_h,
208  const View<int**,CLayout, HostType>& surf_idx_h,
209  const View<double*,CLayout,HostType>& psi_surf_h,
210  const View<RZPair*,CLayout,HostType>& gx_h){
211  const double use_surf_thresh=3.0e-2;
212  int nnode = gx_h.extent(0);
213  View<RZPair*,CLayout,Device> gx("gx",nnode);
214  View<int*, CLayout, Device> nnodes_on_surface(NoInit("nnodes_on_surface"),nnodes_on_surface_h.layout());
215  View<int**,CLayout, Device> surf_idx(NoInit("surf_idx"),surf_idx_h.layout());
216  Kokkos::deep_copy(nnodes_on_surface, nnodes_on_surface_h);
217  Kokkos::deep_copy(surf_idx, surf_idx_h);
218  Kokkos::deep_copy(gx, gx_h);
219 
220  int nsurfaces = nnodes_on_surface.size();
221 
222  int npsi_surf2=0;
223  View<bool*,CLayout,Device> use_surf("use_surf", nsurfaces);
224  Kokkos::parallel_reduce("get_psi_surf2", Kokkos::RangePolicy<typename Device::execution_space>(0,psi_surf_h.size()), KOKKOS_LAMBDA( const int i, int& npsi_surf2_l){
225  double zmin=1e10;
226  for(int j=0; j<nnodes_on_surface(i); j++){
227  int k=surf_idx(i, j)-1; // 1-indexed
228  // Determine which flux surfaces to use for 1D diagnosis
229  // Only use flux surfaces that cross outer midplane
230  if ( (std::abs(gx(k).z-magnetic_field.equil.axis_z) < zmin) && (gx(k).r-(magnetic_field.equil.axis_r - 5.0e-5) >= 0.0) ){
231  zmin=std::abs(gx(k).z -magnetic_field.equil.axis_z);
232  }
233  }
234 
235  if (zmin <= use_surf_thresh){
236  use_surf(i) = true;
237  npsi_surf2_l++;
238  }else{
239  use_surf(i) = false;
240  }
241  }, npsi_surf2);
242  Kokkos::fence();
243 
244  // Bring results to host
245  View<bool*,CLayout,HostType> use_surf_h("use_surf", nsurfaces);
246  Kokkos::deep_copy(use_surf_h, use_surf);
247 
248  // Populate psi_surf2 with desired surfaces from psi_surf
249  View<double*, CLayout, HostType> psi_surf2_h(NoInit("psi_surf2"),npsi_surf2);
250  int j=0;
251  for(int i=0; i<nsurfaces; i++){
252  if (use_surf_h(i)){
253  psi_surf2_h(j) = psi_surf_h(i);
254  j++;
255  }
256  }
257 
258  // Make sure surfaces are in ascending order
259  View<int*, HostType> idx(NoInit("idx"),npsi_surf2);
260  for(int i=0; i<npsi_surf2; i++) idx(i) = i + 1; // idx is one-indexed because it is reordered in Fortran
261  int left=1;
262  int right=npsi_surf2;
263  my_qsort(left,right,idx.data(),psi_surf2_h.data(),npsi_surf2);
264  View<double*, HostType> tmp(NoInit("tmp"),npsi_surf2);
265  for(int i=0; i<npsi_surf2; i++) tmp(i)=psi_surf2_h(idx(i) - 1); // -1 since idx is one-indexed
266  for(int i=0; i<npsi_surf2; i++) psi_surf2_h(i)=tmp(i);
267 
268  return psi_surf2_h;
269 }
270 
271 // Calculate and store magnetic field at nodes
272 template<class Device, class GridDevice>
273 View<double*,CLayout,GridDevice> setup_grid_bfield(const MagneticField<Device>& magnetic_field, const View<RZPair*,CLayout,GridDevice>& gx_h){
274  int nnode = gx_h.extent(0);
275  View<RZPair*,CLayout,Device> gx("gx",nnode);
276  Kokkos::deep_copy(gx, gx_h);
277 
278  // Calculate psi at grid points
279  View<double*,CLayout,Device> bfield("bfield", nnode);
280  Kokkos::parallel_for("node_bfield", Kokkos::RangePolicy<typename Device::execution_space>(0,nnode), KOKKOS_LAMBDA( const int idx ){
281  double br, bz, bphi;
282  magnetic_field.bvec_interpol(gx(idx).r,gx(idx).z,0.0,br,bz,bphi);
283  bfield(idx) = sqrt(br*br + bz*bz + bphi*bphi);
284  });
285  Kokkos::fence();
286 
287  View<double*,CLayout,GridDevice> bfield_h("bfield", nnode);
288  Kokkos::deep_copy(bfield_h, bfield);
289 
290  return bfield_h;
291 }
292 
293 
294 /*void plot_grid(Grid<HostType>& grid){
295  int nx = 80;
296  int ny = 40;
297  double dr = (equil.max_r - equil.min_r)/nx;
298  double dz = (equil.max_z - equil.min_z)/ny;
299  printf("\n");
300  std::vector<int> prevrow(nx+1,-1);
301 
302  for (int j=ny;j>=0;j--){
303  printf("\n");
304  int prevnum = -1;
305  for (int i=0;i<=nx;i++){
306  double r = equil.min_r + i*dr;
307  double z = equil.min_z + j*dz;
308  int num = get_analytic_psi(equil,r,z)*5.0;
309  char mychar = 48+num;
310  if (prevnum!=num || prevrow[i]!=num) printf("%c",mychar);
311  else printf(" ");
312  prevnum = num;
313  prevrow[i] = num;
314  }
315  }
316  printf("\n");
317 }
318 */
319 
320 }
321 #endif
KOKKOS_INLINE_FUNCTION void bvec_interpol(double r, double z, double phi, double &br, double &bz, double &bphi) const
Definition: magnetic_field.tpp:229
void init_guess_xtable_fort(int *nguess_2, double *grid_guess_max, double *grid_guess_min, double *grid_inv_guess_d, int *ntriangle, int *nnodes, const RZPair *grid_x, Vertex *grid_nd, int *guess_xtable, int *guess_count, int *guess_list_len_in)
void my_qsort(int left, int right, int *idx, double *psi_surf2_tmp, int npsi_surf2)
Definition: magnetic_field.hpp:12
Equilibrium equil
The object containing information about the magnetic equilibrium.
Definition: magnetic_field.hpp:32
double axis_z
z coordinate of axis
Definition: equil.hpp:95
Definition: grid_structs.hpp:28
idx
Definition: diag_f0_df_port1.hpp:32
FileRegion
Definition: grid_setup.hpp:42
double axis_r
r coordinate of axis
Definition: equil.hpp:94
void init_guess_list_fort(int *nguess_2, double *grid_guess_max, double *grid_guess_min, double *grid_inv_guess_d, int *ntriangle, int *nnodes, const RZPair *grid_x, Vertex *grid_nd, int *guess_list, int *guess_xtable, int *guess_count, int *guess_list_len_in)
Definition: grid_structs.hpp:24
Region
Definition: grid_setup.hpp:48
Definition: magnetic_field.F90:1
void parallel_for(const std::string name, int n_ptl, Function func, Option option, HostAoSoA aosoa_h, DeviceAoSoA aosoa_d)
Definition: streamed_parallel_for.hpp:252
Bicub< Device > psi_bicub
The object for interpolating psi (magnetic flux surfaces)
Definition: magnetic_field.hpp:30
double epsil_psi
Not sure?
Definition: equil.hpp:85
Kokkos::ViewAllocateWithoutInitializing NoInit
Definition: space_settings.hpp:68
KOKKOS_INLINE_FUNCTION bool is_in_region_1_or_2(double r, double z, double psi) const
Definition: equil.tpp:102
double xpt_psi
Psi coordinate of 1st X-point.
Definition: equil.hpp:84