HARM
harm and utilities
 All Data Structures Files Functions Variables Typedefs Macros Pages
fluxct.c
Go to the documentation of this file.
1 
2 #include "decs.h"
3 
8 
12 
36 
37 
39 {
40  int Nvec[NDIM];
41 
42  Nvec[0]=0;
43  Nvec[1]=N1;
44  Nvec[2]=N2;
45  Nvec[3]=N3;
46 
47 
48  /* flux-ct */
49 
50  // A[1] located at CORN1
51  // A[2] located at CORN2
52  // A[3] located at CORN3
53 
54  // F_{\mu\nu} \equiv A_{\nu,\mu} - A_{\mu,\nu}
55 
56  // B^i \equiv \dF^{it}
57 
58  // F_{ij} = \detg B^k [ijk]
59 
60  // F_{\theta\phi} = \detg B^r
61 
62  // F_{\phi r} = \detg B^\theta
63 
64  // F_{r\theta} = \detg B^\phi
65 
66 
67  // \detg B^x = A_{z,y} - A_{y,z}
68  // \detg B^y = A_{x,z} - A_{z,x}
69  // \detg B^z = A_{y,x} - A_{x,y}
70 
71  // loop optimized for filling cells rather than for speed
72 
73 
74  // can do full loop since A[1,2,3] are defined even on their plus parts (redundant but simpler than messing with B's post-hoc by linear extrapolation or something)
75  // puts burden on computing A[1,2,3] (such as having radius or anything at plus part)
76  // this burden is easier since coord() and bl_coord() have no limits on the i,j,k they are given.
77  // so in principle one can give an analytic expression
78  // however, depends on metric and such things if converting expression from one basis to another.
79  // however, this way is more correct than post-hoc extrapolation.
80  // only an issue for fixed boundary conditions, where one could just specify the flux directly.
81  // ufield explicitly needed for FV method
82 
83 
84  // 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)
85 #pragma omp parallel
86  {
87  int i,j,k;
88  struct of_geom geomdontuse;
89  struct of_geom *ptrgeom=&geomdontuse;
90  FTYPE igdetgnosing;
91  int dir;
92  int odir1,odir2;
93  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUPFULL; // doesn't depend upon dir, but blockijk must be private, so put in parallel loop
94 
95 
96  // generally ptr's are different inside parallel block
97  ptrgeom=&geomdontuse;
98 
99 
101  //
102  // B^1
103  //
105 
106  dir=1;
107  get_odirs(dir,&odir1,&odir2);
108  if(!(Nvec[odir1]==1 && Nvec[odir2]==1)){
110 
111 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE()) nowait // nowait valid because each next loop writes to independent memory regions (or to local temporary variables like igdetgnosing that is overwritten for each iteration and so doesn't matter). And also don't require result of one loop for next loop (this is often not true!)
113  OPENMP3DLOOPBLOCK2IJK(i,j,k);
114 
115  // ufield doesn't require geometry
116  MACP0A1(ufield,i,j,k,B1) = +(AVGCORN_1(A[3],i,jp1mac(j),k)-AVGCORN_1(A[3],i,j,k))/(dx[2]);
117  MACP0A1(ufield,i,j,k,B1) += -(AVGCORN_1(A[2],i,j,kp1mac(k))-AVGCORN_1(A[2],i,j,k))/(dx[3]);
118 
119  get_geometry(i, j, k, CENT, ptrgeom);
120  igdetgnosing = sign(ptrgeom->gdet)/(fabs(ptrgeom->gdet)+SMALL); // avoids 0.0 for any sign of ptrgeom->gdet
121  MACP0A1(pfield,i,j,k,B1-1+dir) = MACP0A1(ufield,i,j,k,B1-1+dir)*igdetgnosing;
122  }
123  }// end if doing this dir
124 
125 
127  //
128  // B^2
129  //
131 
132  dir=2;
133  get_odirs(dir,&odir1,&odir2);
134  if(!(Nvec[odir1]==1 && Nvec[odir2]==1)){
136 
137 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE()) nowait
139  OPENMP3DLOOPBLOCK2IJK(i,j,k);
140 
141  MACP0A1(ufield,i,j,k,B2) = +(AVGCORN_2(A[1],i,j,kp1mac(k))-AVGCORN_2(A[1],i,j,k))/(dx[3]);
142  MACP0A1(ufield,i,j,k,B2) += -(AVGCORN_2(A[3],ip1mac(i),j,k)-AVGCORN_2(A[3],i,j,k))/(dx[1]);
143 
144  get_geometry(i, j, k, CENT, ptrgeom);
145  igdetgnosing = sign(ptrgeom->gdet)/(fabs(ptrgeom->gdet)+SMALL); // avoids 0.0 for any sign of ptrgeom->gdet
146  MACP0A1(pfield,i,j,k,B1-1+dir) = MACP0A1(ufield,i,j,k,B1-1+dir)*igdetgnosing;
147  }
148  } // end if dir
149 
150 
152  //
153  // B^3
154  //
156 
157  dir=3;
158  get_odirs(dir,&odir1,&odir2);
159  if(!(Nvec[odir1]==1 && Nvec[odir2]==1)){
161 
162 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE()) nowait
164  OPENMP3DLOOPBLOCK2IJK(i,j,k);
165 
166  MACP0A1(ufield,i,j,k,B3) = +(AVGCORN_3(A[2],ip1mac(i),j,k)-AVGCORN_3(A[2],i,j,k))/(dx[1]);
167  MACP0A1(ufield,i,j,k,B3) += -(AVGCORN_3(A[1],i,jp1mac(j),k)-AVGCORN_3(A[1],i,j,k))/(dx[2]);
168 
169  get_geometry(i, j, k, CENT, ptrgeom);
170  igdetgnosing = sign(ptrgeom->gdet)/(fabs(ptrgeom->gdet)+SMALL); // avoids 0.0 for any sign of ptrgeom->gdet
171  MACP0A1(pfield,i,j,k,B1-1+dir) = MACP0A1(ufield,i,j,k,B1-1+dir)*igdetgnosing;
172  }
173  }// end if dir
174 
175  }// end full parallel region (with implied barrier)
176 
177 
178 
179 
180 
181 
182 
183  return(0);
184 }
185 
186 
187 
188 
189 
191 int flux_ct(int stage,
192  int initialstep, int finalstep,
193  FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*emf)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3], FTYPE (*vconemf)[NSTORE2][NSTORE3][NDIM-1], FTYPE (*dq1)[NSTORE2][NSTORE3][NPR], FTYPE (*dq2)[NSTORE2][NSTORE3][NPR], FTYPE (*dq3)[NSTORE2][NSTORE3][NPR], FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*vpot)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3], int *Nvec, FTYPE *CUf, FTYPE *CUnew, SFTYPE fluxdt, SFTYPE fluxtime)
194 {
195  int flux_ct_computeemf(int stage, FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*emf)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3], FTYPE (*vconemf)[NSTORE2][NSTORE3][NDIM-1], FTYPE (*dq1)[NSTORE2][NSTORE3][NPR], FTYPE (*dq2)[NSTORE2][NSTORE3][NPR], FTYPE (*dq3)[NSTORE2][NSTORE3][NPR], FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL]);
196  int flux_ct_diffusivecorrections(int stage, FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*emf)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3], FTYPE (*vconemf)[NSTORE2][NSTORE3][NDIM-1], FTYPE (*dq1)[NSTORE2][NSTORE3][NPR], FTYPE (*dq2)[NSTORE2][NSTORE3][NPR], FTYPE (*dq3)[NSTORE2][NSTORE3][NPR], FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL]);
197  int flux_ct_emf2flux(int stage, FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*emf)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3], FTYPE (*vconemf)[NSTORE2][NSTORE3][NDIM-1], FTYPE (*dq1)[NSTORE2][NSTORE3][NPR], FTYPE (*dq2)[NSTORE2][NSTORE3][NPR], FTYPE (*dq3)[NSTORE2][NSTORE3][NPR], FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL]);
198 
199 
200 
201 
202 
203 
204  MYFUN(flux_ct_computeemf(stage, pb, emf, vconemf, dq1, dq2, dq3, F1, F2, F3),"step_ch.c:advance()", "flux_ct",1);
205 
206  MYFUN(flux_ct_diffusivecorrections(stage, pb, emf, vconemf, dq1, dq2, dq3, F1, F2, F3),"step_ch.c:advance()", "flux_ct",1);
207 
208 
209  if(EVOLVEWITHVPOT>0 || TRACKVPOT>0){
210  // Evolve A_i
211  // Had to be here where EMFs are at standard CORN1,2,3 positions and before final F assigned
212  // TOTH CT method doesn't cleanly differentiate between point update and average update of A_i, so just stick to TOTH CT EMF itself
213  evolve_vpotgeneral(FLUXB, stage, initialstep, finalstep, pb, Nvec, NULL, emf, CUf, CUnew, fluxdt, fluxtime, vpot);
214  }
215 
216  int fluxvpot_modifyemfsuser=0;
217  fluxvpot_modifyemfsuser=(EVOLVEWITHVPOT>0 || TRACKVPOT>0)&&(MODIFYEMFORVPOT==MODIFYEMF || MODIFYEMFORVPOT==MODIFYVPOT);
218 
219  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
220  // User "boundary conditions" to modify EMFs before used to get fluxes
221  adjust_fluxcttoth_emfs(fluxtime,pb,emf);
222  }
223 
225  //
226  // must come last for FLUXCTTOTH to produce correct fluxes from point corner EMFs
227  //
229  MYFUN(flux_ct_emf2flux(stage, pb, emf, vconemf, dq1, dq2, dq3, F1, F2, F3),"step_ch.c:advance()", "flux_ct",1);
230 
231 
232 
233  return(0);
234 }
235 
236 
237 
238 
239 
240 
243 int flux_ct_computeemf(int stage, FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*emf)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3], FTYPE (*vconemf)[NSTORE2][NSTORE3][NDIM-1], FTYPE (*dq1)[NSTORE2][NSTORE3][NPR], FTYPE (*dq2)[NSTORE2][NSTORE3][NPR], FTYPE (*dq3)[NSTORE2][NSTORE3][NPR], FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL])
244 {
245  // full-type geometry below
246  FTYPE coefemf[NDIM];
247  extern int choose_limiter(int dir, int i, int j, int k, int pl);
248 
249 
250  // Note that Toth method needs off-direction flux beyond where normal-flux needed. For example, for dir=1 setting F1(i) needs F23[i-1],F23[i]. So fluxloop needs to define F2/F3 as if cell centered quantity.
251  // Also, if modify flux[B1,B2,B3] after set by flux calculation, then that information can propagate from outer boundaries to active region
252  // When FLUXCTTOTH method used, must not modify fluxes within ghost region (say setting F1[B2]=-F2[B1]) since info will move to active region
253  // e.g. if put NaN in EMF3 at very outer edge, then reaches active domain by this method
254 
255 
256 
257 
258  if(FLUXB==FLUXCTHLL){
259  dualfprintf(fail_file,"Makes no sense to call flux_ct with FLUXB==FLUXCTHLL\n");
260  myexit(9176325);
261  }
262 
263 
264 
265 
267  //
268  // COMPUTE PRE-FUNCTIONS used by Athena method
269  //
271  if((FLUXB==ATHENA1)||(FLUXB==ATHENA2)){
272  // compute v^i
273 
274  // loop must go over COMPEMFZLOOP's range minus 1 for i and j and k
275  // COMPPREEMFZLOOP{
276  // COMPFULLLOOP{ // GODMARK: could try to be more constrained
277  // use ucon_calc() to get v^i
278 #pragma omp parallel
279  {
280  int i, j, k, l;
281  struct of_geom geomcfulldontuse;
282  struct of_geom *ptrgeomcfull=&geomcfulldontuse;
283  FTYPE ucon[NDIM];
284  FTYPE others[NUMOTHERSTATERESULTS];
285 
287 
288 
289 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE())
291  OPENMP3DLOOPBLOCK2IJK(i,j,k);
292 
293 
294  // EMF below is based upon averaging of zone-centered quantities, so use CENT here (i.e. not CORN)
295  get_geometry(i, j, k, CENT, ptrgeomcfull);
296  MYFUN(ucon_calc(MAC(pb,i,j,k), ptrgeomcfull, ucon, others),"fluxct.c:flux_ct()", "ucon_calc() dir=0", 1);
297 
298 
299  // ptrgeom->gdet is \detg for EMF flux (ptrgeom->e is EOM factor for flux equation)
300 #if(CORNGDETVERSION)
301  for(l=U1;l<=U3;l++) MACP0A1(vconemf,i,j,k,l)=(ucon[l-U1+1]/ucon[TT]); // put in at end
302 #else
303  for(l=U1;l<=U3;l++) MACP0A1(vconemf,i,j,k,l)=(ucon[l-U1+1]/ucon[TT])*(ptrgeomcfull->EOMFUNCMAC(l));
304 #endif
305  }// end 3D LOOP
306  }// end parallel region
307  }// end if ATHENA1||ATHENA2
308 
309 
310 
311 
312 
313 
314 
315 
316 
317 
318 #if(CORNGDETVERSION)
319 
320  if((FLUXB==ATHENA1)||(FLUXB==ATHENA2)||(FLUXB==FLUXCTTOTH)||(FLUXB==FLUXCD)){
321 
323  //
324  // strip off geometry factor, which is added when computing the EMF
325  //
327  // COMPFULLLOOP{ // GODMARK: could try to be more constrained
328 #pragma omp parallel
329  {
330  int i,j,k;
331  // gdet-type geometry below
332  struct of_gdetgeom geomf1dontuse,geomf2dontuse,geomf3dontuse;
333  struct of_gdetgeom *ptrgeomf1=&geomf1dontuse,*ptrgeomf2=&geomf2dontuse,*ptrgeomf3=&geomf3dontuse;
334 
336 
337 
338 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE())
340  OPENMP3DLOOPBLOCK2IJK(i,j,k);
341 
342 
344  // F1
346 #if(N1>1)
347  get_geometry_gdetmix(i,j,k,FACE1,ptrgeomf1);
348  MACP0A1(F1,i,j,k,B1)*=(ptrgeomf1->IEOMFUNCNOSINGMAC(B1));
349  MACP0A1(F1,i,j,k,B2)*=(ptrgeomf1->IEOMFUNCNOSINGMAC(B2));
350  MACP0A1(F1,i,j,k,B3)*=(ptrgeomf1->IEOMFUNCNOSINGMAC(B3));
351 #endif
352 
354  // F2
356 #if(N2>1)
357  get_geometry_gdetmix(i,j,k,FACE2,ptrgeomf2);
358  MACP0A1(F2,i,j,k,B1)*=(ptrgeomf2->IEOMFUNCNOSINGMAC(B1));
359  MACP0A1(F2,i,j,k,B2)*=(ptrgeomf2->IEOMFUNCNOSINGMAC(B2));
360  MACP0A1(F2,i,j,k,B3)*=(ptrgeomf2->IEOMFUNCNOSINGMAC(B3));
361 #endif
362 
364  // F3
366 #if(N3>1)
367  get_geometry_gdetmix(i,j,k,FACE3,ptrgeomf3);
368  MACP0A1(F3,i,j,k,B1)*=(ptrgeomf3->IEOMFUNCNOSINGMAC(B1));
369  MACP0A1(F3,i,j,k,B2)*=(ptrgeomf3->IEOMFUNCNOSINGMAC(B2));
370  MACP0A1(F3,i,j,k,B3)*=(ptrgeomf3->IEOMFUNCNOSINGMAC(B3));
371 #endif
372  }// end 3D loop
373  }// end parallel region
374 
375  // don't need to put back geometry factor since in the end the EMF defines the Flux completely (except for FLUXB==FLUXCTHLL)
376  }// end if ATHENA1||ATHENA2||FLUXCTTOTH||FLUXCD
377 #endif // end if CORNGDETVERSION
378 
379 
380 
381 
382 
383 
384  // GODMARK: strange one has to do this. Related to FLUXCT not reducing correctly for plane-parallel grid-aligned flows?
385  if((N2>1)&&(N3>1)) coefemf[1]=0.25;
386  else coefemf[1]=0.5; // or 0 if neither as controlled by below
387  if((N1>1)&&(N3>1)) coefemf[2]=0.25;
388  else coefemf[2]=0.5; // or 0 if neither as controlled by below
389  if((N1>1)&&(N2>1)) coefemf[3]=0.25;
390  else coefemf[3]=0.5; // or 0 if neither as controlled by below
391 
392 
393 
394 
395 
397  //
398  // COMPUTE EMF
399  //
401 
402  if((FLUXB==FLUXCTTOTH)||(FLUXB==ATHENA1)||(FLUXB==ATHENA2)){
403  /* calculate EMFs */
404  /* Toth approach: just average */
405 
406 
407  // emf_i centered on corner of plane with normal direction i
408 
409  // Note, do need F1[-N1BND] but don't need F2[-N2BND] or F3[-N3BND] in averaging process, which makes normally need to be complicated.
410  // Note: As discussed in superdefs.h, superdefs.pointers.h, and set_arrays_multidimen.c, F1,F2,F3,F1EM,F2EM,F3EM pointers are normal arrays, but their BASE arrays have extra memory at *bottom* so can access F[-NBND-1] without segfaulting. Resulting data not used, but makes loops simpler.
411 
412 
413 #pragma omp parallel // globalprivate stuff needed for final CORNGDET setting if doing that method
414  {
415  int i,j,k;
416  // gdet-type geometry below
417  struct of_gdetgeom geomf1dontuse,geomf2dontuse,geomf3dontuse;
418  struct of_gdetgeom *ptrgeomf1=&geomf1dontuse,*ptrgeomf2=&geomf2dontuse,*ptrgeomf3=&geomf3dontuse;
420 
421 
422  // // COMPLOOPINFP1dir1full
423  // OPENMP3DLOOPSETUP(-N1BND,N1-1+N1BND,INFULLP12,OUTFULL2,INFULLP13,OUTFULL3);
427  // OPENMP3DLOOPSETUP(INFULLP11,OUTFULL1,INFULLP12,OUTFULL2,-N3BND,N3-1+N3BND);
428 
430 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE())
431  OPENMP3DLOOPBLOCK{
432  OPENMP3DLOOPBLOCK2IJK(i,j,k);
433 
434 
436  // EMF1
438 #if((N2>1)||(N3>1))
439  MACP1A0(emf,1,i,j,k) =
440  coefemf[1] * (
441 #if(N2>1)
442  + MACP0A1(F2,i,j,k,B3) + MACP0A1(F2,i,j,km1mac(k),B3)
443 #endif
444 #if(N3>1)
445  - MACP0A1(F3,i,j,k,B2) - MACP0A1(F3,i,jm1mac(j),k,B2)
446 #endif
447  );
448 #else // end if doing EMF1
449  MACP1A0(emf,1,i,j,k)=0.0; // not really 0, but differences in emf will be 0, and that's all that matters
450 #endif // end if not doing EMF1
451 
452 #if(CORNGDETVERSION)// then tack on geometry
453  get_geometry_gdetmix(i,j,k,CORN1,ptrgeomf1);
454  // obviously ptrgeom->EOMFUNCMAC(B2) has to be equal to ptrgeom->EOMFUNCMAC(B3) for this method
455  MACP1A0(emf,1,i,j,k) *= (ptrgeomf1->EOMFUNCMAC(B2));
456 #endif // end if CORNGDETVERSION
457 
458 
459 
461  // EMF2
463 #if((N1>1)||(N3>1))
464  MACP1A0(emf,2,i,j,k) =
465  coefemf[2] * (
466 #if(N3>1)
467  + MACP0A1(F3,i,j,k,B1) + MACP0A1(F3,im1mac(i),j,k,B1)
468 #endif
469 #if(N1>1)
470  - MACP0A1(F1,i,j,k,B3) - MACP0A1(F1,i,j,km1mac(k),B3)
471 #endif
472  );
473 #else // end if doing EMF2
474  MACP1A0(emf,2,i,j,k)=0.0; // not really 0, but differences in emf will be 0, and that's all that matters
475 #endif // end if not doing EMF2
476 
477 #if(CORNGDETVERSION)// then tack on geometry
478  get_geometry_gdetmix(i,j,k,CORN2,ptrgeomf2);
479  // obviously ptrgeom->EOMFUNCMAC(B1) has to be equal to ptrgeom->EOMFUNCMAC(B2) for this method
480  MACP1A0(emf,2,i,j,k) *=(ptrgeomf2->EOMFUNCMAC(B1));
481 #endif // end if CORNGDETVERSION
482 
483 
484 
485 
487  // EMF3
489 #if((N1>1)||(N2>1))
490  MACP1A0(emf,3,i,j,k) =
491  coefemf[3] * (
492 #if(N1>1)
493  + MACP0A1(F1,i,j,k,B2) + MACP0A1(F1,i,jm1mac(j),k,B2)
494 #endif
495 #if(N2>1)
496  - MACP0A1(F2,i,j,k,B1) - MACP0A1(F2,im1mac(i),j,k,B1)
497 #endif
498  );
499 #else // end if doing EMF3
500  MACP1A0(emf,3,i,j,k)=0.0; // not really 0, but differences in emf will be 0, and that's all that matters
501 #endif // end if not doing EMF3
502 
503 #if(CORNGDETVERSION)// then tack on geometry
504  get_geometry_gdetmix(i,j,k,CORN3,ptrgeomf3);
505  // obviously ptrgeom->EOMFUNCMAC(B1) has to be equal to ptrgeom->EOMFUNCMAC(B2) for this method
506  MACP1A0(emf,3,i,j,k) *=(ptrgeomf3->EOMFUNCMAC(B1));
507 #endif // end if CORNGDETVERSION
508 
509  }// end 3D LOOP
510  }// end parallel region (and implied barrier)
511 
512 
513 
514 
515 
516 
517 
518 
519 
520  }// end if FLUXCT TOTH
521  else if(FLUXB==FLUXCD){
522 
523 
524 
525 
526  // Centered Difference (CD)
527  // here emf is actually electric field
528  // in Toth 2000, the F1=f^x F2=f^y
529  // see Toth 2000 equation 28/29
530  // 0.125 here takes care of larger differencing used in advance() in advance.c
531  // all emf's end up at CENT
532  // COMPEMFZLOOP{
533  // COMPLOOPOUTFM1{ // constrain or control better? GODMARK
534 
535 
536 
537  // GODMARK: Why did Charles change sign in front of F's (see old code) ? He changed it as if real sign such that emf[i] = \detg E_i but then later flux was wrong sign since he set flux=emf
538 
539  // GODMARK: should just compute F with diffusive term at CENT directly instead of averaging flux
540 
541 #pragma omp parallel // globalprivate stuff needed for final CORNGDET setting if doing that method
542  {
543  int i,j,k;
544  struct of_gdetgeom geomcdontuse;
545  struct of_gdetgeom *ptrgeomc=&geomcdontuse;
547 
548 
550  //OPENMP3DLOOPSETUP(-N1BND,N1-1+N1BND,INFULL2,OUTFULLM12,INFULL3,OUTFULLM13);
555 
557 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE())
558  OPENMP3DLOOPBLOCK{
559  OPENMP3DLOOPBLOCK2IJK(i,j,k);
560 
561 
563  // EMF1
565 #if((N2>1)||(N3>1))
566  MACP1A0(emf,1,i,j,k) =
567  0.125 * (
568  + MACP0A1(F2,i,j,k,B3) + MACP0A1(F2,i,jp1mac(j),k,B3)
569  - MACP0A1(F3,i,j,k,B2) - MACP0A1(F3,i,j,kp1mac(k),B2)
570  );
571 
572 #if(CORNGDETVERSION)// then tack on geometry
573  get_geometry_gdetmix(i,j,k,CENT,ptrgeomc);
574  // obviously ptrgeom->EOMFUNCMAC(B2) has to be equal to ptrgeom->EOMFUNCMAC(B3) for this method
575  MACP1A0(emf,1,i,j,k) *=(ptrgeomc->EOMFUNCMAC(B2));
576 #endif // end if CORNGDETVERSION
577 
578 #endif // end if doing EMF1
579 
580 
581 
583  // EMF2
585 #if((N1>1)||(N3>1))
586 
587  MACP1A0(emf,2,i,j,k) =
588  0.125 * (
589  + MACP0A1(F3,i,j,k,B1) + MACP0A1(F3,i,j,kp1mac(k),B1)
590  - MACP0A1(F1,i,j,k,B3) - MACP0A1(F1,ip1mac(i),j,k,B3)
591  );
592 
593 #if(CORNGDETVERSION)// then tack on geometry
594  get_geometry_gdetmix(i,j,k,CENT,ptrgeomc);
595  // obviously ptrgeom->EOMFUNCMAC(B1) has to be equal to ptrgeom->EOMFUNCMAC(B2) for this method
596  MACP1A0(emf,2,i,j,k) *=(ptrgeomc->EOMFUNCMAC(B1));
597 #endif // end if CORNGDETVERSION
598 
599 #endif // end if doing EMF2
600 
601 
602 
604  // EMF3
606 #if((N1>1)||(N2>1))
607  MACP1A0(emf,3,i,j,k) =
608  0.125 * (
609  + MACP0A1(F1,i,j,k,B2) + MACP0A1(F1,ip1mac(i),j,k,B2)
610  - MACP0A1(F2,i,j,k,B1) - MACP0A1(F2,i,jp1mac(j),k,B1)
611  );
612 
613 #if(CORNGDETVERSION)// then tack on geometry
614  get_geometry_gdetmix(i,j,k,CENT,ptrgeomc);
615  // obviously ptrgeom->EOMFUNCMAC(B1) has to be equal to ptrgeom->EOMFUNCMAC(B2) for this method
616  MACP1A0(emf,3,i,j,k) *=(ptrgeomc->EOMFUNCMAC(B1));
617 #endif // end if CORNGDETVERSION
618 
619 #endif // end if doing EMF3
620 
621  }// end 3D LOOP
622 
623  }// end parallel region (and implied barrier)
624 
625 
626 
627 
628  }// end if FLUXCD
629 
630 
631 
632  return(0);
633 }
634 
635 
636 
637 
638 
639 
640 
641 
642 
643 
644 
645 
646 
647 
648 
649 
650 
653 int flux_ct_diffusivecorrections(int stage, FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*emf)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3], FTYPE (*vconemf)[NSTORE2][NSTORE3][NDIM-1], FTYPE (*dq1)[NSTORE2][NSTORE3][NPR], FTYPE (*dq2)[NSTORE2][NSTORE3][NPR], FTYPE (*dq3)[NSTORE2][NSTORE3][NPR], FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL])
654 {
655  // full-type geometry below
656  FTYPE coefemf[NDIM];
657  extern int choose_limiter(int dir, int i, int j, int k, int pl);
658 
659 
660 
661 
662 
663 
664 
666  //
667  // ADD DIFFUSIVE CORRECTIONS
668  //
670 
671 
672 
673 
674  // add diffusive term
675  // must come after FLUXCT
676  if((FLUXB==ATHENA1)||(FLUXB==ATHENA2)){
677 
678  // Stone & Gardiner point out that Toth FLUXCT and FLUXCD not consistent with underlying integration algorithm for plane-parallel, grid-aligned flows.
679  // fix is to change 0.25 to 0.5 and use a diffusive term as in ATHENA1
680 
681  /* Stone & Gardiner eq. 39 */
682  // Charles Gammie (8/17/05) says this is simple, but repairs HARM defect that 2D does not reduce to 1D when waves are along coordinate lines
683 
684 
686  // COMPEMFZLOOP{
687 #pragma omp parallel
688  {
689  int i,j,k,l;
690  // gdet-type geometry below
691  struct of_gdetgeom geomf1dontuse,geomf2dontuse,geomf3dontuse;
692  struct of_gdetgeom *ptrgeomf1=&geomf1dontuse,*ptrgeomf2=&geomf2dontuse,*ptrgeomf3=&geomf3dontuse;
693  FTYPE diffusiveterm[NDIM];
694  FTYPE emfmm[NDIM],emfpm[NDIM],emfmp[NDIM],emfpp[NDIM],alpha[NDIM] ;
695 
696 
698 
699  // generally ptr's are different inside parallel block
700  ptrgeomf1=&geomf1dontuse;
701  ptrgeomf2=&geomf2dontuse;
702  ptrgeomf3=&geomf3dontuse;
703 
704 
705 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE())
707  OPENMP3DLOOPBLOCK2IJK(i,j,k);
708 
709  // {emf}_i=-\epsilon_{ijk} v^i B^k
710 
711 
712  // average of the below results in averaged emf located at corner (CORN)
713  // same sign as F's (B^2 v^1 - B^1 v^2) with gdet built into vconemf
714 
715  // could remove gdet from vconemf and F1/F2 and put gdet at CORN for final result! Avoids axis problems?
716  // applies to above Toth version as well!
717  // GODMARK
718 
719 #if((N2>1)||(N3>1))
720  // emf_1
721  emfmp[1] =
722  MACP0A1(pb,i ,jm1mac(j),k ,B3)*MACP0A1(vconemf,i ,jm1mac(j),k ,U2) -
723  MACP0A1(pb,i ,jm1mac(j),k ,B2)*MACP0A1(vconemf,i ,jm1mac(j),k ,U3) ;
724  emfmm[1] =
725  MACP0A1(pb,i ,jm1mac(j),km1mac(k),B3)*MACP0A1(vconemf,i ,jm1mac(j),km1mac(k),U2) -
726  MACP0A1(pb,i ,jm1mac(j),km1mac(k),B2)*MACP0A1(vconemf,i ,jm1mac(j),km1mac(k),U3) ;
727  emfpm[1] =
728  MACP0A1(pb,i ,j ,km1mac(k),B3)*MACP0A1(vconemf,i ,j ,km1mac(k),U2) -
729  MACP0A1(pb,i ,j ,km1mac(k),B2)*MACP0A1(vconemf,i ,j ,km1mac(k),U3) ;
730  emfpp[1] =
731  MACP0A1(pb,i ,j ,k ,B3)*MACP0A1(vconemf,i ,j ,k ,U2) -
732  MACP0A1(pb,i ,j ,k ,B2)*MACP0A1(vconemf,i ,j ,k ,U3) ;
733 #endif
734 
735 #if((N1>1)||(N3>1))
736  // emf_2
737  emfmp[2] =
738  MACP0A1(pb,im1mac(i),j ,k ,B1)*MACP0A1(vconemf,im1mac(i),j ,k ,U3) -
739  MACP0A1(pb,im1mac(i),j ,k ,B3)*MACP0A1(vconemf,im1mac(i),j ,k ,U1) ;
740  emfmm[2] =
741  MACP0A1(pb,im1mac(i),j ,km1mac(k),B1)*MACP0A1(vconemf,im1mac(i),j ,km1mac(k),U3) -
742  MACP0A1(pb,im1mac(i),j ,km1mac(k),B3)*MACP0A1(vconemf,im1mac(i),j ,km1mac(k),U1) ;
743  emfpm[2] =
744  MACP0A1(pb,i ,j ,km1mac(k),B1)*MACP0A1(vconemf,i ,j ,km1mac(k),U3) -
745  MACP0A1(pb,i ,j ,km1mac(k),B3)*MACP0A1(vconemf,i ,j ,km1mac(k),U1) ;
746  emfpp[2] =
747  MACP0A1(pb,i ,j ,k ,B1)*MACP0A1(vconemf,i ,j ,k ,U3) -
748  MACP0A1(pb,i ,j ,k ,B3)*MACP0A1(vconemf,i ,j ,k ,U1) ;
749 #endif
750 
751 #if((N1>1)||(N2>1))
752  // emf_3 (same sign as FLUXCT method as emf[3])
753  emfmp[3] =
754  MACP0A1(pb,im1mac(i),j ,k ,B2)*MACP0A1(vconemf,im1mac(i),j ,k ,U1) -
755  MACP0A1(pb,im1mac(i),j ,k ,B1)*MACP0A1(vconemf,im1mac(i),j ,k ,U2) ;
756  emfmm[3] =
757  MACP0A1(pb,im1mac(i),jm1mac(j),k ,B2)*MACP0A1(vconemf,im1mac(i),jm1mac(j),k ,U1) -
758  MACP0A1(pb,im1mac(i),jm1mac(j),k ,B1)*MACP0A1(vconemf,im1mac(i),jm1mac(j),k ,U2) ;
759  emfpm[3] =
760  MACP0A1(pb,i ,jm1mac(j),k ,B2)*MACP0A1(vconemf,i ,jm1mac(j),k ,U1) -
761  MACP0A1(pb,i ,jm1mac(j),k ,B1)*MACP0A1(vconemf,i ,jm1mac(j),k ,U2) ;
762  emfpp[3] =
763  MACP0A1(pb,i ,j ,k ,B2)*MACP0A1(vconemf,i ,j ,k ,U1) -
764  MACP0A1(pb,i ,j ,k ,B1)*MACP0A1(vconemf,i ,j ,k ,U2) ;
765 #endif
766 
767  for(l=1;l<=3;l++){
768  diffusiveterm[l]= 0.25*(emfmp[l] + emfmm[l] + emfpm[l] + emfpp[l]);
769  }
770 
771 #if(CORNGDETVERSION)// then tack on geometry
772 
773  get_geometry_gdetmix(i,j,k,CORN1,ptrgeomf1);
774  get_geometry_gdetmix(i,j,k,CORN2,ptrgeomf2);
775  get_geometry_gdetmix(i,j,k,CORN3,ptrgeomf3);
776 
777  // obviously ptrgeom->EOMFUNCMAC(B2) has to be equal to ptrgeom->EOMFUNCMAC(B3) for this method
778  diffusiveterm[1] *=(ptrgeomf1->EOMFUNCMAC(B2));
779  // obviously ptrgeom->EOMFUNCMAC(B1) has to be equal to ptrgeom->EOMFUNCMAC(B2) for this method
780  diffusiveterm[2] *=(ptrgeomf2->EOMFUNCMAC(B1));
781  // obviously ptrgeom->EOMFUNCMAC(B1) has to be equal to ptrgeom->EOMFUNCMAC(B2) for this method
782  diffusiveterm[3] *=(ptrgeomf3->EOMFUNCMAC(B1));
783 #endif
784 
785  // now add diffusive term to emf
786  // notice original emf multiplied by 2 to account for diffusive term being subtracted, so result is consistent
787  for(l=1;l<=3;l++){
788  MACP1A0(emf,l,i,j,k) = 2.0*MACP1A0(emf,l,i,j,k) - diffusiveterm[l];
789  }
790 
791 
792  }// end COMPEMFZLOOP
793  }// end parallel region
794 
795  }// end ATHENA1
796 
797 
798 
799 
800 
801 
802 
803 
804 
805 
806  // add another diffusive flux correction
807  // must come after ATHENA1
808  if(FLUXB==ATHENA2){
809 
810 
811 
812  if(LIMADJUST>0 || DODQMEMORY==0 || choose_limiter(1, 0,0,0,RHO)>=PARA || choose_limiter(2, 0,0,0,RHO)>=PARA || choose_limiter(3, 0,0,0,RHO)>=PARA){ // note only look at one point and one variable here for test
813  dualfprintf(fail_file,"Cannot use Athena2 with limadjust since dq's not defined\n");
814  myexit(11);
815  }
816 
817  // GODMARK
818  // should just use unrescaled p2interp stored, but need one for each direction.
819  // should also use wave speeds from edges?
820 
821 
822 
823 
824  /* Stone & Gardiner eq. 48 */
825  // Charles Gammie (8/17/05) says does much better on flux loop advection test than ordinary HARM
826  // COMPLOOPINFP1{ // constrain or control better? GODMARK
827  // COMPEMFZLOOP{
828 #pragma omp parallel OPENMPGLOBALPRIVATEFORSTATEANDGEOM // requires full copyin()
829  {
830  // Below stuff is for Athena 1 and Athena 2
831  int dir;
832  int i,j,k,l,pl,pliter;
833  // gdet-type geometry below
834  struct of_gdetgeom geomf1dontuse,geomf2dontuse,geomf3dontuse;
835  struct of_gdetgeom *ptrgeomf1=&geomf1dontuse,*ptrgeomf2=&geomf2dontuse,*ptrgeomf3=&geomf3dontuse;
836  FTYPE diffusiveterm[NDIM];
837  FTYPE emfmm[NDIM],emfpm[NDIM],emfmp[NDIM],emfpp[NDIM],alpha[NDIM] ;
838  // Gammie stuff
839  FTYPE B1pp,B1pm,B1mp,B1mm;
840  FTYPE B2pp,B2pm,B2mp,B2mm ;
841  FTYPE B3pp,B3pm,B3mp,B3mm ;
842  FTYPE U1pp,U1pm,U1mp,U1mm;
843  FTYPE U2pp,U2pm,U2mp,U2mm ;
844  FTYPE U3pp,U3pm,U3mp,U3mm ;
845  // FTYPE cms_func(FTYPE *prim_var) ;
846  FTYPE B1d,B1u,B1l,B1r;
847  FTYPE B2d,B2u,B2l,B2r;
848  FTYPE B3d,B3u,B3l,B3r;
849  FTYPE pbavg[NPR];
850  struct of_state state;
851  int ignorecourant;
852  FTYPE cmax1,cmin1,cmax2,cmin2,ctop1,ctop2;
853  struct of_geom geomco1dontuse,geomco2dontuse,geomco3dontuse;
854  struct of_geom *ptrgeomco1=&geomco1dontuse,*ptrgeomco2=&geomco2dontuse,*ptrgeomco3=&geomco3dontuse;
855 
856 
858 
859 
860  // generally ptr's are different inside parallel block
861  ptrgeomf1=&geomf1dontuse;
862  ptrgeomf2=&geomf2dontuse;
863  ptrgeomf3=&geomf3dontuse;
864  ptrgeomco1=&geomco1dontuse;
865  ptrgeomco2=&geomco2dontuse;
866  ptrgeomco3=&geomco3dontuse;
867 
868 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE())
870  OPENMP3DLOOPBLOCK2IJK(i,j,k);
871 
872 
873  // dq1 and dq2 and dq3 are well-defined from fluxcalc() (both directions)
874 
875 
876  // simple average of 1-D linear extrapolation here, where could use p2interp data saved from step_ch.c? still available by this function call?
877 
878 
879 #if((N2>1)||(N3>1))
880  // for emf_1
881 
882  // B2 located at FACE2 @ (k-1)
883  B2d = 0.5*(
884  MACP0A1(pb,i,jm1mac(j),km1mac(k),B2) + 0.5*MACP0A1(dq2,i,jm1mac(j),km1mac(k),B2) +
885  MACP0A1(pb,i,j ,km1mac(k),B2) - 0.5*MACP0A1(dq2,i,j ,km1mac(k),B2)
886  ) ;
887 
888  // B2 located at FACE2 @ (k)
889  B2u = 0.5*(
890  MACP0A1(pb,i,jm1mac(j),k,B2) + 0.5*MACP0A1(dq2,i,jm1mac(j),k,B2) +
891  MACP0A1(pb,i,j ,k,B2) - 0.5*MACP0A1(dq2,i,j ,k,B2)
892  ) ;
893 
894  // B3 located at FACE3 @ (j-1)
895  B3l = 0.5*(
896  MACP0A1(pb,i,jm1mac(j),km1mac(k),B3) + 0.5*MACP0A1(dq3,i,jm1mac(j),km1mac(k),B3) +
897  MACP0A1(pb,i,jm1mac(j),k ,B3) - 0.5*MACP0A1(dq3,i,jm1mac(j),k ,B3)
898  ) ;
899  // B3 located at FACE3 @ j
900  B3r = 0.5*(
901  MACP0A1(pb,i,j,km1mac(k),B3) + 0.5*MACP0A1(dq3,i,j,km1mac(k),B3) +
902  MACP0A1(pb,i,j,k ,B3) - 0.5*MACP0A1(dq3,i,j,k ,B3)
903  ) ;
904 
905  // B2 for all centers around CORN1
906  // B2[j - mp][k - mp]
907  B2mm = MACP0A1(pb,i,jm1mac(j),km1mac(k),B2) ;
908  B2mp = MACP0A1(pb,i,jm1mac(j),k ,B2) ;
909  B2pm = MACP0A1(pb,i,j ,km1mac(k),B2) ;
910  B2pp = MACP0A1(pb,i,j ,k ,B2) ;
911 
912  // B3 for all centers around CORN1
913  // B3[j - mp][k - mp]
914  B3mm = MACP0A1(pb,i,jm1mac(j),km1mac(k),B3) ;
915  B3mp = MACP0A1(pb,i,jm1mac(j),k ,B3) ;
916  B3pm = MACP0A1(pb,i,j ,km1mac(k),B3) ;
917  B3pp = MACP0A1(pb,i,j ,k ,B3) ;
918 
919  // compute characteristic velocity -- only for Athena2 method
920 
921 
922  // average pb to CORN1 for average phase speed there
923  PLOOP(pliter,pl) pbavg[pl]=0.25*(MACP0A1(pb,i,j,k,pl)+MACP0A1(pb,i,jm1mac(j),k,pl)+MACP0A1(pb,i,j,km1mac(k),pl)+MACP0A1(pb,i,jm1mac(j),km1mac(k),pl));
924  get_geometry(i, j, k, CORN1, ptrgeomco1); // used here and below emf's
925  MYFUN(get_state(pbavg, ptrgeomco1, &state),"step_ch.c:flux_ct()", "get_state()", 1);
926  // KORALNOTE: Correct because this applies to the diffusive term only for the magnetic field evolution, so needs to stay vchar()
927  dir=2; MYFUN(vchar(pbavg, &state, dir, ptrgeomco1, &cmax1, &cmin1,&ignorecourant),"step_ch.c:flux_ct()", "vchar() dir=1", 1);
928  dir=3; MYFUN(vchar(pbavg, &state, dir, ptrgeomco1, &cmax2, &cmin2,&ignorecourant),"step_ch.c:flux_ct()", "vchar() dir=2", 2);
929  ctop1 = max(fabs(cmax1), fabs(cmin1));
930  ctop2 = max(fabs(cmax2), fabs(cmin2));
931  // alpha=0.5*(ctop1+ctop2); // use average?
932  // alpha=max(ctop1,ctop2); // use maximum?
933  // seems alpha can be arbitrary since 0 is ATHENA1
934 
935  // alpha = dx1/dt ; /* crude approx */
936 
937 
938  // GODMARK: seems to have left/right and up/down asymmetry due to subtraction
939  // if fabs were around each sutracted term, then would be ok (e.g. fabs(B1d-B1u))
940 
941  // notice that ctop1 and ctop2 have different "units", so cannot use with B2/B3 arbitrarily, must be consistent.
942  diffusiveterm[1] = 0.125*(
943  +ctop1*(
944  + B2d - B2mm - B2u + B2mp
945  + B2d - B2pm - B2u + B2pp
946  )
947  +ctop2*(
948  + B3r - B3pm - B3l + B3mm
949  + B3r - B3pp - B3l + B3mp
950  )
951  ) ;
952 #endif
953 
954 #if((N1>1)||(N3>1))
955  // for emf_2
956 
957  // B3 located at FACE3 @ (i-1)
958  B3d = 0.5*(
959  MACP0A1(pb,im1mac(i),j,km1mac(k),B3) + 0.5*MACP0A1(dq3,im1mac(i),j,km1mac(k),B3) +
960  MACP0A1(pb,im1mac(i),j,k ,B3) - 0.5*MACP0A1(dq3,im1mac(i),j,k ,B3)
961  ) ;
962 
963  // B3 located at FACE3 @ (i)
964  B3u = 0.5*(
965  MACP0A1(pb,i,j,km1mac(k),B3) + 0.5*MACP0A1(dq3,i,j,km1mac(k),B3) +
966  MACP0A1(pb,i,j,k ,B3) - 0.5*MACP0A1(dq3,i,j,k ,B3)
967  ) ;
968 
969  // B3 located at FACE1 @ (k-1)
970  B1l = 0.5*(
971  MACP0A1(pb,im1mac(i),j,km1mac(k),B1) + 0.5*MACP0A1(dq1,im1mac(i),j,km1mac(k),B1) +
972  MACP0A1(pb,i ,j,km1mac(k),B1) - 0.5*MACP0A1(dq1,i ,j,km1mac(k),B1)
973  ) ;
974  // B1 located at FACE1 @ k
975  B1r = 0.5*(
976  MACP0A1(pb,im1mac(i),j,k,B1) + 0.5*MACP0A1(dq1,im1mac(i),j,k,B1) +
977  MACP0A1(pb,i ,j,k,B1) - 0.5*MACP0A1(dq1,i ,j,k,B1)
978  ) ;
979 
980  // B3 for all centers around CORN1
981  // B3[k - mp][i - mp]
982  B3mm = MACP0A1(pb,im1mac(i),j,km1mac(k),B3) ;
983  B3mp = MACP0A1(pb,i ,j,km1mac(k),B3) ;
984  B3pm = MACP0A1(pb,im1mac(i),j,k ,B3) ;
985  B3pp = MACP0A1(pb,i ,j,k ,B3) ;
986 
987  // B1 for all centers around CORN1
988  // B1[k - mp][i - mp]
989  B1mm = MACP0A1(pb,im1mac(i),j,km1mac(k),B1) ;
990  B1mp = MACP0A1(pb,i ,j,km1mac(k),B1) ;
991  B1pm = MACP0A1(pb,im1mac(i),j,k ,B1) ;
992  B1pp = MACP0A1(pb,i ,j,k ,B1) ;
993 
994  // compute characteristic velocity -- only for Athena2 method
995 
996 
997  // average pb to CORN1 for average phase speed there
998  PLOOP(pliter,pl) pbavg[pl]=0.25*(MACP0A1(pb,i,j,k,pl)+MACP0A1(pb,im1mac(i),j,k,pl)+MACP0A1(pb,i,j,km1mac(k),pl)+MACP0A1(pb,im1mac(i),j,km1mac(k),pl));
999  get_geometry(i, j, k, CORN2, ptrgeomco2); // used here and below emf's
1000  MYFUN(get_state(pbavg, ptrgeomco2, &state),"step_ch.c:flux_ct()", "get_state()", 1);
1001  dir=3; MYFUN(vchar(pbavg, &state, dir, ptrgeomco2, &cmax1, &cmin1,&ignorecourant),"step_ch.c:flux_ct()", "vchar() dir=1", 1);
1002  dir=1; MYFUN(vchar(pbavg, &state, dir, ptrgeomco2, &cmax2, &cmin2,&ignorecourant),"step_ch.c:flux_ct()", "vchar() dir=2", 2);
1003  ctop1 = max(fabs(cmax1), fabs(cmin1));
1004  ctop2 = max(fabs(cmax2), fabs(cmin2));
1005  // alpha=0.5*(ctop1+ctop2); // use average?
1006  // alpha=max(ctop1,ctop2); // use maximum?
1007  // seems alpha can be arbitrary since 0 is ATHENA1
1008 
1009  // alpha = dx1/dt ; /* crude approx */
1010 
1011 
1012  // GODMARK: seems to have left/right and up/down asymmetry due to subtraction
1013  // if fabs were around each sutracted term, then would be ok (e.g. fabs(B3d-B3u))
1014 
1015  // notice that ctop1 and ctop2 have different "units", so cannot use with B2/B3 arbitrarily, must be consistent.
1016  diffusiveterm[2] = 0.125*(
1017  +ctop1*(
1018  + B3d - B3mm - B3u + B3mp
1019  + B3d - B3pm - B3u + B3pp
1020  )
1021  +ctop2*(
1022  + B1r - B1pm - B1l + B1mm
1023  + B1r - B1pp - B1l + B1mp
1024  )
1025  ) ;
1026 #endif
1027 
1028 #if((N1>1)||(N2>1))
1029  // for emf_3
1030 
1031  // B1 located at FACE1 @ (j-1)
1032  B1d = 0.5*(
1033  MACP0A1(pb,im1mac(i),jm1mac(j),k,B1) + 0.5*MACP0A1(dq1,im1mac(i),jm1mac(j),k,B1) +
1034  MACP0A1(pb,i ,jm1mac(j),k,B1) - 0.5*MACP0A1(dq1,i ,jm1mac(j),k,B1)
1035  ) ;
1036 
1037  // B1 located at FACE1 @ j
1038  B1u = 0.5*(
1039  MACP0A1(pb,im1mac(i),j,k,B1) + 0.5*MACP0A1(dq1,im1mac(i),j,k,B1) +
1040  MACP0A1(pb,i ,j,k,B1) - 0.5*MACP0A1(dq1,i ,j,k,B1)
1041  ) ;
1042 
1043  // B2 located at FACE2 @ (i-1)
1044  B2l = 0.5*(
1045  MACP0A1(pb,im1mac(i),jm1mac(j),k,B2) + 0.5*MACP0A1(dq2,im1mac(i),jm1mac(j),k,B2) +
1046  MACP0A1(pb,im1mac(i),j ,k,B2) - 0.5*MACP0A1(dq2,im1mac(i),j ,k,B2)
1047  ) ;
1048  // B2 located at FACE2 @ i
1049  B2r = 0.5*(
1050  MACP0A1(pb,i,jm1mac(j),k,B2) + 0.5*MACP0A1(dq2,i,jm1mac(j),k,B2) +
1051  MACP0A1(pb,i,j ,k,B2) - 0.5*MACP0A1(dq2,i,j ,k,B2)
1052  ) ;
1053 
1054  // B1 for all centers around CORN3
1055  // B1[i - mp][j - mp]
1056  B1mm = MACP0A1(pb,im1mac(i),jm1mac(j),k,B1) ;
1057  B1mp = MACP0A1(pb,im1mac(i),j ,k,B1) ;
1058  B1pm = MACP0A1(pb,i ,jm1mac(j),k,B1) ;
1059  B1pp = MACP0A1(pb,i ,j ,k,B1) ;
1060 
1061  // B2 for all centers around CORN3
1062  // B2[i - mp][j - mp]
1063  B2mm = MACP0A1(pb,im1mac(i),jm1mac(j),k,B2) ;
1064  B2mp = MACP0A1(pb,im1mac(i),j ,k,B2) ;
1065  B2pm = MACP0A1(pb,i ,jm1mac(j),k,B2) ;
1066  B2pp = MACP0A1(pb,i ,j ,k,B2) ;
1067 
1068  // compute characteristic velocity -- only for Athena2 method
1069 
1070 
1071  // average pb to CORN3 for average phase speed there
1072  PLOOP(pliter,pl) pbavg[pl]=0.25*(MACP0A1(pb,i,j,k,pl)+MACP0A1(pb,i,jm1mac(j),k,pl)+MACP0A1(pb,im1mac(i),j,k,pl)+MACP0A1(pb,im1mac(i),jm1mac(j),k,pl));
1073  get_geometry(i, j, k, CORN3, ptrgeomco3); // used here and below emf's
1074  MYFUN(get_state(pbavg, ptrgeomco3, &state),"step_ch.c:flux_ct()", "get_state()", 1);
1075  dir=1; MYFUN(vchar(pbavg, &state, dir, ptrgeomco3, &cmax1, &cmin1,&ignorecourant),"step_ch.c:flux_ct()", "vchar() dir=1", 1);
1076  dir=2; MYFUN(vchar(pbavg, &state, dir, ptrgeomco3, &cmax2, &cmin2,&ignorecourant),"step_ch.c:flux_ct()", "vchar() dir=2", 2);
1077  ctop1 = max(fabs(cmax1), fabs(cmin1));
1078  ctop2 = max(fabs(cmax2), fabs(cmin2));
1079  // alpha=0.5*(ctop1+ctop2); // use average?
1080  // alpha=max(ctop1,ctop2); // use maximum?
1081  // seems alpha can be arbitrary since 0 is ATHENA1
1082 
1083  // alpha = dx1/dt ; /* crude approx */
1084 
1085 
1086  // GODMARK: seems to have left/right and up/down asymmetry due to subtraction
1087  // if fabs were around each sutracted term, then would be ok (e.g. fabs(B1d-B1u))
1088 
1089  // notice that ctop1 and ctop2 have different "units", so cannot use with B2/B3 arbitrarily, must be consistent.
1090  diffusiveterm[3] = 0.125*(
1091  +ctop1*(
1092  + B1d - B1mm - B1u + B1mp
1093  + B1d - B1pm - B1u + B1pp
1094  )
1095  +ctop2*(
1096  + B2r - B2pm - B2l + B2mm
1097  + B2r - B2pp - B2l + B2mp
1098  )
1099  ) ;
1100 #endif
1101 
1102 
1103 
1104 
1106  //
1107  // add geometry
1108  //
1110 
1111  // must add geometry (no choice since above diffusive correction never had geometry)
1112  get_geometry_gdetmix(i,j,k,CORN1,ptrgeomf1);
1113  get_geometry_gdetmix(i,j,k,CORN2,ptrgeomf2);
1114  get_geometry_gdetmix(i,j,k,CORN3,ptrgeomf3);
1115 
1116  // obviously ptrgeom->EOMFUNCMAC(B2) has to be equal to ptrgeom->EOMFUNCMAC(B3) for this method
1117  diffusiveterm[1] *=(ptrgeomf1->EOMFUNCMAC(B2));
1118  // obviously ptrgeom->EOMFUNCMAC(B1) has to be equal to ptrgeom->EOMFUNCMAC(B2) for this method
1119  diffusiveterm[2] *=(ptrgeomf2->EOMFUNCMAC(B1));
1120  // obviously ptrgeom->EOMFUNCMAC(B1) has to be equal to ptrgeom->EOMFUNCMAC(B2) for this method
1121  diffusiveterm[3] *=(ptrgeomf3->EOMFUNCMAC(B1));
1122 
1124  //
1125  // now add diffusive term to emf
1126  //
1128  for(l=1;l<=3;l++){
1129  MACP1A0(emf,l,i,j,k)+= - diffusiveterm[l];
1130  }
1131 
1132 
1133  }// end EMF loop
1134  }// end parallel region
1135 
1136  }// end if athena2
1137 
1138 
1139 
1140  return(0);
1141 }
1142 
1143 
1144 
1145 
1146 
1147 
1148 
1149 
1150 
1151 
1152 
1153 
1154 
1155 
1156 
1157 
1158 
1161 int flux_ct_emf2flux(int stage, FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*emf)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3], FTYPE (*vconemf)[NSTORE2][NSTORE3][NDIM-1], FTYPE (*dq1)[NSTORE2][NSTORE3][NPR], FTYPE (*dq2)[NSTORE2][NSTORE3][NPR], FTYPE (*dq3)[NSTORE2][NSTORE3][NPR], FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL])
1162 {
1163  // full-type geometry below
1164  FTYPE coefemf[NDIM];
1165  extern int choose_limiter(int dir, int i, int j, int k, int pl);
1166 
1167 
1168 
1169 
1170 
1173  //
1174  // compute flux from EMF (signs must be consistent so that similar signed quantity in end)
1175  // e.g. flux terms originally involving B^2 v^1 - B^1 v^2 must come out with same sign at end
1176  //
1177  // This calculation takes care of case when EMF is not needed, so above need not worry about resetting values of emf to 0 or something
1178  //
1179  // we set flux to 0 when that dimension doesn't matter, but note that flux really is not 0. Rather the differences in the flux are 0 across that direction. However, this difference never enters since this flux is only used as flux differences.
1180  // These flux differences are *assumed* to vanish if that dimension has N=1. However, a problem could be setup such that those differences would NOT be 0.
1181  // For example, a wedge out of an axisymmetric slice that has boundaries that are not symmetric around the equator. This would have flux differences that would lead to changes in the quantity. This would be a quasi-2D problem modelled in 1D.
1182  //
1185 
1186  // Presume emf[N+SHIFT] so can combine loops, which just ignores values at emf[N+SHIFT-1]. Increases cache miss for F1,F2,F3, but less for emf(1,2,3) and less loop overhead, especially for OpenMP
1187 
1188  if((FLUXB==FLUXCTTOTH)||(FLUXB==ATHENA2)||(FLUXB==ATHENA1)){
1189  /* rewrite EMFs as fluxes, after Toth */
1190 
1191 
1192 #pragma omp parallel // no copyin() needed since not calling any functions that use global vars
1193  {
1194  int i,j,k;
1196 
1200  // OPENMP3DLOOPSETUP(INFULL1,OUTFULLM11,-N2BND,N2-1+N2BND,INFULL3,OUTFULLM13);
1201  // COMPF2CTZLOOP {
1203  //OPENMP3DLOOPSETUP(INFULL1,OUTFULLM11,INFULL2,OUTFULLM12,-N3BND,N3-1+N3BND);
1204  // COMPF3CTZLOOP {
1205 
1206 
1208 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE()) // not needed with just 1 loop: nowait // Can "nowait" since each F1,F2,F3 set independently on successive loops
1210  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1211 
1213  // F1
1215 #if(N1>1)
1216  // below line always true
1217  MACP0A1(F1,i,j,k,B1) = 0.;
1218  MACP0A1(F1,i,j,k,B2) = 0.5 * (MACP1A0(emf,3,i,j,k) + MACP1A0(emf,3,i,jp1mac(j),k)); // put emf3 back to FACE1
1219  MACP0A1(F1,i,j,k,B3) = - 0.5 * (MACP1A0(emf,2,i,j,k) + MACP1A0(emf,2,i,j,kp1mac(k))); // put emf2 back to FACE1
1220 #endif
1221 
1222 
1223 
1225  // F2
1227 #if(N2>1)
1228  MACP0A1(F2,i,j,k,B1) = - 0.5 * (MACP1A0(emf,3,i,j,k) + MACP1A0(emf,3,ip1mac(i),j,k));
1229  // below line always true
1230  MACP0A1(F2,i,j,k,B2) = 0.;
1231  MACP0A1(F2,i,j,k,B3) = 0.5 * (MACP1A0(emf,1,i,j,k) + MACP1A0(emf,1,i,j,kp1mac(k)));
1232 #endif
1233 
1235  // F3
1237 #if(N3>1)
1238  MACP0A1(F3,i,j,k,B1) = 0.5 * (MACP1A0(emf,2,i,j,k) + MACP1A0(emf,2,ip1mac(i),j,k));
1239  MACP0A1(F3,i,j,k,B2) = - 0.5 * (MACP1A0(emf,1,i,j,k) + MACP1A0(emf,1,i,jp1mac(j),k));
1240  // below line always true
1241  MACP0A1(F3,i,j,k,B3) = 0.;
1242 #endif
1243  }// end loop block [using outer loop since even though 3X more expensive cache-wise for F1, less so for emf. Reduces OpenMP overhead alot.
1244  }// end parallel region (and implied barrier)
1245 
1246 
1247 
1248 
1249 
1250  } // end if FLUXCT
1251  else if(FLUXB==FLUXCD){
1252 
1253 
1254 
1255 
1256 
1257  // F's are emf's, where dF/dx is (F(i+1)-F(i-1))/dx
1258  // fluxes remain at center!
1259 
1260 #pragma omp parallel // no copyin() required
1261  {
1262  int i,j,k;
1264 
1265 
1266 
1267  // COMPF1CTZLOOP {
1269 
1270 
1272 #pragma omp for schedule(OPENMPFULLNOVARYSCHEDULE()) // nowait // Can "nowait" since each successive loop sets F1,F2,F3 independently
1274  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1275 
1277  // F1
1279 #if(N1>1)
1280  // always below line
1281  MACP0A1(F1,i,j,k,B1) = 0.0;
1282  MACP0A1(F1,i,j,k,B2) = MACP1A0(emf,3,i,j,k);
1283  MACP0A1(F1,i,j,k,B3) = -MACP1A0(emf,2,i,j,k);
1284 #endif // end if doing F1
1285 
1286 
1287 
1289  // F2
1291 #if(N2>1)
1292  MACP0A1(F2,i,j,k,B1) = -MACP1A0(emf,3,i,j,k);
1293  // always below line
1294  MACP0A1(F2,i,j,k,B2) = 0.;
1295  MACP0A1(F2,i,j,k,B3) = MACP1A0(emf,1,i,j,k);
1296 #endif // end if doing F2
1297 
1298 
1299 
1301  // F3
1303 #if(N3>1)
1304  MACP0A1(F3,i,j,k,B1) = MACP1A0(emf,2,i,j,k);
1305  MACP0A1(F3,i,j,k,B2) = -MACP1A0(emf,1,i,j,k);
1306  // always below line
1307  MACP0A1(F3,i,j,k,B3) = 0.;
1308 #endif // end if doing F3
1309  }// end loop block [using outer loop since even though 3X more expensive cache-wise for F1, less so for emf. Reduces OpenMP overhead alot.
1310  }// end parallel region (and implied barrier)
1311 
1312 
1313 
1314  } // end if FLUXCD
1315 
1316 
1317 
1318  return(0);
1319 }