HARM
harm and utilities
 All Data Structures Files Functions Variables Typedefs Macros Pages
fluxctstag.c
Go to the documentation of this file.
1 #include "decs.h"
2 
3 
12 
60 static void rescale_calc_stagfield_full(int *Nvec, FTYPE (*pstag)[NSTORE2][NSTORE3][NPR2INTERP],FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP]);
61 
62 
63 
64 
65 
66 
67 
73 {
74  int Nvec[NDIM];
75 
76 
77 #if(FIELDSTAGMEM==0)
78  dualfprintf(fail_file,"Set FIELDSTAGMEM==1 to do FLUXCTSTAG\n");
79  myexit(7158915);
80 #endif
81 
82  /* flux-staggered */
83 
84  // note A_i is always at CORN1,2,3 (edges) for any method, so init.c remains the same
85  // all comments same as for centered field -- only change is no averaging of A_i to faces from edges (CORN1,2,3)
86 
87 
88  Nvec[0]=0;
89  Nvec[1]=N1;
90  Nvec[2]=N2;
91  Nvec[3]=N3;
92 
94  //
95  // now with double-quasi-deaveraged A_i compute B^i
96  //
97  // use Nvec in case 1-D then if Nvec[odir1]==1 && Nvec[odir2]==1 then don't assign dir field since constant in time and not zero as would be determined here
98  // pfield should be from de-(laterally)-averaged ufield at FACE1,2,3
99  //
101 
102  // since nowait'ed above (because each loop sets ufield,pfield for each dir that don't depend upon eachother), need barrier here at end to stop before continuing (implied in parallel reigon)
103 #pragma omp parallel
104  {
105 
106  int i,j,k;
107  int dir;
108  FTYPE igdetgnosing[NDIM];
109  int odir1,odir2;
110  int jj;
111  struct of_gdetgeom geomfdontuse[NDIM];
112  struct of_gdetgeom *ptrgeomf[NDIM];
113  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUPFULL; // doesn't depend upon dir, but blockijk must be private
114 
115 
116  // generally ptr's are different inside parallel block
117  DLOOPA(jj) ptrgeomf[jj]=&(geomfdontuse[jj]);
118 
119 
120 
121  dir=1;
122  get_odirs(dir,&odir1,&odir2);
123  if(!(Nvec[odir1]==1 && Nvec[odir2]==1)){
125 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait
127  OPENMP3DLOOPBLOCK2IJK(i,j,k);
128 
129  // ufield doesn't require geometry
130  MACP0A1(ufield,i,j,k,B1) = +(NOAVGCORN_1(A[3],i,jp1mac(j),k)-NOAVGCORN_1(A[3],i,j,k))/(dx[2]);
131  MACP0A1(ufield,i,j,k,B1) += -(NOAVGCORN_1(A[2],i,j,kp1mac(k))-NOAVGCORN_1(A[2],i,j,k))/(dx[3]);
132 
133  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgeomf[dir]);
134  set_igdetsimple(ptrgeomf[dir]);
135  igdetgnosing[dir] = ptrgeomf[dir]->igdetnosing;
136  MACP0A1(pfield,i,j,k,B1-1+dir) = MACP0A1(ufield,i,j,k,B1-1+dir)*igdetgnosing[dir];
137 
138  }
139  }// end if
140 
141  dir=2;
142  get_odirs(dir,&odir1,&odir2);
143  if(!(Nvec[odir1]==1 && Nvec[odir2]==1)){
145 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait
147  OPENMP3DLOOPBLOCK2IJK(i,j,k);
148 
149  MACP0A1(ufield,i,j,k,B2) = +(NOAVGCORN_2(A[1],i,j,kp1mac(k))-NOAVGCORN_2(A[1],i,j,k))/(dx[3]);
150  MACP0A1(ufield,i,j,k,B2) += -(NOAVGCORN_2(A[3],ip1mac(i),j,k)-NOAVGCORN_2(A[3],i,j,k))/(dx[1]);
151 
152  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgeomf[dir]);
153  set_igdetsimple(ptrgeomf[dir]);
154  igdetgnosing[dir] = ptrgeomf[dir]->igdetnosing;
155  MACP0A1(pfield,i,j,k,B1-1+dir) = MACP0A1(ufield,i,j,k,B1-1+dir)*igdetgnosing[dir];
156 
157  }
158  }
159 
160  dir=3;
161  get_odirs(dir,&odir1,&odir2);
162  if(!(Nvec[odir1]==1 && Nvec[odir2]==1)){
164 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait
166  OPENMP3DLOOPBLOCK2IJK(i,j,k);
167 
168  MACP0A1(ufield,i,j,k,B3) = +(NOAVGCORN_3(A[2],ip1mac(i),j,k)-NOAVGCORN_3(A[2],i,j,k))/(dx[1]);
169  MACP0A1(ufield,i,j,k,B3) += -(NOAVGCORN_3(A[1],i,jp1mac(j),k)-NOAVGCORN_3(A[1],i,j,k))/(dx[2]);
170 
171  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgeomf[dir]);
172  set_igdetsimple(ptrgeomf[dir]);
173  igdetgnosing[dir] = ptrgeomf[dir]->igdetnosing;
174  MACP0A1(pfield,i,j,k,B1-1+dir) = MACP0A1(ufield,i,j,k,B1-1+dir)*igdetgnosing[dir];
175 
176  }
177  }
178  }// end full parallel region (with implied barrier)
179 
180 
181 
182 #if(0)
183  bound_prim(STAGEM1,t,ufield, 0);
184  bound_prim(STAGEM1,t,pfield, 0);
185 #endif
186 
187 
188 
189  return(0);
190 }
191 
192 
193 
194 
195 
196 
197 
198 
203 int fluxcalc_fluxctstag(int stage,
204  int initialstep, int finalstep,
205  FTYPE (*pr)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR], FTYPE (*pl_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pr_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP],
206  // FTYPE (*pbcorn)[COMPDIM][NUMCS][NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3],
208  FTYPE (*wspeed)[COMPDIM][NUMCS][NSTORE1][NSTORE2][NSTORE3],
209  FTYPE (*prc)[NSTORE2][NSTORE3][NPR2INTERP],
210  FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP],
211  FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP],
212  struct of_state (*fluxstatecent)[NSTORE2][NSTORE3],
213  struct of_state (*fluxstate)[NSTORE1][NSTORE2][NSTORE3][NUMLEFTRIGHT],
214  FTYPE (*geomcorn)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3],
215  int *Nvec, FTYPE (*dqvec[NDIM])[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*fluxvec[NDIM])[NSTORE2][NSTORE3][NPR+NSPECIAL],
217  FTYPE *CUf, FTYPE *CUnew, SFTYPE fluxdt, SFTYPE fluxtime, struct of_loop *cent2faceloop, struct of_loop (*face2cornloop)[NDIM][NDIM]
218  )
219 {
220  int interpolate_prim_face2corn(FTYPE (*pr)[NSTORE2][NSTORE3][NPR], FTYPE (*primface_l)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*primface_r)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP],
221  // FTYPE (*pbcorn)[COMPDIM][NUMCS][NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3],
223  struct of_loop *cent2faceloop, struct of_loop (*face2cornloop)[NDIM][NDIM],
224  FTYPE (*prc)[NSTORE2][NSTORE3][NPR2INTERP],
225  FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP],
226  FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP],
227  int *Nvec, FTYPE (*dqvec[NDIM])[NSTORE2][NSTORE3][NPR2INTERP]);
228  int dir;
229  int idel, jdel, kdel, face;
230  int is, ie, js, je, ks, ke;
231  int fluxcalc_fluxctstag_emf_1d(int stage, FTYPE (*pr)[NSTORE2][NSTORE3][NPR], int dir, int odir1, int odir2, int is, int ie, int js, int je, int ks, int ke, FTYPE (*fluxvec[NDIM])[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE CUf, struct of_loop (*face2cornloop)[NDIM],
232  // FTYPE (*pbcorn)[COMPDIM][NUMCS][NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3],
234  FTYPE (*wspeed)[COMPDIM][NUMCS][NSTORE1][NSTORE2][NSTORE3]);
235  int edgedir, odir1,odir2;
236  // static int firsttime=1;
237  int i,j,k;
238  int enerregion;
239  int *localenerpos;
240 
241 
242 
243  // forCOMPZSLOOP:
244  // avoid looping over region outside active+ghost grid
245  // good because somewhat general and avoid bad inversions, etc.
246  enerregion=TRUEGLOBALWITHBNDENERREGION;
247  localenerpos=enerposreg[enerregion];
248 
249 
251  //
252  // first obtain pbinterp and pvinterp (point CORN1,2,3 quantities) from pl_ct and pr_ct (FACE1,2,3 quantities)
253  // This can't be done per dimension since flux needs multi-D quantities for 2D Riemann problem...hence why stored and outside dimenloop
254  //
256  interpolate_prim_face2corn(pr, pl_ct, pr_ct, pvbcorn, cent2faceloop, face2cornloop,prc,pleft,pright,Nvec,dqvec);
257 
258 
259 
260 
262  //
263  // LOOP OVER EDGES (corresponds to EMF,edge directions, NOT face directions)
264  //
266  DIMENLOOP(dir){
267 
268  edgedir=dir;
269 
271  //
272  // other dimensions
273  // will be setting flux associated with d_t(Bodir1) and d_t(Bodir2) and setting flux(Bdir)->0
274 
275  get_odirs(dir,&odir1,&odir2);
276  // skip to next dir if 1D such that EMF[dir] not needed since always cancels with itself
277  // assumes set to 0 and if set to 0 once then always 0 (assume set to 0 in
278  if(Nvec[odir1]==1 && Nvec[odir2]==1){
279  // if(firsttime){
280  // then ensure that really 0 and should remain 0 for entire evolution
281  // don't need to set this except once assuming no other code sets to non-zero
282  // No! If those directions are 0 then flux isn't defined nor used
283  //COMPZSLOOP( -N1BND, N1-1+N1BND, -N2BND, N2-1+N2BND, -N3BND, N3-1+N3BND ){
284  // MACP1A1(fluxvec,odir1,i,j,k,B1-1+odir2)=MACP1A1(fluxvec,odir2,i,j,k,B1-1+odir1)=MACP1A1(fluxvec,dir,i,j,k,B1-1+dir)=0.0;
285  // }
286  // }
287  continue;
288  }
289 
290  //loop over the interfaces where fluxes are computed -- atch, useCOMPZSLOOP( is, ie, js, je, ks, ke ) { ... }
291  // since looping over edges (emfs) and flux loop different than emf loop, then expand loops so consistent with both fluxes corresponding to that emf
292  is=emffluxloop[dir][FIS];
293  ie=emffluxloop[dir][FIE];
294  js=emffluxloop[dir][FJS];
295  je=emffluxloop[dir][FJE];
296  ks=emffluxloop[dir][FKS];
297  ke=emffluxloop[dir][FKE];
298 
299 
300  // dir corrsponds to *edge,emf* NOT face
301  // CUf[2] is for flux updates
302  MYFUN(fluxcalc_fluxctstag_emf_1d(stage, pr, dir, odir1, odir2, is, ie, js, je, ks, ke, fluxvec, CUf[2], face2cornloop[edgedir],pvbcorn,wspeed),"flux.c:fluxcalc()", "fluxcalc_fluxctstag_1d", dir);
303 
304 #if(PRODUCTION==0)
305  trifprintf("%d",dir);
306 #endif
307  }// end DIMENLOOP(dir)
308 
309 
310 #if(0)
311  bound_flux(STAGEM1,t,fluxvec[1],fluxvec[2],fluxvec[3], 0);
312  if(N1>1) bound_prim(STAGEM1,t,fluxvec[1], 0);
313  if(N2>1) bound_prim(STAGEM1,t,fluxvec[2], 0);
314  if(N3>1) bound_prim(STAGEM1,t,fluxvec[3], 0);
315 #endif
316 
317 
318 #if(0)
319  // SUPERDEBUG: shouldn't be needed -- test
320 
321  dualfprintf(fail_file,"nstep=%ld steppart=%d\n",nstep,steppart);
322  LOOPF_23{ // debug only
323  dualfprintf(fail_file,"j=%d emf[0]=%21.15g emf[N1]=%21.15g diff=%21.15g\n",j,MACP1A1(fluxvec,1,0,j,k,B2),MACP1A1(fluxvec,1,N1,j,k,B2),MACP1A1(fluxvec,1,0,j,k,B2)-MACP1A1(fluxvec,1,N1,j,k,B2));
324  //MACP1A1(fluxvec,1,N1,j,k,B2)=MACP1A1(fluxvec,1,0,j,k,B2);
325  // MACP1A1(fluxvec,2,N1,j,k,B1)=-MACP1A1(fluxvec,1,0,j,k,B2);
326 
327  // MACP1A1(fluxvec,1,N1,j,k,B2)=-MACP1A1(fluxvec,2,N1,j,k,B1);
328  //=-MACP1A1(fluxvec,2,N1,j,k,B1)=
329  }
330 #endif
331 
332 
333 
334 
335  if(EVOLVEWITHVPOT>0 || TRACKVPOT>0){
336  // Evolve A_i
337  evolve_vpotgeneral(FLUXB, stage, initialstep, finalstep, pr, Nvec, fluxvec, NULL, CUf, CUnew, fluxdt, fluxtime, vpot);
338  }
339 
340 
341  int fluxvpot_modifyemfsuser=0;
342  fluxvpot_modifyemfsuser=(EVOLVEWITHVPOT>0 || TRACKVPOT>0)&&(MODIFYEMFORVPOT==MODIFYEMF || MODIFYEMFORVPOT==MODIFYVPOT);
343 
344  if(fluxvpot_modifyemfsuser==0){// if didn't already call adjust_emfs() in fluxvpot above, have to allow user to be able to still modify emfs calling function directly
345  // User "boundary conditions" to modify EMFs/FLUXes
346  adjust_fluxctstag_emfs(fluxtime,pr,Nvec,fluxvec);
347  }
348 
349 
350 
351 
352  // firsttime=0;
353  return(0);
354 
355 }
356 
357 
358 
359 
360 
361 
362 
391 
394 int fluxcalc_fluxctstag_emf_1d(int stage, FTYPE (*pr)[NSTORE2][NSTORE3][NPR], int dir, int odir1, int odir2, int is, int ie, int js, int je, int ks, int ke, FTYPE (*fluxvec[NDIM])[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE CUf, struct of_loop (*face2cornloop)[NDIM],
395  // FTYPE (*pbcorn)[COMPDIM][NUMCS][NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3],
397  FTYPE (*wspeed)[COMPDIM][NUMCS][NSTORE1][NSTORE2][NSTORE3])
398 {
399  int idel1,jdel1,kdel1;
400  int idel2,jdel2,kdel2;
401  int Nvec[NDIM];
402 
403 
404 
406  //
407  // get direction offsets for array accesses
408  //
410  Nvec[0]=0;
411  Nvec[1]=N1;
412  Nvec[2]=N2;
413  Nvec[3]=N3;
414 
415  idel1 = fluxloop[odir1][FIDEL];
416  jdel1 = fluxloop[odir1][FJDEL];
417  kdel1 = fluxloop[odir1][FKDEL];
418 
419  idel2 = fluxloop[odir2][FIDEL];
420  jdel2 = fluxloop[odir2][FJDEL];
421  kdel2 = fluxloop[odir2][FKDEL];
422 
423 
424 
426  //
427  // flux loop : Extra "expand" zone for the purpose of averaging flux to get emf at corner. Only used by field components, see flux_ct().
428  // This loop is over interfaces where fluxes are evaluated -- atch
429  //
431 
432  //#if((SIMULBCCALC==2)&&(TYPE2==1))
433  // COMPFZLOOP(is,js,ks)
434  //#else
435  //#endif
437 
438 #pragma omp parallel
439  {
440  int i,j,k,pl,pliter;
441  struct of_gdetgeom gdetgeomdontuse;
442  struct of_gdetgeom *ptrgdetgeom=&gdetgeomdontuse;
443  int m,l;
444  FTYPE emf2d[COMPDIM-1][COMPDIM-1],c2d[NUMCS][COMPDIM-1];
445  FTYPE dB[COMPDIM-1],ctop[COMPDIM-1];
446  FTYPE emffinal;
447  FTYPE geomcornodir1,geomcornodir2;
448  FTYPE topwave[COMPDIM-1],bottomwave[COMPDIM-1];
449  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
450 
451  int fluxmethodlocal;
452  FTYPE cmaxfactorodir1;
453  FTYPE cmaxfactorodir2;
454  FTYPE cminfactorodir1;
455  FTYPE cminfactorodir2;
456 
457 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
459  OPENMP3DLOOPBLOCK2IJK(i,j,k);
460 
461  // defaults
462  fluxmethodlocal=fluxmethod[B1]; // assume all B's are same.
463  cmaxfactorodir1=1.0;
464  cmaxfactorodir2=1.0;
465  cminfactorodir1=1.0;
466  cminfactorodir2=1.0;
467 #if(OUTERRADIALSUPERFAST)
468  // force effective superfast condition on outer radial boundaries
470  if(dir==3 && odir1==1 && startpos[1]+i==totalsize[1]){ fluxmethodlocal=HLLFLUX; cminfactorodir1=0.0; }
471  if(dir==3 && odir2==1 && startpos[1]+i==totalsize[1]){ fluxmethodlocal=HLLFLUX; cminfactorodir2=0.0; }
472  if(dir==3 && odir1==1 && startpos[1]+i==0){ fluxmethodlocal=HLLFLUX; cmaxfactorodir1=0.0; }
473  if(dir==3 && odir2==1 && startpos[1]+i==0){ fluxmethodlocal=HLLFLUX; cmaxfactorodir2=0.0; }
474  }
475 #endif
476 
477  // pvcorninterp and pbcorninterp are defined to be used like below initializaiton in set_arrays.c
478  // for(pl2=1;pl2<=COMPDIM;pl2++) for(pl=1;pl<=COMPDIM;pl++) for(m=0;m<NUMCS+1;m++) for(l=0;l<NUMCS;l++) GLOBALMACP1A3(pvbcorninterp,pl2,i,j,k,pl,m,l)=valueinit;
479 
480 
482  //
483  // pvcorn must contain velocity in same frame as field primitive in order to avoid interpolating yet another set of quantities (even can't do just 1 extra since 2 directions to interpolate from and no way to keep symmetry of interpolations without doing 2 extras and (e.g.) averaging)
484  // assume final EMF being too large for the local field ($B^2-E^2>0$ or $\gamma^2\sim B^2/(B^2-E^2)$) will not be a problem since extra EMF at CORN would only increase field
485  // not formally inconsistent since didn't interpolate other velocity or field to same location
486  //
487  // for each edge/EMF (dir):
488  // 1) There are 2 values for fields in each directions (odir1,odir2)
489  // 2) There are 2x2 values for velocities in directions (odir1,odir2)
490  //
491  // 3) Need to work out where interpolated quantities go
492  //
493 
494 
495  // unsure if signature and overall sign will be right -- GODMARK
496  // i,j,k should already be taken into account (i.e. no offsets to add)
497  // emf in dir direction
498  for(m=0;m<NUMCS;m++) for(l=0;l<NUMCS;l++){
499  // emf[+- in odir1][+- in odir2]
500  // velocity in same positions as emf
501  // for example, emf3[+-x][+-y] = By[+-x]*vx[+-x][+-y] - Bx[+-y]*vy[+-x][+-y]
502  // below requires velocity to be lab-frame 3-velocity consistent with lab-frame 3-field primitive
503 
504  // see fluxct.c for signature definition of EMF and flux
505 
506  // m%3+1 gives next 1->2,2->3,3->1
507  // 3-(4-m)%3 = (dir+1)%3+1 gives previous 1->3,2->1,3->2
508  // so odir1 is forward cyclic
509  // so odir2 is backward cyclic
510  // notice that the emf in total uses 4 fields and 4*2 velocities for 12 total quantities
511  // not all pbcorn[][?] positions are used (have 3 only need 2 per dir)
512  // pvcorn[which corner][which component in pl form][+-odir1][+-odir2]
513  // pbcorn[which corner][which component in pl form][+-remaining direction that is not corn nor pl-dir]
514 
515  emf2d[m][l] =
516  // + MACP3A0(pbcorn,dir,B1-1+odir2,m,i,j,k)*MACP4A0(pvcorn,dir,U1-1+odir1,m,l,i,j,k)
517  // - MACP3A0(pbcorn,dir,B1-1+odir1,l,i,j,k)*MACP4A0(pvcorn,dir,U1-1+odir2,m,l,i,j,k);
518  + MACP1A3(pvbcorn,dir,i,j,k,odir2,NUMCS,m)*MACP1A3(pvbcorn,dir,i,j,k,odir1,m,l)
519  - MACP1A3(pvbcorn,dir,i,j,k,odir1,NUMCS,l)*MACP1A3(pvbcorn,dir,i,j,k,odir2,m,l);
520  }
521 
522 
524  //
525  // get wave speeds (these are not interpolated yet to CORNER, they start at FACE regardless of STOREWAVESPEEDS==1,2)
526  // note wspeed has NO sign information (for any case, including as set by global_vchar())
527  // c[CMIN,CMAX][0=odir1,1=odir2]
528  // need to determine i,j,k to choose based upon odir value
529  // -?del? since going from FACE to CORN
530  // del2 for c2d[][0] since wspeed[odir1] is wave going in odir1-direction, whereas other wavespeed to MAX with is in other (odir2) direction
531  if(Nvec[odir1]>1){
532  c2d[CMIN][0] = fabs(MAX(0.,MAX(+MACP3A0(wspeed,EOMSETMHD,odir1,CMIN,i,j,k),+MACP3A0(wspeed,EOMSETMHD,odir1,CMIN,i-idel2,j-jdel2,k-kdel2))))*cminfactorodir1;
533  c2d[CMAX][0] = fabs(MAX(0.,MAX(+MACP3A0(wspeed,EOMSETMHD,odir1,CMAX,i,j,k),+MACP3A0(wspeed,EOMSETMHD,odir1,CMAX,i-idel2,j-jdel2,k-kdel2))))*cmaxfactorodir1;
534  }
535  else{
536  // GODMARK: shoud just set the offending wavespeed (associated with non-existing dimensional direction) to 1.0 so don't have this conditional
537  // then speed doesn't matter, not set, so scale-out
538  c2d[CMIN][0] = 1.0;
539  c2d[CMAX][0] = 1.0;
540  }
541 
542  if(Nvec[odir2]>1){
543  c2d[CMIN][1] = fabs(MAX(0.,MAX(+MACP3A0(wspeed,EOMSETMHD,odir2,CMIN,i,j,k),+MACP3A0(wspeed,EOMSETMHD,odir2,CMIN,i-idel1,j-jdel1,k-kdel1))))*cminfactorodir2;
544  c2d[CMAX][1] = fabs(MAX(0.,MAX(+MACP3A0(wspeed,EOMSETMHD,odir2,CMAX,i,j,k),+MACP3A0(wspeed,EOMSETMHD,odir2,CMAX,i-idel1,j-jdel1,k-kdel1))))*cmaxfactorodir2;
545  }
546  else{
547  // then speed doesn't matter, not set, so scale-out
548  c2d[CMIN][1] = 1.0;
549  c2d[CMAX][1] = 1.0;
550  }
551 
552  ctop[0] = MAX(c2d[CMIN][0],c2d[CMAX][0]);
553  ctop[1] = MAX(c2d[CMIN][1],c2d[CMAX][1]);
554 
555 
557  //
558  // compute conserved dissipation term
559  //
561 
562 
563  // "upper" minus "lower" fields
564  // dB[?] corresponds to ? meaning field direction, not interpolation or any other direction
565  // dB[0] corresponds to dB["odir1"]
566  // dB[0] = MACP3A0(pbcorn,dir,B1-1+odir1,1,i,j,k) - MACP3A0(pbcorn,dir,B1-1+odir1,0,i,j,k) ;
567  dB[0] = MACP1A3(pvbcorn,dir,i,j,k,odir1,NUMCS,1) - MACP1A3(pvbcorn,dir,i,j,k,odir1,NUMCS,0) ;
568  // dB[1] corresponds to dB["odir2"]
569  // dB[1] = MACP3A0(pbcorn,dir,B1-1+odir2,1,i,j,k) - MACP3A0(pbcorn,dir,B1-1+odir2,0,i,j,k) ;
570  dB[1] = MACP1A3(pvbcorn,dir,i,j,k,odir2,NUMCS,1) - MACP1A3(pvbcorn,dir,i,j,k,odir2,NUMCS,0) ;
571 
572 
573 
575  //
576  // compute emf
577  //
579 
580  // Del Zanna et al. (2003) has opposite sign in equations 44,45 since they define the electric field (E_i) whereas we define EMF=-gdet E_i
581  // see fluxct.c comments
582  // Sign of dissipative term is as for HLL flux, which since EMF and flux have different sign relationships for each direction/field, we have:
583  //
584  // emf_1 = B^3 v^2 - B^2 v^3 = F2[B3] or -F3[B2] : Dissipative terms: -(dB3) and +(dB2)
585  // emf_2 = B^1 v^3 - B^3 v^1 = F3[B1] or -F1[B3] : Dissipative terms: -(dB1) and +(dB3)
586  // emf_3 = B^2 v^1 - B^1 v^2 = F1[B2] or -F2[B1] : Dissipative terms: -(dB2) and +(dB1)
587  //
588  // So since dissipative term order is EMF[edgedir] += dB[odir1] + dB[odir2]
589  // then we have:
590  // edgedir=1 odir1=2 odir2=3 , so need -dB[1] and +dB[0]
591  // edgedir=2 odir1=3 odir2=1 , so need -dB[1] and +dB[0]
592  // edgedir=3 odir1=1 odir2=2 , so need -dB[1] and +dB[0]
593  // so same formula for all EMFs
594 
595 
596  // below topwave[] are positive definite but could be 0.0 and then HLLFLUX formula not right
597  topwave[0]=c2d[CMIN][0] + c2d[CMAX][0];
598  topwave[1]=c2d[CMIN][1] + c2d[CMAX][1];
599 
600 
601  if( (fluxmethodlocal==HLLFLUX) && (topwave[0]>SMALL) && (topwave[1]>SMALL) ){
602 
603  bottomwave[0]=1.0/topwave[0];
604  bottomwave[1]=1.0/topwave[1];
605 
606  // HLL
607  emffinal =
608  // non-dissipative term
609  + (
610  +c2d[CMAX][0]*c2d[CMAX][1]*emf2d[0][0] // emf has -odir1 -odir2, so wavespeed has +odir1 +odir2
611  +c2d[CMAX][0]*c2d[CMIN][1]*emf2d[0][1] // emf has -odir1 +odir2, so wavespeed has +odir1 -odir2
612  +c2d[CMIN][0]*c2d[CMAX][1]*emf2d[1][0] // emf has +odir1 -odir2, so wavespeed has -odir1 +odir2
613  +c2d[CMIN][0]*c2d[CMIN][1]*emf2d[1][1] // emf has +odir1 +odir2, so wavespeed has -odir1 -odir2
614  )*bottomwave[0]*bottomwave[1]
615  // dissipative terms
616  - EMFDISSIPATION*(
617  // dB has d(B[odir2]) so wavespeed has +-odir1 (note d(B[odir1]) for +-odir1 is 0 due to divb=0) (i.e. otherwise would be 4 dissipation terms for 2D Riemann problem)
618  c2d[CMIN][0]*c2d[CMAX][0]*bottomwave[0]*dB[1]
619  )
620  + EMFDISSIPATION*(
621  // dB has d(B[odir1]) so wavespeed has +-odir2 (note d(B[odir2]) for +-odir2 is 0 due to divb=0) (i.e. otherwise would be 4 dissipation terms for 2D Riemann problem)
622  c2d[CMIN][1]*c2d[CMAX][1]*bottomwave[1]*dB[0]
623  )
624  ;
625  }
626  else{ // assume if not HLL then LAXF since only 2 methods for this routine
627  // LAXF
628  // dB and ctop flip odir's due to divb=0(i.e. otherwise would be 4 dissipation terms for 2D Riemann problem)
629  emffinal =
630  + 0.25*(emf2d[0][0]+emf2d[0][1]+emf2d[1][0]+emf2d[1][1])
631  - EMFDISSIPATION*0.50*(ctop[0]*dB[1] - ctop[1]*dB[0]);
632  }
633 
634 
635 
636 
637 
639  //
640  // set the fluxes (final flux is expected to have geometry on it)
641  //
643 
644  // B inside pbcorn was setup with geometry
645  // assume that if on singularity where gdet=0 then interpolation gave good value on singularity
646  // GODMARK: seems like issue with choice of how to treat gdet is related to presence (or not) of line current on singularity
647  // For example, for POLARAXIS E_z will not be 0 if first used gdet and then interpolated, while if used gdet afterwards then will be 0
648  // Same ambiguity exists in fluxct.c
649 #if(CORNGDETVERSION==1)
650  // even though only want geom.e, geom.e calculation could depend upon many things
651  get_geometry_geomeonly(i, j, k, CORN1-1+dir, ptrgdetgeom); // get geometry at CORN[dir] where emf is located
652 
653  // GODMARK: why use ptrgeom->e here and ptrgeom->g in most other places?
654  geomcornodir1=ptrgdetgeom->EOMFUNCMAC(B1-1+odir1); // which field ptrgeom->e doesn't matter as mentioned below
655  geomcornodir2=ptrgdetgeom->EOMFUNCMAC(B1-1+odir2);
656 #else
657  geomcornodir1=1.0;
658  geomcornodir2=1.0;
659 #endif
660 
661 
662 
663 #if(0) // DEBUG:
664  if(i==26 && j==40 && k==0){
665  dualfprintf(fail_file,"ORIG: emf2d[1][1]=%21.15g emf2d[1][0]=%21.15g emf2d[0][1]=%21.15g emf2d[0][0]=%21.15g ctop[0]=%21.15g ctop[1]=%21.15g dB[0]=%21.15g dB[1]=%21.15g emffinal=%21.15g gdetcorn3=%21.15g\n",emf2d[1][1],emf2d[1][0],emf2d[0][1],emf2d[0][0],ctop[0],ctop[1],dB[0],dB[1],emffinal,ptrgdetgeom->gdet);
666  dualfprintf(fail_file,"ORIG: c2d[CMIN][0]=%21.15g c2d[CMAX][0]=%21.15g c2d[CMIN][1]=%21.15g c2d[CMAX][1]=%21.15g\n",c2d[CMIN][0],c2d[CMAX][0],c2d[CMIN][1],c2d[CMAX][1]);
667  }
668 #endif
669 
670 
671 
672 
673  // see fluxct.c for definitions of signature
674  // e.g. edgedir=3 gives F[1][B2]=E3 and F[2][B1]=-E3 F[3][B3]=0, which is correct.
675  // Checked that correct for all edgedir's
676  // notice that geometries for field-type primitive must all be same for field since otherwise emf ptrgeom->e factor has a mixed association
677  if(Nvec[odir1]>1) MACP1A1(fluxvec,odir1,i,j,k,B1-1+odir2) = + emffinal*geomcornodir2;
678  if(Nvec[odir2]>1) MACP1A1(fluxvec,odir2,i,j,k,B1-1+odir1) = - emffinal*geomcornodir1;
679  if(Nvec[dir]>1) MACP1A1(fluxvec,dir,i,j,k,B1-1+dir) = 0.0;
680 
681 #if((WHICHEOM==WITHNOGDET)&&(NOGDETB1>0)||(NOGDETB2>0)||(NOGDETB3>0))
682  dualfprintf(fail_file,"Makes no sense to have field with different geometry factor since flux,emf mixes those factors\n");
683  myexit(196826);
684 #endif
685 
686  // done!
687 
688  }// end 3D LOOP
689  }// end parallel region
690 
691 
692 
693 
694 
695 #if(0)
696  bound_flux(STAGEM1,t,fluxvec[1],fluxvec[2],fluxvec[3], 0);
697  if(N1>1) bound_prim(STAGEM1,t,fluxvec[1], 0);
698  if(N2>1) bound_prim(STAGEM1,t,fluxvec[2], 0);
699  if(N3>1) bound_prim(STAGEM1,t,fluxvec[3], 0);
700 #endif
701 
702 
703 
704 
705  return (0);
706 }
707 
708 
709 
710 
711 
712 
714 void slope_lim_continuous_e2z(int realisinterp, int dir, int idel, int jdel, int kdel, FTYPE (*primreal)[NSTORE2][NSTORE3][NPR], FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*dq)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP], struct of_loop *face2centloop)
715 {
716  extern void slope_lim_linetype_c2e(int realisinterp, int whichprimtype, int interporflux, int dir, int idel, int jdel, int kdel, FTYPE (*primreal)[NSTORE2][NSTORE3][NPR], FTYPE (*stencilvar)[NSTORE2][NSTORE3][NPR], FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP]);
717  extern void slope_lim_pointtype(int interporflux, int realisinterp, int pl, int dir, int loc, int continuous, int idel, int jdel, int kdel, FTYPE (*primreal)[NSTORE2][NSTORE3][NPR], FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*dq)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP]);
718  int pl,pliter;
719 
720 
721 
722 
723  // TODOMARK: Can take discrete derivative so edge quantity at center, then c2e fully correct, and correctly interpolates as continuous.
724  // Like:
725  // 0 1 2 3
726  // B1 B1 B1 B1 B1
727  //-> dB1 dB1 dB1 dB1
728  //-> interpolate as center to face giving:
729  //-> dl dr dl dr dl dr dl dr dl dr
730  //-> Now have left-right face values as well as center value of dB
731  //
732 
733 
734  PINTERPLOOP(pliter,pl){ // probably only pl=B1+dir-1;
735  // difference oriented on difference in dir, otherwise full
736  }
737 
738  // SUPERGODMARK: preal is located at CENT always, but p2interp will be at FACE, so have to average preal inside to get correct location
739 
740 
741  // SUPERGODMARK: Use continuous version, overrides use of (e.g.) PARALINE in favor of MC continuous.
742  if(OLDNONCONT==1 && LINEINTERPTYPE(lim[dir]) ){ // this overrides lim, but lim must still be set properly
743  get_loop(INTERPLINETYPE, ENOINTERPTYPE, dir, face2centloop);
744 
745  // 1 below means primitives instead of conserved quantities (used for loops)
746  // GODMARK: ENOMARK: pstag below may only contain field so can't be used for pressure indicator
747  // GODMARK: set_interppoint() inside this function sets starting and ending position for loops, and as set c2e always needs more than e2c for obtaining flux, so leaving as for c2e is fine for now
748  slope_lim_linetype_c2e(realisinterp, ENOPRIMITIVE, ENOINTERPTYPE, dir, idel, jdel, kdel, primreal, NULL, p2interp, pleft, pright);
749 
750  // ENOMARK: for ENO should really use special _e2c_cont() function that assumes continuity is required GODMARK
751  // slope_lim_linetype_e2c_cont(realisinterp, ENOPRIMITIVE, ENOINTERPTYPE, dir, idel, jdel, kdel, primreal, NULL, p2interp, pcent);
752  }
753  else{
754  // Should really interpolate such that continuous GODMARK
755  // GODMARK: set_interppoint() inside this function sets starting and ending position for loops, and as set c2e always needs more than e2c for obtaining flux, so leaving as for c2e is fine for now
756  int loc;
757  int continuous;
758  if(OLDNONCONT){
759  loc=CENT;
760  continuous=0;
761  }
762  else{
763  loc=FACE1+dir-1;
764  continuous=1;
765  }
766  get_loop(INTERPPOINTTYPE, ENOINTERPTYPE, dir, face2centloop);
767  PINTERPLOOP(pliter,pl){
768  slope_lim_pointtype(ENOINTERPTYPE, realisinterp, pl, dir, loc, continuous, idel, jdel, kdel, primreal, p2interp, dq, pleft, pright); // GODMARK: overwritting dq from other type of interpolation
769  }
770  }
771 
772 
773 
774  // TODOMARK: Then after interpolation, just sum-up from left-most-edge-value using derivative at edge to get centered quantities
775  // Get final values by doing:
776  //
777  // for linear interpolations, is continuous linear function within cell
778  //
779  // Bc = Bfl + (3.0/8.0)*dl + (1.0/8.0)*dr
780  //
781  // for parabolic interpolations, is continous parabolic function within cell
782  //
783  // Bc = Bfl + (1.0/3.0)*dB + (5.0/24.0)*dl - (1.0/24.0)*dr
784  //
785  // assumes original interpolation of dB properly reduces in shocks, so in shock one reduces down to possibly DONOR so dl=dr=0
786 
787 
788 
789 
790 
791 
792 
793 
794 #if(0)
795  bound_prim(STAGEM1,t,pleft, 0);
796  bound_prim(STAGEM1,t,pright, 0);
797 #endif
798 
799 }
800 
801 
802 
803 
804 
812 int interpolate_ustag2fieldcent(int stage, SFTYPE boundtime, int timeorder, int numtimeorders, FTYPE (*preal)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],FTYPE (*upoint)[NSTORE2][NSTORE3][NPR],FTYPE (*pcent)[NSTORE2][NSTORE3][NPR])
813 {
814  int ustagpoint2pstag(FTYPE (*upoint)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR]);
815  int interpolate_pfield_face2cent(FTYPE (*preal)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],FTYPE (*ucent)[NSTORE2][NSTORE3][NPR],FTYPE (*pcent)[NSTORE2][NSTORE3][NPR], struct of_loop *face2centloop, FTYPE (*dqvec[NDIM])[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*prc)[NSTORE2][NSTORE3][NPR], FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP], int *Nvec);
816  struct of_loop face2cent[NDIM];
817  int finalstep;
818  FTYPE (*dqvec[NDIM])[NSTORE2][NSTORE3][NPR2INTERP];
819  int Nvec[NDIM];
820 
821 
822 
823 #if(0)
824  bound_prim(STAGEM1,boundtime,upoint, 0);
825 #endif
826 
827 
828 
829  // setup spatial sizes
830  Nvec[0]=0;
831  Nvec[1]=N1;
832  Nvec[2]=N2;
833  Nvec[3]=N3;
834 
835 
836  // setup dq's if needed
837  // called by advance() that doesn't have dq1,dq2,dq3 passed to it (yet), so access global dq1,dq2,dq3
838  dqvec[1]=GLOBALPOINT(dq1);
839  dqvec[2]=GLOBALPOINT(dq2);
840  dqvec[3]=GLOBALPOINT(dq3);
841 
842 
843 
844  // Actually updates field using conserved update (and inverts field)
845  // next use of pstagscratch by fluxcalc() will be correct (see setup_rktimestep() commends for RK4)
846  ustagpoint2pstag(upoint,pstag);
847 
848 
849  if(timeorder==numtimeorders-1) finalstep=1; else finalstep=0;
850 
851 
852 
853 
855  //
856  // Bound pstag
857  //
858  // must bound pstag at FACE1,2,3 so enough boundary zones to interpolate to get field at CENT
859  // note that unlike other conserved quantities, since field trivially inverted there is no issue with possible failure modes or fixups, so only need to bound once
860  // That is, we always update field as required for divb=0
861  // bound_pstag() takes care of which quantities to bound (only bounding B1,B2,B3)
862 
863  bound_pstag(stage, finalstep, boundtime, preal, pstag, upoint, USEMPI);
864 
865 
866  // note that ustag isn't bounded, but is used for divb calculation, which is thus only valid at active CENT cells -- but that's all that's in normal dumps unless FULLOUTPUT is used
867 
868 
869  // pstagescratch should contain result of deaverage_ustag2pstag() -- gets utoinvert ready for inversion using guess pb
870  // other quantities in utoinvert are unchanged by this function (and if needed de-averaging this didn't do it!)
871  interpolate_pfield_face2cent(preal,pstag,upoint,pcent,face2cent,dqvec,GLOBALPOINT(prc),GLOBALPOINT(pleft),GLOBALPOINT(pright),Nvec);
872 
873 
874 #if(0)
875  bound_prim(STAGEM1,boundtime,pcent);
876 #endif
877 
878  // pstagscratch is at FACE1,2,3 and is primary field variable
879  // pfield is at CENT and is dependent field variable
880  //
881  // This means pstagscratch must be bounded as a flux1,2,3
882  // In MPI use pstag with boundflux()
883  // In user bound, user must treat field differently knowing where field is located
884 
885  // pfield at CENT does NOT need to be bounded itself since pstag is bounded and then interpolated in extended off-dir range in interpolate_pfield_face2cent() that uses slope_lim_continuous_e2z()
886 
887  // So only need to bound pstag like a flux -- need to bound before FACE_2_CENT interpolation
888 
889 
890  // now have field at CENT wherever needed for both EMF at CORN1,2,3 AND have enough for normal fluxes at faces
891  // Note don't use CENT field to get field in direction of flux of any quantity -- revert to existing staggered value
892  // This is why don't need to bound the field at CENT
893 
894 
895 
896 
897  return(0);
898 
899 }
900 
901 
902 
903 
904 
905 
906 
907 #define USTAG2PSTAGCONSTRAINEDLOOP 1 // should be 1
908 
912 int ustagpoint2pstag(FTYPE (*ustag)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR])
913 {
914  int Nvec[NDIM];
915 
916 
917  Nvec[0]=0;
918  Nvec[1]=N1;
919  Nvec[2]=N2;
920  Nvec[3]=N3;
921 
922 
924  //
925  // get pstag from unew
926  // p should be de-averaged field at FACE1,2,3
927  //
929 
930 
931 
932 #pragma omp parallel
933  {
934  void ustag2pstag(int dir, int i, int j, int k, FTYPE (*ustag)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR]);
935  extern void get_stag_startendindices(int *loop, int dir, int *is,int *ie,int *js,int *je,int *ks,int *ke);
936  int i,j,k,pl,pliter;
937  int dir;
938  FTYPE igdetgnosing;
939  int is,ie,js,je,ks,ke;
940  struct of_gdetgeom gdetgeomfdontuse[NDIM];
941  struct of_gdetgeom *ptrgdetgeomf[NDIM];
942  int jj;
943 
945 
946 
947  // generally ptr's are different inside parallel block
948  DLOOPA(jj) ptrgdetgeomf[jj]=&(gdetgeomfdontuse[jj]);
949 
950 
951 #if(USTAG2PSTAGCONSTRAINEDLOOP==0)
952 
953 
954  // Not well-constrained
955  DIMENLOOP(dir){
956  pl=B1-1+dir;
957 
960 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait // "nowait" ok because each pstag[B1,B2,B3] set independently
962  OPENMP3DLOOPBLOCK2IJK(i,j,k);
963 
964  // get geometry for face pre-interpolated values
965  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgdetgeomf[dir]); // FACE1,FACE2,FACE3 each
966  set_igdetsimple(ptrgdetgeomf[dir]);
967  igdetgnosing = ptrgdetgeomf[dir]->igdetnosing;
968  MACP0A1(pstag,i,j,k,pl) = MACP0A1(ustag,i,j,k,pl)*igdetgnosing;
969  }
970  }
971 
972 
973 
974 #else // else if constrained loops
975 
976 
977 
978  // well-constrained to only update pstag where really want update
979  // This ensures don't modify pstag outside well-defined box that defines current computational space
980  // do pl==B1
981  pl=B1;
982  dir=1;
983  get_stag_startendindices(Uconsevolveloop, dir, &is,&ie,&js,&je,&ks,&ke);
984  // dualfprintf(fail_file,"dir=%d is=%d ie=%d js=%d je=%d ks=%d ke=%d\n",dir,is,ie,js,je,ks,ke);
986  OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
987 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait // "nowait" ok because each pstag[B1,B2,B3] set independently
989  OPENMP3DLOOPBLOCK2IJK(i,j,k);
990 
991  ustag2pstag(dir, i, j, k, ustag,pstag);
992  }
993 
994 
995 
996  // do pl==B2
997  pl=B2;
998  dir=2;
999  get_stag_startendindices(Uconsevolveloop, dir, &is,&ie,&js,&je,&ks,&ke);
1000  // dualfprintf(fail_file,"dir=%d is=%d ie=%d js=%d je=%d ks=%d ke=%d\n",dir,is,ie,js,je,ks,ke);
1002  OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
1003 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait
1005  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1006 
1007  ustag2pstag(dir, i, j, k, ustag,pstag);
1008  }
1009 
1010 
1011 
1012  // do pl==B3
1013  pl=B3;
1014  dir=3;
1015  get_stag_startendindices(Uconsevolveloop, dir, &is,&ie,&js,&je,&ks,&ke);
1016  // dualfprintf(fail_file,"dir=%d is=%d ie=%d js=%d je=%d ks=%d ke=%d\n",dir,is,ie,js,je,ks,ke);
1018  OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
1019 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait
1021  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1022 
1023  ustag2pstag(dir, i, j, k, ustag,pstag);
1024  }
1025 
1026 
1027 #endif
1028  }// end parallel region (with implicit barrier)
1029 
1030 
1031 
1032 
1033 
1034 
1035 #if(0)
1036  bound_prim(STAGEM1,t,pstag);
1037 #endif
1038 
1039 
1040  return(0);
1041 }
1042 
1043 
1044 
1045 
1048 void ustag2pstag(int dir, int i, int j, int k, FTYPE (*ustag)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR])
1049 {
1050  FTYPE igdetgnosing;
1051  int pl,pliter;
1052  struct of_gdetgeom gdetgeomfdontuse[NDIM];
1053  struct of_gdetgeom *ptrgdetgeomf[NDIM];
1054  int jj;
1055 
1056  // assign memory
1057  DLOOPA(jj) ptrgdetgeomf[jj]=&(gdetgeomfdontuse[jj]);
1058 
1059 
1060  pl=B1-1+dir;
1061 
1062  // get geometry for face pre-interpolated values
1063  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgdetgeomf[dir]); // FACE1,FACE2,FACE3 each
1064  set_igdetsimple(ptrgdetgeomf[dir]);
1065  igdetgnosing = ptrgdetgeomf[dir]->igdetnosing;
1066 
1067 
1068  MACP0A1(pstag,i,j,k,pl) = MACP0A1(ustag,i,j,k,pl)*igdetgnosing;
1069 
1070 
1071 }
1072 
1073 
1074 
1075 
1076 
1077 
1078 // if not rescaling, then default is to interpolate \detg B^i rather than B^i -- more accurate for field-aligned flows (e.g. monopole)
1079 // 0 : don't use gdet rescale. Use normal rescale or no rescale.
1080 // 1 : use gdet rescale
1081 // 2 : use gdet rescale dependent on SPC coordinates. \detg B1 alone 1-dir, B2 along 2-dir, and B3 along 3-dir (but \detg B3 just as fine)
1082 //
1083 // \detg B1 alone 1-dir for typical split-monopolar type field.
1084 // B2 along 2-dir because B2 and B2hat are regular near pole and division by near-zero would be inaccurate at pole. Assumes B2 flips sign across pole in correct sense in boundary cells as viewed by active cells. Also for EMF_1 or EMF_3 wouldn't make sense unless also interpolated \detg v2 that makes no sense either.
1085 // B3 or \detg B3 along 3-dir is same.
1086 //
1087 // 1 might be fine because this is only used for face2cent, and using "1" instead of "2" allows even jumps in B2 (e.g. due to sign change) across the pole so CENT version of B2 higher order.
1088 // However, experimentally found 1 leads to MANY more hot->entropy reductions. So should use "2"
1089 //
1091 #define IFNOTRESCALETHENUSEGDET 1
1092 
1093 #define IFNOTRESCALETHENUSEGDETswitch(dir) (IFNOTRESCALETHENUSEGDET==1 || (IFNOTRESCALETHENUSEGDET==2 && (ISSPCMCOORD(MCOORD)==0 || ISSPCMCOORD(MCOORD)==1 && (dir==1 || dir==3))))
1094 
1095 
1096 
1098 static void rescale_calc_stagfield_full(int *Nvec, FTYPE (*pstag)[NSTORE2][NSTORE3][NPR2INTERP],FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP])
1099 {
1100  int nprlocalstart,nprlocalend;
1101  int nprlocallist[MAXNPR];
1102 
1103 
1105  //
1106  // save choice for interpolations so can restore global variables after done
1107  {
1108  int pl,pliter;
1109  nprlocalstart=npr2interpstart;
1110  nprlocalend=npr2interpend;
1111  PMAXNPRLOOP(pl) nprlocallist[pl]=npr2interplist[pl];
1112  }
1113 
1114 
1115 #pragma omp parallel OPENMPGLOBALPRIVATEFORSTATEANDGEOMINTERPFULLNPR2INTERP // requires full copyin() changes npr2interp stuff
1116  {
1117  int i,j,k;
1118  int jj;
1119  int pl,dir;
1120  struct of_geom geomfdontuse[NDIM];
1121  struct of_geom *ptrgeomf[NDIM];
1122  struct of_gdetgeom gdetgeomfdontuse[NDIM];
1123  struct of_gdetgeom *ptrgdetgeomf[NDIM];
1124  extern int rescale(int which, int dir, FTYPE *pr, struct of_geom *geom,FTYPE*newvar);
1125 
1127 
1128 
1129  // generally ptr's are different inside parallel block
1130  // assign memory
1131  DLOOPA(jj) ptrgeomf[jj]=&(geomfdontuse[jj]);
1132  DLOOPA(jj) ptrgdetgeomf[jj]=&(gdetgeomfdontuse[jj]);
1133 
1134 
1135  // LOOP over faces (dimensions)
1136  DIMENLOOP(dir){ // dimen loop because rescale() is at different locations
1137  // odir1=dir%3+1;
1138  // odir2=(dir+1)%3+1;
1139 
1140  // if(Nvec[dir]==1 || (Nvec[dir]!=1 && (Nvec[odir1]==1 && Nvec[odir2]==1) ) ) continue; // later will copy if no such dimension or such dimension but other dimensions don't exist so field must be constant
1141  if(Nvec[dir]==1) continue; // later will copy if no such dimension
1142 
1143 
1144  pl=B1-1+dir;
1145  npr2interpstart=npr2interpend=0; npr2interplist[0]=pl; // B1,B2,B3 each
1146 
1147 
1148 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) // NO, rescale() may set arbitrary p2interp's //nowait // p2interp[B1,B2,B3] set independently
1150  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1151 
1152 
1153 #if(RESCALEINTERPFLUXCTSTAG && RESCALEINTERP)
1154  // get geometry for face pre-interpolated values
1155  get_geometry(i, j, k, FACE1-1+dir, ptrgeomf[dir]); // FACE1,FACE2,FACE3 each
1156  rescale(DORESCALE,dir,MAC(pstag,i,j,k),ptrgeomf[dir],MAC(p2interp,i,j,k));
1157 #else
1158  MACP0A1(p2interp,i,j,k,pl) = MACP0A1(pstag,i,j,k,pl);
1159 
1161  // get geometry for face pre-interpolated values
1162  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgdetgeomf[dir]); // FACE1,FACE2,FACE3 each
1163  MACP0A1(p2interp,i,j,k,pl) *= (ptrgdetgeomf[dir]->gdet);
1164  }
1165 #endif
1166 
1167  }// end COMPFULLLOOP
1168  }// end over dirs
1169  }// end parallel region (with implicit barrier)
1170 
1171 
1172 
1174  //
1175  // restore choice for interpolations from global variables
1176 #pragma omp parallel
1177  { // must set npr2interp stuff inside parallel region since threadprivate
1178  int pl;
1179  npr2interpstart=nprlocalstart;
1180  npr2interpend=nprlocalend;
1181  PMAXNPRLOOP(pl) npr2interplist[pl]=nprlocallist[pl];
1182  }
1183 
1184 
1185 }
1186 
1187 
1188 
1189 
1190 
1191 
1192 
1193 
1194 
1195 
1227 int interpolate_pfield_face2cent(FTYPE (*preal)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],FTYPE (*ucent)[NSTORE2][NSTORE3][NPR],FTYPE (*pcent)[NSTORE2][NSTORE3][NPR], struct of_loop *face2centloop, FTYPE (*dqvec[NDIM])[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*prc)[NSTORE2][NSTORE3][NPR], FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP], int *Nvec)
1228 {
1229  FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP];
1230  int nprlocalstart,nprlocalend;
1231  int nprlocallist[MAXNPR];
1232 
1233 
1234 
1236  // PROCEDURE:
1237  // 1) save interp list
1238  // 2) setup which quantities to interpolate
1239  // 3) rescale pstag (no need to unrescale since have separate memory for p2interp)
1240  // 4) interpolate rescaled pstag (p2interp)
1241  // 5) obtain pcent from dq or pleft/pright for simple interpolation/averaging method
1242  // 6) copy fields if not interpolated/rescaled
1243  // 7) restore interp list
1244 
1245  // GODMARK: in 1D don't have to interpolate face2cent for field in dir-direction since has to be constant
1246 
1248  //
1249  // save choice for interpolations so can restore global variables after done
1250  {
1251  int pl,pliter;
1252  nprlocalstart=npr2interpstart;
1253  nprlocalend=npr2interpend;
1254  PMAXNPRLOOP(pl) nprlocallist[pl]=npr2interplist[pl];
1255  }
1256 
1257 
1259  //
1260  // rescale before interpolation
1261  //
1264  p2interp=prc; // it's different
1265  // rescale or multiply by \sqrt{-g}
1266  rescale_calc_stagfield_full(Nvec, pstag,p2interp);
1267  }
1268  else{
1269  p2interp=pstag; // it's itself
1270  }
1271 
1272 
1273 
1274 
1276  //
1277  // LOOP OVER FACES for each dimension
1278  //
1279  // Peform interpolation on point quantity (even for ENO/FV method a2c_perps would be used before here)
1280  //
1282 
1283 #pragma omp parallel OPENMPGLOBALPRIVATEFORGEOMNPR2INTERP
1284  {
1285  extern int choose_limiter(int dir, int i, int j, int k, int pl);
1286  void slope_lim_continuous_e2z(int realisinterp, int dir, int idel, int jdel, int kdel, FTYPE (*primreal)[NSTORE2][NSTORE3][NPR], FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*dq)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP], struct of_loop *face2centloop);
1287  int pl,pliter;
1288  int idel,jdel,kdel;
1289  int i,j,k;
1290  int dir;
1291  int locallim;
1292  FTYPE pstore_l[NPR2INTERP],pstore_r[NPR2INTERP];
1293  FTYPE *p2interp_l,*p2interp_r;
1294  FTYPE p_l[NPR2INTERP], p_r[NPR2INTERP];
1295  int usedq;
1296  int realisinterp;
1297  int odir1,odir2;
1298  FTYPE igdetgnosing;
1299  int is,ie,js,je,ks,ke;
1300  struct of_geom geomcdontuse;
1301  struct of_geom *ptrgeomc=&geomcdontuse;
1302  struct of_geom geomfdontuse[NDIM];
1303  struct of_geom *ptrgeomf[NDIM];
1304  struct of_gdetgeom gdetgeomcdontuse;
1305  struct of_gdetgeom *ptrgdetgeomc=&gdetgeomcdontuse;
1306  struct of_gdetgeom gdetgeomfdontuse[NDIM];
1307  struct of_gdetgeom *ptrgdetgeomf[NDIM];
1308  int jj;
1309  FTYPE ucentgdet;
1310 
1312 
1313  // assign memory
1314  DLOOPA(jj) ptrgeomf[jj]=&(geomfdontuse[jj]);
1315  DLOOPA(jj) ptrgdetgeomf[jj]=&(gdetgeomfdontuse[jj]);
1316 
1317  // Setup rescale pointer reference
1318 #if(RESCALEINTERPFLUXCTSTAG && RESCALEINTERP)
1319  p2interp_l=pstore_l; // then need separate storage
1320  p2interp_r=pstore_r;
1321 #else
1322  p2interp_l=p_l; // p2interp_? is final p_?
1323  p2interp_r=p_r;
1324 #endif
1325 
1326 
1327 
1328 
1329  // GODMARK: for now use standard interpolation and just force continuity by averaging (probably leads to unstable algorithm)
1330  DIMENLOOP(dir){
1331 
1332  // odir1=dir%3+1;
1333  // odir2=(dir+1)%3+1;
1334 
1336  //
1337  // for TESTNUMBER 1002, stag, recon, below causes peak of B2/B3 to be smaller -- NO IDEA WHY SUPERGODMARK
1338  // for same test, stag, fv method has small peak even with Nvec[dir]==1 only
1339  //
1340  //if(Nvec[dir]==1 || (Nvec[dir]!=1 && (Nvec[odir1]==1 && Nvec[odir2]==1) ) ) continue; // later will copy if no such dimension or such dimension but other dimensions don't exist so field must be constant
1341  //
1343 
1344 
1345  // setup which quantity to interpolate
1346  pl = B1-1+dir;
1347  npr2interpstart=npr2interpend=0; npr2interplist[0]=pl; // B1,B2,B3 each for each dir=1,2,3
1348 
1349 
1350 
1351 
1352  if(Nvec[dir]==1){
1353 
1354 
1356  //
1357  // Copy if no such dimension or such dimension but other dimensions don't exist so field must be constant
1358  // copy over those things not interpolating (and hence not rescalig either)
1359  // unlike FACE_to_EDGE, these degenerate cases result in a trivial copy from the fake FACE to CENT
1360  // what's constant is \detg B^i, not B^i, so need geometry if field along 1D dir with no other dimensions
1361  // no idel,jdel,kdel for simplicity
1363 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait // don't wait for each dir since independent and all memory written to (and used in later loops) is independent for each dir.
1365  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1366 
1367  if(pcent!=NULL){
1368  MACP0A1(pcent,i,j,k,pl)=MACP0A1(pstag,i,j,k,pl);
1369  }
1370 
1371  // get ucent if required
1372  if(ucent!=NULL){// OPTMARK: Is this expensive?
1373  // Note: If WHICHEOM==WITHNOGDET and turned off \detg for fields, then staggered method doesn't work, so ok to assume gdet below and assume standard primitive field such that \detg B^i = conserved quantity
1374  get_geometry_gdetonly(i, j, k, CENT, ptrgdetgeomc); // final quantity is at CENT
1375  MACP0A1(ucent,i,j,k,pl) = MACP0A1(pstag,i,j,k,pl)*(ptrgdetgeomc->gdet); // exactly correct (even for ENO/FV)
1376  }// end if ucent!=NULL
1377 
1378  }// end 3D LOOP
1379 
1380 
1381 
1382 
1383  }
1384  else{ // Then Nvec[dir]!=1, so should treat field generally along this direction
1385 
1386 
1387 
1388  // get loop details
1389  idel = fluxloop[dir][FIDEL];
1390  jdel = fluxloop[dir][FJDEL];
1391  kdel = fluxloop[dir][FKDEL];
1392 
1394  // interpolate
1396  realisinterp=0; // since only dealing with fields
1397  slope_lim_continuous_e2z(realisinterp, dir, idel, jdel, kdel, preal, p2interp, dqvec[dir], pleft, pright, &(face2centloop[dir]));
1398 
1399 
1401  // get p_l p_r
1403  //
1404  // interpolate primitive using slope (dq) or directly from pleft and pright
1405  // For FV: p_left, p_right (indexed by grid cell #) -> p2interp_l, p2interp_r (indexed by interface #) -- atch comment
1406  //
1407  // always do since p2interp is good and dq/pleft/pright should have stored quantities or just-computed quantities
1409 
1410  // Assume for now that limiter is not per i,j,k but only per dir (unlike normal interpolation)
1411  // no HORIZONSUPERFAST here
1412  locallim=choose_limiter(dir, 0,0,0,pl);
1413  usedq = usedqarray[locallim];
1414 
1415  // using COMPZSLOOP since final CENT quantity is used wherever centered primitive is needed for flux (which is sometimes transverse direction)
1416  // do maximal loop but avoid going out of bounds when accessing dqvec,pleft,pright
1417  // NOW do constrained loop
1418  get_inversion_startendindices(Uconsevolveloop,&is,&ie,&js,&je,&ks,&ke);
1420  OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
1421 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
1422  OPENMP3DLOOPBLOCK{
1423  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1424 
1425 
1426 
1427 #if(OLDNONCONT)
1428  // note that interpolation from FACE_to_CENT is different than from FACE_to_EDGE or CENT_to_FACE
1429  // if not rescaling or auto-gdet rescaling, then p2interp_? is already really p_?, otherwise p2interp_? is separate memory from p_?
1430  if(usedq){
1431  p2interp_l[pl] = MACP0A1(p2interp,i,j,k,pl) + 0.5 * MACP1A1(dqvec,dir,i,j,k,pl);
1432  p2interp_r[pl] = MACP0A1(p2interp,i + idel,j + jdel,k + kdel,pl) - 0.5 * MACP1A1(dqvec,dir,i + idel,j + jdel,k + kdel,pl);
1433  }
1434  else{
1435  p2interp_l[pl] = MACP0A1(pright,i,j,k,pl);
1436  p2interp_r[pl] = MACP0A1(pleft,i+idel,j+jdel,k+kdel,pl);
1437  }
1438 #else
1439  // note that interpolation from FACE_to_CENT is different than from FACE_to_EDGE or CENT_to_FACE
1440  // if not rescaling or auto-gdet rescaling, then p2interp_? is already really p_?, otherwise p2interp_? is separate memory from p_?
1441  if(usedq){
1442  p2interp_r[pl] = p2interp_l[pl] = MACP0A1(p2interp,i,j,k,pl) + 0.5 * MACP1A1(dqvec,dir,i,j,k,pl);
1443  }
1444  else{
1445  p2interp_r[pl] = p2interp_l[pl] = MACP0A1(pright,i,j,k,pl); // left at same i,j,k just set equal to right, so can ignore left.
1446  }
1447 #endif
1448 
1449  // TEST ddq=0 equiv or behavior like Athena that just averages the faces so Bi along i is assumed to be piece-wise continuous linear
1450  // p2interp_r[pl] = p2interp_l[pl] = 0.5*(MACP0A1(p2interp,i,j,k,pl) + MACP0A1(p2interp,i+idel,j+jdel,k+kdel,pl));
1451 
1452 
1453 
1454 
1456  //
1457  // after interpolation, unrescale from p2interp to normal primitive
1458  //
1460 #if(RESCALEINTERPFLUXCTSTAG && RESCALEINTERP)
1461  get_geometry(i, j, k, CENT, ptrgeomc); // final quantity is at CENT
1462  rescale(UNRESCALE,dir,p_l,ptrgeomc,p2interp_l);
1463  rescale(UNRESCALE,dir,p_r,ptrgeomc,p2interp_r);
1464 
1465  if(ucent!=NULL) MACP0A1(ucent,i,j,k,pl) = 0.5*(p_l[pl]+p_r[pl])*(ptrgeomc->gdet); // exactly correct (even for ENO/FV)
1466 
1467 #elif(IFNOTRESCALETHENUSEGDET)
1468  get_geometry_gdetonly(i, j, k, CENT, ptrgdetgeomc); // final quantity is at CENT
1469 
1470 
1472  set_igdetsimple(ptrgdetgeomc);
1473  igdetgnosing=ptrgdetgeomc->igdetnosing;
1474  ucentgdet=1.0;
1475  }
1476  else{
1477  igdetgnosing=1.0;
1478  ucentgdet=(ptrgdetgeomc->gdet);
1479  }
1480 
1481  // Assign \detg B^i (must come before p_{lr} mod since p2interp_{lr} pointer = p_{lr} pointer
1482  if(ucent!=NULL) MACP0A1(ucent,i,j,k,pl)=0.5*(p2interp_l[pl]+p2interp_r[pl])*ucentgdet; // go ahead and assign ucent if this method
1483 
1484  // now get B^i from \detg B^i
1485  // remove \detg used during interpolation
1486  p_l[pl] = p2interp_l[pl]*igdetgnosing;
1487  p_r[pl] = p2interp_r[pl]*igdetgnosing;
1488 
1489 
1490 #else
1491  // otherwise p2interp_{l,r} are really just pointing to p_l and p_r
1492  if(ucent!=NULL){
1493  get_geometry_gdetonly(i, j, k, CENT, ptrgdetgeomc); // final quantity is at CENT
1494  // Note: If WHICHEOM==WITHNOGDET and turned off \detg for fields, then staggered method doesn't work, so ok to assume gdet below and assume standard primitive field such that \detg B^i = conserved quantity
1495  MACP0A1(ucent,i,j,k,pl) = 0.5*(p2interp_l[pl]+p2interp_r[pl])*(ptrgdetgeomc->gdet); // exactly correct (even for ENO/FV)
1496  }
1497 
1498 #endif
1499 
1500 
1501  if(pcent!=NULL){
1502  // now set pcent -- GODMARK -- should interpolate such that only 1 continuous value
1503  // Must preserve divb in 1D Riemann problem, so B^{dir} must be continuous
1504  // Yes, should use larger stencil and interpolate such that constant. Essentially choose
1505  // large stencil and effectively choosing which points we trust (not necessarily local points)
1506  MACP0A1(pcent,i,j,k,pl)=0.5*(p_l[pl]+p_r[pl]);
1507  }
1508 
1509  }// endCOMPZSLOOP
1510 
1511  }// end if N>1
1512 
1513  }// end DIMENLOOP
1514  }// end parallel region (with implicit barrier)
1515 
1516 
1517 
1518 
1519 
1520 
1522  //
1523  // restore choice for interpolations from global variables
1524 #pragma omp parallel
1525  { // must set npr2interp stuff inside parallel region since threadprivate
1526  int pl;
1527  npr2interpstart=nprlocalstart;
1528  npr2interpend=nprlocalend;
1529  PMAXNPRLOOP(pl) npr2interplist[pl]=nprlocallist[pl];
1530  }
1531 
1532 
1533 #if(0)
1534  if(pcent!=NULL) bound_prim(STAGEM1,t,pcent);
1535  if(ucent!=NULL) bound_prim(STAGEM1,t,ucent);
1536 #endif
1537 
1538  return(0);
1539 
1540 }
1541 
1542 
1543 
1544 
1545 
1546 
1560 void slope_lim_face2corn(int realisinterp, int dir, int idel, int jdel, int kdel, FTYPE (*primreal)[NSTORE2][NSTORE3][NPR], FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*dq)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP], struct of_loop *face2cornloop)
1561 {
1562  extern void slope_lim_linetype_c2e(int realisinterp, int whichprimtype, int interporflux, int dir, int idel, int jdel, int kdel, FTYPE (*primreal)[NSTORE2][NSTORE3][NPR], FTYPE (*stencilvar)[NSTORE2][NSTORE3][NPR], FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP]);
1563  extern void slope_lim_pointtype(int interporflux, int realisinterp, int pl, int dir, int loc, int continuous, int idel, int jdel, int kdel, FTYPE (*primreal)[NSTORE2][NSTORE3][NPR], FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*dq)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP]);
1564  int pl,pliter;
1565  int interporflux;
1566 
1567 
1568  if(extrazones4emf){
1569  interporflux=ENOINTERPTYPE4EMF;
1570 
1571  }
1572  else{
1573  interporflux=ENOINTERPTYPE;
1574  }
1575 
1576  // SUPERGODMARK: primreal is located at CENT always, but p2interp can be at FACE in orthogonal direction, so have to average preal inside to get correct location
1577 
1578 
1579  if( LINEINTERPTYPE(lim[dir]) ){ // this overrides lim, but lim must still be set properly
1580  // ENOPRIMITIVE below means primitives instead of conserved quantities
1581  get_loop(INTERPLINETYPE, interporflux, dir, face2cornloop);
1582  slope_lim_linetype_c2e(realisinterp, ENOPRIMITIVE, interporflux, dir, idel, jdel, kdel, primreal, NULL, p2interp, pleft, pright);
1583  }
1584  else{
1585  int loc=FACE1+dir-1; // CENT relative to direction of interpolation, but FACE1+dir-1 relative to primreal
1586  int continuous=0;
1587  get_loop(INTERPPOINTTYPE, interporflux, dir, face2cornloop);
1588  PINTERPLOOP(pliter,pl){
1589  slope_lim_pointtype(interporflux,realisinterp, pl, dir, loc, continuous, idel, jdel, kdel, primreal, p2interp, dq, pleft, pright);
1590  }
1591  }
1592 
1593 
1594 #if(0)
1595  bound_prim(STAGEM1,t,pleft);
1596  bound_prim(STAGEM1,t,pright);
1597 #endif
1598 
1599 
1600 }
1601 
1602 
1603 
1604 
1605 
1606 
1607 
1608 
1652 
1654 
1667 
1675 #define INCLUDEGDETINTRANSVERSEINTERPLATIONOFFIELD 2
1676 
1677 
1679 
1682 
1684 
1686 
1688 
1691 #define INCLUDEGDETINTRANSVERSEINTERPLATIONOFFIELDswitchuniboth(facedir,interpdir) (INCLUDEGDETINTRANSVERSEINTERPLATIONOFFIELD==1 || (INCLUDEGDETINTRANSVERSEINTERPLATIONOFFIELD==2 && (ISSPCMCOORD(MCOORD)==0 || ISSPCMCOORD(MCOORD)==1 && (facedir==1 && (interpdir==1 || interpdir==3) || facedir==2 && (interpdir==1 || interpdir==3) || facedir==3 && (interpdir==1 || interpdir==3) )))) // GODMARK: Want to allow interpdir==2 with facedir==3, but not working yet.
1692 
1693 
1694 
1695 
1701 
1703 
1707 #define INCLUDEGDETINTRANSVERSEINTERPLATIONOFVELOCITY 0
1708 
1712 #define INCLUDEGDETINTRANSVERSEINTERPLATIONOFVELOCITYswitchuniboth(facedir,odir) (INCLUDEGDETINTRANSVERSEINTERPLATIONOFVELOCITY==1 || (INCLUDEGDETINTRANSVERSEINTERPLATIONOFVELOCITY==2 && (ISSPCMCOORD(MCOORD)==0 || ISSPCMCOORD(MCOORD)==1 && (odir==1 || odir==3) )))
1713 
1714 
1715 
1716 
1717 
1724 int interpolate_prim_face2corn(FTYPE (*pr)[NSTORE2][NSTORE3][NPR], FTYPE (*primface_l)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*primface_r)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP],
1725  //FTYPE (*pbcorn)[COMPDIM][NUMCS][NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3],
1727  struct of_loop *cent2faceloop, struct of_loop (*face2cornloop)[NDIM][NDIM],
1728  FTYPE (*prc)[NSTORE2][NSTORE3][NPR2INTERP],
1729  FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP],
1730  FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP],
1731  int *Nvec, FTYPE (*dqvec[NDIM])[NSTORE2][NSTORE3][NPR2INTERP])
1732 {
1733  FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP];
1734  int nprlocalstart,nprlocalend;
1735  int nprlocallist[MAXNPR];
1736 
1737 
1738 
1739  // GODMARK: face2corn duplicates cent2face if in 1D
1740  // This causes FLUXCTSTAG method to be slightly slower than FLUXCTTOTH method even in 1D, and somewhat still in 2D since comparing simple averaging with full interpolation
1741 
1743  //
1744  // save choice for interpolations
1745  {
1746  int pl,pliter;
1747  nprlocalstart=npr2interpstart;
1748  nprlocalend=npr2interpend;
1749  PMAXNPRLOOP(pl) nprlocallist[pl]=npr2interplist[pl];
1750  }
1751 
1752 
1754  //
1755  // Procedure: (follow interpolate_pfield_face2cent() above)
1756 
1757  //
1758  // 1) Take primface_l and primface_2 and convert velocity term (have all components) to lab-frame 3-velocity (can't modify primface!!) -- so need another space? (vconemf?) FTYPE BASEMACP0A1(vconemf,N?M,...,NDIM-1);
1759  // 2) rescale() can be setup, but only for field since rescale() assumes input is primitive and after interpolation wouldn't be able to recover lab-frame 3-velocity cmponents if were using primitive velocity (unless WHICHVEL=VEL3, rarely used so no code for that special case when rescale() could be used)
1760  //
1761  // 3) For each of 3 edges, interpolate up and down (into pleft,pright) from each 1 FACE to 2 different CORNs
1762  //
1763  // 4) take interpolated pleft,pright and form p_l and p_r type quantities inside pbcorn[] and pvcorn[]
1764  //
1765  // 5)
1766  //
1767  //
1768  //
1769  //
1770  //
1771  //
1772  //
1773 
1774  // Interpolation list:
1775  //
1776  // FACE1: B1 -> +-C2 and +-C3 l/r V2 -> lr/+-C3 l/r V3 -> lr/+-C2
1777  // FACE2: B2 -> +-C1 and +-C3 l/r V1 -> lr/+-C3 l/r V3 -> lr/+-C1
1778  // FACE3: B3 -> +-C1 and +-C2 l/r V1 -> lr/+-C2 l/r V2 -> lr/+-C1
1779 
1780  // loop over each edge(CORN1,2,3), interpolating in both odir1,odir2 directions and if that odir1,2 direction has N[odir1,2]==1, then just copy instead of interpolate
1781  // only have 1 dq,pleft,pright for NPR2INTERP quantities
1782 
1783  // sort above list by edge(C1,C2,C3):
1784 
1785  // +-C1: FACE2 B2 interpolated in dir=3 ...........
1786 
1787 
1789  // interpolate dimension-by-dimension to allow future optimizations based upon memory localization
1790  // also this allows feeding in primface_l and primface_r directly
1792 
1793  // total of 6 sets of interpolations
1794  // note have chosen to mix velocity,field interpolations with certain symmetry. In the end this means velocity is interpolated along its own direction only -- maybe not best?
1795  // note primface_l[i][Bi]=primface_r[i][Bi]
1796  // note not using many of the primface_l and primface_r (e.g. primface_lr[1][B2] -- cross fields since less local compared to directly evolved staggered field), but others are simply not used
1797  //
1798  // +-dir=1 : FACE2_to_CORN3 1 B2 & 2 V1 (primface_l[2][B2] and primface_lr[2][U1]) , FACE3_to_CORN2 1 B3, 2 V1 (primface_l[3][B3] and primface_lr[3][U1])
1799  // +-dir=2 : FACE1_to_CORN3 1 B1 & 2 V2 (primface_l[1][B1] and primface_lr[1][U2]) , FACE3_to_CORN1 1 B3, 2 V2 (primface_l[3][B3] and primface_lr[3][U2])
1800  // +-dir=3 : FACE1_to_CORN2 1 B1 & 2 V3 (primface_l[1][B1] and primface_lr[1][U3]) , FACE2_to_CORN1 1 B2, 2 V3 (primface_l[2][B2] and primface_lr[2][U3])
1801 
1802 
1804  //
1805  // before computing EMF, need to convert velocity primitive to something consistent with field primitive frame
1806  // i.e. B^i (lab-frame 3-field) is normal field primitive, so use v^i (lab-frame 3-velocity) for velocity
1807  // otherwise number of interpolations increases to 2*4 extra per edge(CORN) since need symmetric value of the other velocity or uu0 if sending ucon
1808  // so just send lab-frame 3-velocity v^i as consistent with lab-frame field B^i in Faraday,Maxwell tensors
1809 
1810  // instead of using rescale(), just assume always better to inteprolate gdet B^i since the flux is conserved
1811 #define NUMSTAGINTERP 6
1812 #define BFACEINTERP 0
1813 #define BFACEINTERPODIR1 0
1814 #define BLFACEINTERP 0 // same as BFACEINTERP
1815 #define BRFACEINTERP 1 // only used if Nvec[dir]==1 [No, but used to hold non-gdet applied version if required]
1816 #define BFACEINTERPODIR2 1 // used to hold standard B field, not gdet*B, in case required.
1817 #define VLODIR1INTERP 2
1818 #define VRODIR1INTERP 3
1819 #define VLODIR2INTERP 4
1820 #define VRODIR2INTERP 5
1821 
1822 
1823 #if(NUMSTAGINTERP>NPR2INTERP)
1824 #error "Cannot have NUMSTAGINTERP>NPR2INTERP. Create new memory space if have to."
1825 #endif
1826 
1827 
1828  // holds quantities prepared for interpolation with space used as listed above
1829  p2interp=prc;
1830 
1831 
1832 
1833  // Loop over faces that contains the original interpolation so only have to compute \detg B^i and v^i once instead of multiple times for each +-dir=1,2,3
1834  // FACE1: B1 -> +-C2 and +-C3 l/r V2 -> lr/+-C3 l/r V3 -> lr/+-C2
1835  // FACE2: B2 -> +-C1 and +-C3 l/r V1 -> lr/+-C3 l/r V3 -> lr/+-C1
1836  // FACE3: B3 -> +-C1 and +-C2 l/r V1 -> lr/+-C2 l/r V2 -> lr/+-C1
1837 
1838 
1839 
1840 
1841 
1842 
1843 #pragma omp parallel OPENMPGLOBALPRIVATEFORUCONANDGEOMNPR2INTERP
1844  {
1845  void slope_lim_face2corn(int realisinterp, int dir, int idel, int jdel, int kdel, FTYPE (*primreal)[NSTORE2][NSTORE3][NPR], FTYPE (*p2interp)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*dq)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pleft)[NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pright)[NSTORE2][NSTORE3][NPR2INTERP], struct of_loop *face2cornloop);
1846  int pl,pliter;
1847  int idel,jdel,kdel;
1848  int idel1,jdel1,kdel1;
1849  int idel2,jdel2,kdel2;
1850  int i,j,k;
1851 
1852  struct of_geom geomfdontuse;
1853  struct of_geom *ptrgeomf=&geomfdontuse;
1854 
1855  struct of_gdetgeom gdetgeomfdontuse;
1856  struct of_gdetgeom *ptrgdetgeomf=&gdetgeomfdontuse;
1857 
1858  struct of_gdetgeom gdetgeomcdontuse;
1859  struct of_gdetgeom *ptrgdetgeomc=&gdetgeomcdontuse;
1860 
1861  struct of_gdetgeom gdetgeomcorndontuse;
1862  struct of_gdetgeom *ptrgdetgeomcorn=&gdetgeomcorndontuse;
1863 
1864  int dir,interpdir,edgedir;
1865  int locallim;
1866  FTYPE pstore_l[NPR2INTERP],pstore_r[NPR2INTERP];
1867  FTYPE *p2interp_l,*p2interp_r;
1868  FTYPE p_l[NPR2INTERP], p_r[NPR2INTERP];
1869  int enerregion;
1870  int *localenerpos;
1871  int odir1,odir2;
1872  int EMFodir1,EMFodir2;
1873  struct of_state ql,qr;
1874  struct of_state *ptrql,*ptrqr;
1875  FTYPE igdetgnosing,igdetgnosingvel;
1876  int usedq;
1877  int whichodir;
1878  int BFACEINTERPCURRENT;
1879  int Aodir1,Aodir2;
1880  int Bodir1,Bodir2;
1881  int Codir1,Codir2;
1882  int Dodir1,Dodir2;
1883  extern int choose_limiter(int dir, int i, int j, int k, int pl);
1884  int realisinterp;
1885  int is,ie,js,je,ks,ke;
1886  FTYPE *prface_l,*prface_r;
1887 
1888 
1889 
1891 
1892 
1893  // default state pointer (from now on below code should only use ptrql,ptrqr
1894  ptrql=&ql;
1895  ptrqr=&qr;
1896 
1897  p2interp_l=pstore_l;
1898  p2interp_r=pstore_r;
1899 
1900 
1902  //
1903  // Loop over faces
1904  //
1906  DIMENLOOP(dir){
1907 
1908 
1909 
1910 
1912  //
1913  // other dimensions
1914  get_odirs(dir,&odir1,&odir2);
1915 
1916  // if(Nvec[odir1]==1 && Nvec[odir2]==1) then EMF[dir]==0, but still copy over results in accordance with this routine since results here are for other EMFs
1917  // for example, if 2D in dirs=1,2 and 1-D in dir=3, then FACE3 still gives EMF1,EMF2 whose differences in dirs=1,2 is used for evolution
1918  // later explicit interpolations are avoided if interpdir is 1-D
1919 
1921  //
1922  // get direction offsets for array accesses
1923  //
1925  idel1 = fluxloop[odir1][FIDEL];
1926  jdel1 = fluxloop[odir1][FJDEL];
1927  kdel1 = fluxloop[odir1][FKDEL];
1928 
1929  idel2 = fluxloop[odir2][FIDEL];
1930  jdel2 = fluxloop[odir2][FJDEL];
1931  kdel2 = fluxloop[odir2][FKDEL];
1932 
1933 
1934 
1935 
1937  //
1938  // Convert and store primitive into p2interp[] -- these are *all* the quantities needed from this face-dir
1939  //
1941 
1942  // DEBUG:
1943  // dualfprintf(fail_file,"%d %d : %d %d : %d %d\n",cent2faceloop[dir].is, cent2faceloop[dir].ie, cent2faceloop[dir].js, cent2faceloop[dir].je, cent2faceloop[dir].ks, cent2faceloop[dir].ke);
1944 
1945  // Was using:
1946  // COMPZSLOOP( -N1BND, N1-1+N1BND, -N2BND, N2-1+N2BND, -N3BND, N3-1+N3BND ){
1947  // But, need loops to be controlled to don't access beyond where left-right faces set since ucon can fail with arbitrary input or nan's unlike other types of calculations
1948  // cent2faceloop is over CENT positions, which now since accessing the faces needs to be transcribed to FACE values interior to those CENT values
1949  // One shifts up in interpdir (dir) flux direction because interpolated -1 extra CENT cell and N CENT cell to get flux at 0 and N.
1950  // Note that +SHIFT term just translates pleft/pright type locations to p_l/p_r type locations
1951  is=cent2faceloop[dir].is + SHIFT1*(dir==1);
1952  ie=cent2faceloop[dir].ie;
1953  js=cent2faceloop[dir].js + SHIFT2*(dir==2);
1954  je=cent2faceloop[dir].je;
1955  ks=cent2faceloop[dir].ks + SHIFT3*(dir==3);
1956  ke=cent2faceloop[dir].ke;
1957 
1959  OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
1960 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
1961  OPENMP3DLOOPBLOCK{
1962  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1963 
1964 
1965  // setup which primeface_l and primeface_r to use
1966  // if Nvec[dir]==1, handled specially later
1967  prface_l=MACP1A0(primface_l,dir,i,j,k);
1968  prface_r=MACP1A0(primface_r,dir,i,j,k);
1969 
1970 
1971  // get geometry for face pre-interpolated values
1972 
1973 
1974 #if(STOREFLUXSTATE==0)
1975  get_geometry(i, j, k, FACE1-1+dir, ptrgeomf); // at face[dir]
1976 
1977  // VELs: note don't use velocity in "dir" direction
1978  // LEFTVEL: compute and store v^i at face (input to ucon_calc() is primitive list as correct in primface_l,r)
1979  MYFUN(ucon_calc(prface_l, ptrgeomf, ptrql->ucon, ptrql->others) ,"flux.c:interpolate_face2corn()", "ucon_calc()", 1);
1980  // RIGHTVEL: compute and store v^i at face
1981  MYFUN(ucon_calc(prface_r, ptrgeomf, ptrqr->ucon, ptrqr->others) ,"flux.c:interpolate_face2corn()", "ucon_calc()", 2);
1982 
1983 #else
1984 
1985  // really only need i,j,k in geomf for get_stateforfluxcalc(), unless doing INCLUDEGDETINTRANSVERSEINTERPLATIONOFFIELD!=0
1986  ptrgeomf->i=i;
1987  ptrgeomf->j=j;
1988  ptrgeomf->k=k;
1989  ptrgeomf->p=FACE1-1+dir; // "p" not used by get_stteforfluxcalc(), but ISLEFT/ISRIGHT is w.r.t. just offset from face but located at the position of the face
1990 
1991  get_stateforfluxcalc(dir, ISLEFT, prface_l, ptrgeomf, &ptrql);
1992  get_stateforfluxcalc(dir, ISRIGHT, prface_r, ptrgeomf, &ptrqr);
1993 
1994  // Just always do to avoid complicated conditional
1995  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgdetgeomf); // at face[dir]
1996 
1997 
1998 #endif
1999 
2000 
2001  MACP0A1(p2interp,i,j,k,BFACEINTERPODIR2) = MACP0A1(p2interp,i,j,k,BFACEINTERPODIR1) = prface_l[B1-1+dir]; // note that prface_l[dir]=prface_r[dir] at face[dir]
2002  // p2interp located at face[dir] before interpolation, so gdet should be there
2003  // BFACE: compute and store \detg B^i and prepare for 2-way interpolation of that single field (notice that primface_l,r same for face field
2004  // note that since interpolating \detg B^i, don't have to unrescale because can just use this to obtain EMF w/ gdet
2005  // odir1 and odir2 here refer to possible choices for interpdir, which is always different than [and transverse to] dir.
2007  MACP0A1(p2interp,i,j,k,BFACEINTERPODIR1) *= (ptrgdetgeomf->gdet);
2008  }
2010  MACP0A1(p2interp,i,j,k,BFACEINTERPODIR2) *= (ptrgdetgeomf->gdet);
2011  }
2012 
2013 
2014  // VELs: note don't use velocity in "dir" direction
2015  // GODMARK: Could/Should allow application of rescale on v^i, such as gdet. This would allow (e.g.) SPC to handle uu3 and B3 the same with gdet, so that interpolation doesn't operate on divergent quantity and operates consistently on these so EMF1 is correctly cancels terms.
2016  // LEFTVEL: compute and store v^i at face (input to ucon_calc() is primitive list as correct in primface_l,r)
2017  MACP0A1(p2interp,i,j,k,VLODIR1INTERP) = (ptrql->ucon[odir1])/(ptrql->ucon[TT]);
2018  MACP0A1(p2interp,i,j,k,VLODIR2INTERP) = (ptrql->ucon[odir2])/(ptrql->ucon[TT]);
2019  // RIGHTVEL: compute and store v^i at face
2020  MACP0A1(p2interp,i,j,k,VRODIR1INTERP) = (ptrqr->ucon[odir1])/(ptrqr->ucon[TT]);
2021  MACP0A1(p2interp,i,j,k,VRODIR2INTERP) = (ptrqr->ucon[odir2])/(ptrqr->ucon[TT]);
2022 
2023  // See comments related to switch prior to this whole function
2025  MACP0A1(p2interp,i,j,k,VLODIR1INTERP) *= (ptrgdetgeomf->gdet);
2026  MACP0A1(p2interp,i,j,k,VRODIR1INTERP) *= (ptrgdetgeomf->gdet);
2027  }
2029  MACP0A1(p2interp,i,j,k,VLODIR2INTERP) *= (ptrgdetgeomf->gdet);
2030  MACP0A1(p2interp,i,j,k,VRODIR2INTERP) *= (ptrgdetgeomf->gdet);
2031  }
2032 
2033 
2034 
2035 
2036  }// end COMPZSLOOP
2037 
2038 
2039 
2040 
2041 
2042 
2044  //
2045  // now send relevant terms in p2interp to interpolator for each odir1,odir2 directions
2046  //
2048 
2049 
2050 
2051 
2052 
2053 
2054 
2055 
2056  // MACP4A0(pvcorn,corner/emf/edge dir,i,j,k,which velocity,l/r,u/d)
2057  // note that emf[+- in EMFodir1][+- in EMFodir2] implies pvcorn[l/r][u/d] = pvcorn[l/r in EMFodir1][u/d in EMFodir2] since have matching [l][m] when accessing emf[] and pvcorn[] where in this comment edgedir=dir and odir1 and odir2 are interpdir and dir (order?)
2058  //
2059  // translation:
2060  //
2061  // in EMF calculation function:
2062  // edgedir=1 odir1=2 odir2=3
2063  // edgedir=2 odir1=3 odir2=1
2064  // edgedir=3 odir1=1 odir2=2
2065  //
2066  // in this function for interpdir=odir1 interpolation:
2067  // face dir=1 odir1=interpdir=2 odir2=edgedir=3 EMFodir1=1 EMFodir2=2
2068  // face dir=2 odir1=interpdir=3 odir2=edgedir=1 EMFodir1=2 EMFodir2=3
2069  // face dir=3 odir1=interpdir=1 odir2=edgedir=2 EMFodir1=3 EMFodir2=1
2070  //
2071  //
2072  // Hence, EMFodir1 is facedir and EMFodir2 is interpdir
2073  //
2074  // in this function for interpdir=odir2 interpolation:
2075  // face dir=1 odir2=interpdir=3 odir1=edgedir=2 EMFodir1=3 EMFodir2=1
2076  // face dir=2 odir2=interpdir=1 odir1=edgedir=3 EMFodir1=1 EMFodir2=2
2077  // face dir=3 odir2=interpdir=2 odir1=edgedir=1 EMFodir1=2 EMFodir2=3
2078  //
2079  //
2080  // Hence, EMFodir1 is interpdir and EMFodir2 is facedir
2081  //
2082  // So need to define EMFodir1 and EMFodir2 from edgedir
2083 
2084 
2085 
2087  //
2088  // Loop over other directions not in face-dir
2089  //
2091 
2092  for(whichodir=0;whichodir<=1;whichodir++){
2093 
2094  if(whichodir==0){ // whichodir==0 arbitrarily corresponds to interpdir=odir1
2096  // interpolate in odir1 direction (places quantities at edge/emf/corner odir2)
2097 
2098  npr2interpstart=0;
2099  npr2interpend=2; // 3 things
2100  npr2interplist[0]=BFACEINTERPODIR1; // always interpdir field
2101  BFACEINTERPCURRENT=npr2interplist[0];
2102  // ODIR? should be same as interpdir
2103  npr2interplist[1]=VLODIR1INTERP; // hence [1] is for previous p_l
2104  npr2interplist[2]=VRODIR1INTERP; // hence [2] is for previous p_r
2105 
2106  // face is dir, and interpolation direction and edge direction are orthogonal to that
2107  interpdir=odir1;
2108  edgedir=odir2;
2109 
2110  // del's associated with interpolation direction
2111  idel=idel1;
2112  jdel=jdel1;
2113  kdel=kdel1;
2114  }
2115  else{
2116 
2118  // interpolate in odir2 direction (places quantities at edge/emf/corner odir1)
2119 
2120  npr2interpstart=0;
2121  npr2interpend=2; // 3 things
2122  npr2interplist[0]=BFACEINTERPODIR2; // always interpdir field
2123  BFACEINTERPCURRENT=npr2interplist[0];
2124  // ODIR? should be same as interpdir
2125  npr2interplist[1]=VLODIR2INTERP; // hence [1] is for previous p_l
2126  npr2interplist[2]=VRODIR2INTERP; // hence [2] is for previous p_r
2127 
2128  interpdir=odir2;
2129  edgedir=odir1;
2130 
2131  // del's associated with interpolation direction
2132  idel=idel2;
2133  jdel=jdel2;
2134  kdel=kdel2;
2135  }
2136 
2137 
2138 
2140  //
2141  // set EMFodir's
2142  //
2144  get_odirs(edgedir,&EMFodir1,&EMFodir2);
2145 
2146 
2147 
2149  //
2150  // Setup access to emf-like quantities that have 3-dimensions and going to 2-dimensions
2151  //
2153 
2154  if(EMFodir1==interpdir){
2155  // then first entry should contain 0/1 for *current* interpolation
2156  // then EMFodir1 is interpdir corresponding to direction for current interpolation
2157  // then EMFodir2 is face-dir corresponding to direction for previous interpolation
2158  Aodir1=0; Aodir2=0;
2159  Bodir1=1; Bodir2=0;
2160  Codir1=0; Codir2=1;
2161  Dodir1=1; Dodir2=1;
2162  }
2163  else{
2164  // then first entry should contain 0/1 for *previous* interpolation
2165  // then EMFodir1 is face-dir corresponding to direction for previous interpolation
2166  // then EMFodir2 is interpdir corresponding to direction for current interpolation
2167  Aodir1=0; Aodir2=0;
2168  Bodir1=0; Bodir2=1;
2169  Codir1=1; Codir2=0;
2170  Dodir1=1; Dodir2=1;
2171  }
2172 
2173 
2174 
2175 
2177  // interpolate
2178  //
2179  // GODMARK: Note put primface_l[dir] (yes, face-dir) into slope_lim as a "good primitive" to be used for shock or other indicators -- should really use average of primface_l and primface_r for symmetry considerations -- otherwise not used -- ENOMARK
2180  //
2181  // only really do interpolation if dimension exists ...
2183  // (Nvec[interpdir]>1 && (! (Nvec[edgedir]==1 && Nvec[dir]==1) )) // ... or even if dimension exists but orthogonal dimensions do not then just copy over result -- need to modify more things to do this
2184  // if(Nvec[interpdir]>1){
2185 
2186  // if Nvec[dir]==1, then that face quantity is really a centered quantity in some CORN plane. See below for how assignment is done.
2187 
2188  if(!(Nvec[interpdir]==1 || Nvec[dir]==1&&Nvec[interpdir]!=1 )){
2189  realisinterp=0; // since only ever limited set of quantities
2190  slope_lim_face2corn(realisinterp, interpdir,idel,jdel,kdel,pr,p2interp,dqvec[interpdir],pleft,pright, &(face2cornloop[edgedir][EMFodir1][EMFodir2]));
2191  }
2192 
2193 
2194 
2195 
2196 
2198  // get p_l p_r
2200  //
2201  // interpolate primitive using slope (dq) or directly from pleft and pright
2202  //
2204 
2205  // Assume for now that limiter is not per i,j,k but only per dir (unlike normal interpolation) (also no pl dependence)
2206  // no HORIZONSUPERFAST here
2207  locallim=choose_limiter(interpdir, 0,0,0,B1);
2208  usedq = usedqarray[locallim];
2209 
2210 
2211  // face2corn is at effective-CENT relative to edgedir
2212  // loop below will be at effective-FACEs, so extended in interpdir direction
2213  // One shifts up in interpdir direction because interpolated -1 extra "CENT" cell and N "CENT" cell to get corner at 0 and N.
2214  if(!(Nvec[interpdir]==1|| Nvec[dir]==1&&Nvec[interpdir]!=1 )){
2215  is=face2cornloop[edgedir][EMFodir1][EMFodir2].is + SHIFT1*(interpdir==1);
2216  ie=face2cornloop[edgedir][EMFodir1][EMFodir2].ie;
2217  js=face2cornloop[edgedir][EMFodir1][EMFodir2].js + SHIFT2*(interpdir==2);
2218  je=face2cornloop[edgedir][EMFodir1][EMFodir2].je;
2219  ks=face2cornloop[edgedir][EMFodir1][EMFodir2].ks + SHIFT3*(interpdir==3);
2220  ke=face2cornloop[edgedir][EMFodir1][EMFodir2].ke;
2221  }
2222  else{
2223  // since just copying, revert to locations where interpolated CENT -> FACE
2224  // Note that +SHIFT term just translates pleft/pright type locations to p_l/p_r type locations
2225  is=cent2faceloop[interpdir].is + SHIFT1*(interpdir==1);
2226  ie=cent2faceloop[interpdir].ie;
2227  js=cent2faceloop[interpdir].js + SHIFT2*(interpdir==2);
2228  je=cent2faceloop[interpdir].je;
2229  ks=cent2faceloop[interpdir].ks + SHIFT3*(interpdir==3);
2230  ke=cent2faceloop[interpdir].ke;
2231  // is=-N1BND+idel;
2232  // ie=N1-1+N1BND;
2233  // js=-N2BND+jdel;
2234  // je=N2-1+N2BND;
2235  // ks=-N3BND+kdel;
2236  // ke=N3-1+N3BND;
2237  }
2238 
2239  // dualfprintf(fail_file,"edgedir=%d EMFodir1=%d EMFodir2=%d :: is=%d ie=%d js=%d je=%d ks=%d ke=%d\n",edgedir,EMFodir1,EMFodir2,is,ie,js,je,ks,ke);
2240 
2242  // OPENMP3DLOOPSETUP( -N1BND+idel, N1-1+N1BND, -N2BND+jdel, N2-1+N2BND, -N3BND+kdel, N3-1+N3BND );
2243  OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
2244 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) //nowait // Don't wait since each direction is independent // NO: use of pleft, pright, and some use of p2interp (that depend on each dir) from loop above makes not possible to use "nowait"
2246  OPENMP3DLOOPBLOCK2IJK(i,j,k);
2247 
2248 
2249  // if(Nvec[interpdir]>1 && (! (Nvec[edgedir]==1 && Nvec[dir]==1) ))
2250  // if(Nvec[interpdir]>1){
2251  if(!(Nvec[interpdir]==1|| Nvec[dir]==1&&Nvec[interpdir]!=1 )){
2252 
2253  if(usedq){
2254  PINTERPLOOP(pliter,pl){
2255  // FACE_to_CORN interpolation is same as if doing CENT_to_EDGE from point of view of indicies to use and pleft,pright assignments
2256  p2interp_l[pl] = MACP0A1(p2interp,i - idel,j - jdel,k - kdel,pl) + 0.5 * MACP1A1(dqvec,interpdir,i - idel,j - jdel,k - kdel,pl);
2257  p2interp_r[pl] = MACP0A1(p2interp,i,j,k,pl) - 0.5 * MACP1A1(dqvec,interpdir,i,j,k,pl);
2258  }
2259  }
2260  else{
2261  PINTERPLOOP(pliter,pl){
2262  p2interp_l[pl] = MACP0A1(pright,i-idel,j-jdel,k-kdel,pl);
2263  p2interp_r[pl] = MACP0A1(pleft,i,j,k,pl);
2264  }
2265  }
2266 
2267  }
2268  else if(Nvec[interpdir]==1){
2269 
2270  // if no interpolation, just copy result from pre-interpolated p2interp[] avoiding,bypassing dq,pleft,pright
2271  PINTERPLOOP(pliter,pl){
2272  p2interp_r[pl] = p2interp_l[pl] = MACP0A1(p2interp,i,j,k,pl);
2273  }
2274 
2275 
2276 
2277  }
2278  else if(Nvec[dir]==1&&Nvec[interpdir]!=1){
2279 
2280  // if interpolation already done, just copy over left-right values from cent2face operation
2281  // E.g. If N1==1 and dir==1, then B1,v2 are already interpolated with interpdir==2 to CORN3=FACE2 *and* B1,v3 are already interpolated with interpdir==3 to CORN2=FACE3.
2282  // E.g. If N2==1 and dir==2, then B2,v1 are already interpolated with interpdir==1 to CORN3=FACE1 *and* B2,v3 are already interpolated with interpdir==3 to CORN1=FACE3.
2283  // E.g. If N3==1 and dir==3, then B3,v1 are already interpolated with interpdir==1 to CORN2=FACE1 *and* B3,v2 are already interpolated with interpdir==2 to CORN1=FACE2.
2284  //
2285  // Since face is the corner we want, so same ptrgeomf is good. That is, FACE1-1+dir = desired CORN.
2286  // But needed to change l/r dir from "dir" to "interpdir"
2287 
2288  // Have to compute v^i=u^i/u^t here since didn't know interpdir in earlier part of this whole function
2289  prface_l=MACP1A0(primface_l,interpdir,i,j,k);
2290  prface_r=MACP1A0(primface_r,interpdir,i,j,k);
2291 
2292 
2293  // get geometry for face pre-interpolated values
2294 #if(STOREFLUXSTATE==0)
2295  get_geometry(i, j, k, FACE1-1+dir, ptrgeomf); // at face[dir]=CORN(perp to dir and interpdir)
2296  MYFUN(ucon_calc(prface_l, ptrgeomf, ptrql->ucon, ptrql->others) ,"flux.c:interpolate_face2corn()", "ucon_calc()", 1);
2297  MYFUN(ucon_calc(prface_r, ptrgeomf, ptrqr->ucon, ptrqr->others) ,"flux.c:interpolate_face2corn()", "ucon_calc()", 2);
2298 #else
2299 
2300  ptrgeomf->i=i;
2301  ptrgeomf->j=j;
2302  ptrgeomf->k=k;
2303  ptrgeomf->p=FACE1-1+dir; // "p" not used by get_stateforfluxcalc()
2304 
2305  get_stateforfluxcalc(interpdir, ISLEFT, prface_l, ptrgeomf, &ptrql);
2306  get_stateforfluxcalc(interpdir, ISRIGHT, prface_r, ptrgeomf, &ptrqr);
2307 
2308  // Just always do to avoid complicated conditional
2309  // as when storing, still at original face locations already interpolated/computed during normal flux calculation
2310  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgdetgeomf); // at face[dir]
2311 
2312 
2313 #endif
2314 
2315  // now copy over values
2316  p2interp_l[BFACEINTERPCURRENT] = prface_l[B1-1+dir];
2317  p2interp_r[BFACEINTERPCURRENT] = prface_r[B1-1+dir];
2318  // applying gdet if just copying result so same application of factors as when setting up p2interp[]
2320  p2interp_l[BFACEINTERPCURRENT] *= (ptrgdetgeomf->gdet);
2321  p2interp_r[BFACEINTERPCURRENT] *= (ptrgdetgeomf->gdet);
2322  }
2323 
2324  // [1,2] are from previous (i.e. face) interpolation. But if Nvec[dir=facedir]=1, then those are same values
2325  // as above setup has, always dealing with v^{interpdir}
2326  // here, the l,r indicate across interpdir (not dir as otherwise when requiring interpolation)
2327  p2interp_l[npr2interplist[1]] = p2interp_l[npr2interplist[2]] = (ptrql->ucon[interpdir])/(ptrql->ucon[TT]);
2328  p2interp_r[npr2interplist[1]] = p2interp_r[npr2interplist[2]] = (ptrqr->ucon[interpdir])/(ptrqr->ucon[TT]);
2329  // applying gdet if just copying result so same application of factors as when setting up p2interp[]
2331  p2interp_l[npr2interplist[1]] *= (ptrgdetgeomf->gdet);
2332  p2interp_l[npr2interplist[2]] *= (ptrgdetgeomf->gdet);
2333  p2interp_r[npr2interplist[1]] *= (ptrgdetgeomf->gdet);
2334  p2interp_r[npr2interplist[2]] *= (ptrgdetgeomf->gdet);
2335  }
2336  }
2337  else{
2338  dualfprintf(fail_file,"Shouldn't reach here in fluxctstag.c\n");
2339  myexit(837434873);
2340  }
2341 
2342 
2343 
2345  // DONE with interpolations or copies
2347 
2348 
2349 
2351  //
2352  // Set lab-frame 3-magnetic field at CORN
2353  //
2354  // MACP1A3(pbcorn,corner/emf/edge dir,i,j,k,which field,+-present interpdir)
2355 
2356  int didsetigdet;
2357  didsetigdet=0;
2359  get_geometry_gdetonly(i, j, k, CORN1-1+edgedir, ptrgdetgeomcorn); // at CORN[dir]
2360  // then unrescale field since will multiply geometry once have final EMF (avoids line currents)
2361  set_igdetsimple(ptrgdetgeomcorn);
2362  igdetgnosing = ptrgdetgeomcorn->igdetnosing;
2363  didsetigdet=1;
2364  }
2366  get_geometry_gdetonly(i, j, k, CORN1-1+edgedir, ptrgdetgeomcorn); // at CORN[dir]
2367  // then add gdet now since will not multiply geometry once have final EMF
2368  igdetgnosing = ptrgdetgeomcorn->gdet; // here igdet really is just geom
2369  }
2370  else{
2371  // nothing to do
2372  igdetgnosing = 1.0;
2373  }
2374 
2375 
2376  // MACP3A0(pbcorn,edgedir,B1-1+dir,0,i,j,k) = p2interp_l[npr2interplist[0]]*igdetgnosing;
2377  // MACP3A0(pbcorn,edgedir,B1-1+dir,1,i,j,k) = p2interp_r[npr2interplist[0]]*igdetgnosing;
2378  MACP1A3(pvbcorn,edgedir,i,j,k,dir,NUMCS,0) = p2interp_l[npr2interplist[0]]*igdetgnosing;
2379  MACP1A3(pvbcorn,edgedir,i,j,k,dir,NUMCS,1) = p2interp_r[npr2interplist[0]]*igdetgnosing;
2380 
2381 
2382 
2383 
2385  //
2386  // Set lab-frame 3-velocity at CORN
2387  //
2388  // pvcorn[EMFdir][i][j][k][whichvel][l/r in EMFodir1][u/d in EMFodir2]
2389  //
2390  // for example:
2391  // edgedir=1: EMFodir1=2 EMFodir2=3 then emf[0][0] is emf[left for EMFodir1][left for EMFodir2]
2392  // so if interpolated in 2-dir and EMFodir1==2, then emf[0/1 filled with current p_l and p_r][0/1 filled with previous p_l p_r]
2393 
2394 
2395  // de-applying any gdet factor
2397  if(didsetigdet){
2398  igdetgnosingvel=igdetgnosing;
2399  }
2400  else{
2401  get_geometry_gdetonly(i, j, k, CORN1-1+edgedir, ptrgdetgeomcorn); // at CORN[dir]
2402  set_igdetsimple(ptrgdetgeomcorn);
2403  igdetgnosingvel = ptrgdetgeomcorn->igdetnosing;
2404  }
2405  }
2406  else igdetgnosingvel=1.0;
2407 
2408 
2409  // npr2interplist[1,2] constains [u,d for velocity in interpdir direction]
2410  MACP1A3(pvbcorn,edgedir,i,j,k,interpdir,Aodir1,Aodir2) = p2interp_l[npr2interplist[1]] *= igdetgnosingvel; // current p_l for previous p_l
2411  MACP1A3(pvbcorn,edgedir,i,j,k,interpdir,Bodir1,Bodir2) = p2interp_r[npr2interplist[1]] *= igdetgnosingvel; // current p_r for previous p_l
2412  MACP1A3(pvbcorn,edgedir,i,j,k,interpdir,Codir1,Codir2) = p2interp_l[npr2interplist[2]] *= igdetgnosingvel; // current p_l for previous p_r
2413  MACP1A3(pvbcorn,edgedir,i,j,k,interpdir,Dodir1,Dodir2) = p2interp_r[npr2interplist[2]] *= igdetgnosingvel; // current p_r for previous p_r
2414 
2415 
2416 
2417  }// endCOMPZSLOOP
2418 
2419  }// end loop over (whichodir) other directions // at end of loop, have pbcorn,pvcorn for this 1 face interpolated to 2 corners
2420 
2421 
2422 
2423  }// end DIMENLOOP // at end of loop, have pbcorn,pvcorn for 3 edges
2424 
2425 
2426  }// end over parallel region (and implied barrier)
2427 
2428 
2429 
2431  //
2432  // restore choice for interpolations
2433  //
2435 #pragma omp parallel
2436  { // must set npr2interp stuff inside parallel region since threadprivate
2437  int pl;
2438  npr2interpstart=nprlocalstart;
2439  npr2interpend=nprlocalend;
2440  PMAXNPRLOOP(pl) npr2interplist[pl]=nprlocallist[pl];
2441  }
2442 
2443 
2444 
2445 
2446 
2447 
2448  return(0);
2449 
2450 }
2451 
2452 
2453 
2454 
2455 
2456 
2457 
2458 
2459 
2460 
2461 
2466 //int interpolate_ustag2fieldcent
2467 (int stage, SFTYPE boundtime, int timeorder, int numtimeorders, FTYPE (*preal)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],FTYPE (*upoint)[NSTORE2][NSTORE3][NPR],FTYPE (*pcent)[NSTORE2][NSTORE3][NPR])
2468 {
2469  int i,j,k,pl;
2470  int ii,jj,kk;
2471  struct of_geom geomcdontuse;
2472  struct of_geom *ptrgeomc=&geomcdontuse;
2473  struct of_geom geomfdontuse;
2474  struct of_geom *ptrgeomf=&geomfdontuse;
2475  struct of_geom geomfudontuse;
2476  struct of_geom *ptrgeomfu=&geomfudontuse;
2477  int finalstep;
2478 
2479  // COMPFULLLOOP{
2480 
2481  // must carefully replace pstag only on specific locations
2482 #define MYOCOMPLOOPF3 for(k=SHIFTX3DN;k<=N3-1+SHIFT3+SHIFTX3UP;k++)
2483 #define MYOCOMPLOOPF2 for(j=SHIFTX2DN;j<=N2-1+SHIFT2+SHIFTX2UP;j++)
2484 #define MYOCOMPLOOPF1 for(i=SHIFTX1DN;i<=N1-1+SHIFT1+SHIFTX1UP;i++)
2485 #define MYOCOMPLOOPF MYOCOMPLOOPF3 MYOCOMPLOOPF2 MYOCOMPLOOPF1
2486 
2487  MYOCOMPLOOPF{
2488  PLOOPBONLY(pl){
2489  get_geometry(i, j, k, FACE1+pl-B1, ptrgeomf);
2490 
2491  // first convert staggered upoint to pstag
2492  MACP0A1(pstag,i,j,k,pl)=MACP0A1(upoint,i,j,k,pl)*sign(ptrgeomf->gdet)/(fabs(ptrgeomf->gdet)+SMALL);
2493  // GODMARK: Some problem with gdet not being 0 on axis!! Leads to pstag[B2]=-2E50, but apparently overwritten?
2494  }
2495  }
2496 
2497  // COMPZLOOP{
2498  // dualfprintf(fail_file,"DEATH1: i=%d j=%d k=%d :: %21.15g %21.15g %21.15g\n",i,j,k,MACP0A1(pstag,i,j,k,B1),MACP0A1(pstag,i,j,k,B2),MACP0A1(pstag,i,j,k,B3));
2499  // }
2500 
2501  // bound new pstag
2502  if(timeorder==numtimeorders-1) finalstep=1; else finalstep=0;
2503  bound_pstag(stage, finalstep, boundtime, preal, pstag, upoint, USEMPI);
2504 
2505 
2506  // COMPFULLLOOP{
2507  // dualfprintf(fail_file,"DEATH2: i=%d j=%d k=%d :: %21.15g %21.15g %21.15g\n",i,j,k,MACP0A1(pstag,i,j,k,B1),MACP0A1(pstag,i,j,k,B2),MACP0A1(pstag,i,j,k,B3));
2508  // }
2509 
2510  // now can define everything from pstag
2511  // GODMARK: this defines pcent and upoint on larger domain than normal code, so may mask problem.
2512  // COMPFULLLOOP{
2513 
2514  // correctly similar constrained loop as in normal code:
2515  int is,ie,js,je,ks,ke;
2516  get_inversion_startendindices(Uconsevolveloop,&is,&ie,&js,&je,&ks,&ke);
2517  COMPZSLOOP(is,ie,js,je,ks,ke){
2518 
2519  get_geometry(i, j, k, CENT, ptrgeomc);
2520  PLOOPBONLY(pl){
2521  get_geometry(i, j, k, FACE1+pl-B1, ptrgeomf);
2522  if(pl==B1){
2523  ii=ip1mac(i);
2524  jj=j;
2525  kk=k;
2526  }
2527  else if(pl==B2){
2528  ii=i;
2529  jj=jp1mac(j);
2530  kk=k;
2531  }
2532  else if(pl==B3){
2533  ii=i;
2534  jj=j;
2535  kk=kp1mac(k);
2536  }
2537 
2538  if(ii==i && jj==j && kk==k){
2539  // then just copy
2540  MACP0A1(pcent,i,j,k,pl)=MACP0A1(pstag,i,j,k,pl);
2541  }
2542  else{
2543  // now "interpolate" pstag -> pcent
2544  get_geometry(ii, jj, kk, FACE1+pl-B1, ptrgeomfu);
2545  // below consistent with interpolate_ustag2fieldcent(), but can try different way
2546  MACP0A1(pcent,i,j,k,pl)=0.5*( MACP0A1(pstag,i,j,k,pl)*(ptrgeomf->gdet/ptrgeomc->gdet) + MACP0A1(pstag,ii,jj,kk,pl)*(ptrgeomfu->gdet/ptrgeomc->gdet));
2547  }
2548 
2549  // finally get conserved quantity at CENT for inversion
2550  MACP0A1(upoint,i,j,k,pl)=MACP0A1(pcent,i,j,k,pl)*(ptrgeomc->gdet);
2551  }// end over pl
2552  }// end loop
2553 
2554  return(0);
2555 }