HARM
harm and utilities
 All Data Structures Files Functions Variables Typedefs Macros Pages
fluxvpot.c
Go to the documentation of this file.
1 #include "decs.h"
2 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 int get_fluxpldirs(int *Nvec, int dir, int *fluxdir, int* pldir, int *plforflux, FTYPE *signflux)
26 {
27  int odir1,odir2;
28 
29 
30  // get cyclic other dimensions
31  get_odirs(dir,&odir1,&odir2);
32 
33  if(Nvec[odir1]>1) { *fluxdir=odir1; *pldir=odir2; *plforflux = B1+ *pldir-1; *signflux=1.0; } // A[dir] = F[odir1][B1+odir2-1] // normal ordering
34  else if(Nvec[odir2]>1){ *fluxdir=odir2; *pldir=odir1; *plforflux = B1+ *pldir-1; *signflux=-1.0; } // A[dir] = F[odir2][B1+odir1-1] // opposite ordering
35  else{ *fluxdir=0; *pldir=0; *plforflux=0; }
36  // else{
37  // dualfprintf(fail_file,"Shouldn't reach EMF line integration with Nvec=%d %d %d\n",Nvec[1],Nvec[2],Nvec[3]);
38  // myexit(917515);
39  // }
40 
41  return(0);
42 }
43 
44 
49 void get_odirs(int dir,int *odir1,int *odir2)
50 {
51  // m%3+1 gives next 1->2,2->3,3->1
52  // 3-(4-m)%3 = (dir+1)%3+1 gives previous 1->3,2->1,3->2
53  *odir1=dir%3+1; // if dir==3, then odir1=1
54  *odir2=(dir+1)%3+1; // if dir==3, then odir2=2
55 }
56 
57 
60 int set_location_fluxasemforvpot(int dir, int *numdirs, int *odir1, int *odir2, int *loc)
61 {
62  int fieldloc[NDIM];
63 
64  get_numdirs_fluxasemforvpot(numdirs,fieldloc); // field loc has locations of each field component (not used here)
65 
66 
67  get_odirs(dir,odir1,odir2);
68 
69 
70  if(FLUXB==FLUXCTHLL){
71  // for this method we use F1/F2/F3 and locations are different
72 
73  loc[*odir1]=FACE1-1 + *odir1;
74  loc[*odir2]=FACE1-1 + *odir2;
75 
76  }
77  else{
78 
79  loc[*odir1]=CORN1-1 + dir;
80  loc[*odir2]=CORN1-1 + dir;
81 
82  }
83 
84  return(0);
85 
86 
87 
88 }
89 
91 int get_numdirs_fluxasemforvpot(int *numdirs, int *fieldloc)
92 {
93 
95  //
96  // These choices must be made consistent with use of vpot2field()
97  //
99 
100 
101  if(! (FLUXB==FLUXCTHLL || FLUXB==FLUXCTSTAG) ){
102  *numdirs = 1;
103  fieldloc[1]=CENT;
104  fieldloc[2]=CENT;
105  fieldloc[3]=CENT;
106  }
107  else if(FLUXB==FLUXCTHLL){
108  // for this method we use F1/F2/F3 and locations are different
109  *numdirs=2;
110  fieldloc[1]=CENT;
111  fieldloc[2]=CENT;
112  fieldloc[3]=CENT;
113  }
114  else{
115 
116  if(extrazones4emf==0){
117 
119  // for this method we use F1/F2/F3 but location is same corner
120  *numdirs=2;
121  }
122  else{
123  // unless emfextrazones4emf==0 and fluxrecon and doing point field, then don't need both directions
124  *numdirs=1;
125  }
126  }
127  else{
128  // then just using A not F1/F2/F3
129  *numdirs=1;
130  }
131 
132  if(FLUXB==FLUXCTSTAG){
133  fieldloc[1]=FACE1;
134  fieldloc[2]=FACE2;
135  fieldloc[3]=FACE3;
136  }
137  else{
138  // non-HLL version
139  fieldloc[1]=CENT;
140  fieldloc[2]=CENT;
141  fieldloc[3]=CENT;
142  }
143 
144  }
145 
146  return(0);
147 
148 
149 
150 }
151 
152 
153 
159 {
160  int i,j,k,pl,pliter;
161  int numdirs, fieldloc[NDIM];
162 
163 
165  //
166  // get whether using A or F1/F2/F3 and where final field located per direction of field
167  //
169  get_numdirs_fluxasemforvpot(&numdirs,fieldloc);
170 
171 
173  //
174  // One of 3 things:
175  // 1) single line-integrate vector potential (A_i) for FV method
176  // 2) double transverse quasi-deaverage (per A_i) for FLUXRECON method if evolving Bhat
177  // 3) single quasi-deaverage (per flux direction) for FLUXRECON if evolving point field
178  //
180  if(DOENOFLUX==NOENOFLUX){
181  // nothing to do
182  }
184 
185  if(numdirs==2){
186  // difference between CTHLL and CTSTAG is position of flux
187  // then treat flux itself as flux and assume flux set as vector potential
188  // don't actually use A here
189  // if doing FLUXRECON and evolving points, then
190  vectorpot_useflux(STAGEM1, pfield, F1, F2, F3);
191  }
192  else{
193  // SUPERGODMARK: should tell where field is located
194  vectorpot_fluxreconorfvavg(STAGEM1, pfield, A, F1, F2, F3);
195  }
196  }
197  else{
198  dualfprintf(fail_file,"No vectorpot for this case of DOENOFLUX=%d\n",DOENOFLUX);
199  myexit(83465765);
200  }
201 
202 
203 
204 
206  //
207  // Now use higher-order vector potential to obtain (primitive AND conserved) field that satisfies divb=0 in certain form
208  //
210 
211  if(numdirs==1){
212  // use of A
213  if((FLUXB==ATHENA1)||(FLUXB==ATHENA2)||(FLUXB==FLUXCTTOTH)){
214  vpot2field_centeredfield(A,pfield,ucons);
215  }
216  else if(FLUXB==FLUXCD){
217  vpot2field_centeredfield(A,pfield,ucons); // probably wrong for FLUXCD? GODMARK
218  dualfprintf(fail_file,"FLUXCD probably not setup right in vpot2field()\n");
219  myexit(196726);
220  }
221  else if(FLUXB==FLUXCTSTAG){
222  // overwrites any old choice for unew for field only
223  // pstag is in general not a point value of field!
224  vpot2field_staggeredfield(A,pfield,ucons);
225  }
226  else{
227  dualfprintf(fail_file,"Undefined numdirs==1 with FLUXB==%d\n",FLUXB);
228  myexit(2752632);
229  }
230  }
231  else if(numdirs==2){
232 
233  // use of F1/F2/F3
234  vpot2field_useflux(fieldloc,pfield,ucons,F1,F2,F3);
235 
236  // FLUXCTHLL is just for testing how behaves without divb=0 control
237  // with fluxcthll always numdirs==2 so uses flux instead of A
238 
239  // overwrites any old choice for unew for field only
240  // pstag is in general not a point value of field!
241  if(! (FLUXB==FLUXCTHLL || FLUXB==FLUXCTSTAG) ){
242  dualfprintf(fail_file,"Undefined numdirs==2 with FLUXB==%d\n",FLUXB);
243  myexit(23578234);
244  }
245 
247  // DEBUG:
248  // bound_pstag(STAGEM1,t,pfield, pstag, ucons, 1, USEMPI);
249 
250  // then need to obtian Bhat so can compute divb
251  // In this case unew is inputted point conserved field
252  field_Bhat_fluxrecon(pfield,ucons,Bhat);
253  }
254 
255  }
256 
257 
259  //
260  // copy result of vector potential calculation to staggered field if doing FLUXCTSTAG
261  //
263  if(FLUXB==FLUXCTSTAG){
264  copy_3d_fieldonly_fullloop(pfield,pstag);
265  // from now on, pfield is assumed to be at CENT
266  }
267 
268 
269 
270 
272  //
273  // Before ucons->{upoint,ppoint} that involves interpolation, need to make sure setup pre-interpolates if haven't already.
274  // Uses pglobal like initbase.c consistent with first calculation of pre_interpolation
275  //
277 
279  pre_interpolate_and_advance(GLOBALPOINT(pglobal));
280  }
281 
283  //
284  // convert average or quasi-deaveraged field to point field (ulast and pfield)
285  // Ok to use ulastglobal as temporary space
286  //
288 
289  ucons2upointppoint(time,pfield,pstag,ucons,uconstemp,pfield);
290 
291 
292 
293  // Since above procedures changed pfield that is probably pcent that is p, we need to rebound p since pfield was reset to undefined values in ghost cells since A_i isn't determined everywhere
294  // alternatively for evolve_withvpot() could have inputted not the true p or some copy of it so wouldn't have to bound (except up to machine error difference when recomputed field using A_i)
295  int finalstep=1; // assume user wants to know that conserved quants changed
296  bound_prim(STAGEM1,finalstep, time,pfield,pstag,ucons, USEMPI);
297 
298 
299  return(0);
300 
301 }
302 
303 
304 
305 
306 
307 
309 int ucons2upointppoint(SFTYPE boundtime, FTYPE (*pfield)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],FTYPE (*unew)[NSTORE2][NSTORE3][NPR],FTYPE (*ulast)[NSTORE2][NSTORE3][NPR],FTYPE (*pcent)[NSTORE2][NSTORE3][NPR])
310 {
311  int i,j,k,pl,pliter;
312  int numdirs, fieldloc[NDIM];
313 
314 
316  //
317  // get whether using A or F1/F2/F3 and where final field located per direction of field
318  //
320  get_numdirs_fluxasemforvpot(&numdirs,fieldloc);
321 
322 
323 
324  // SUPERDEBUG:
325  //bound_pstag(STAGEM1, t, pfield, pfield, unew);
326  //bound_pstag(STAGEM1, t, pfield, pfield, unew);
327  // dualfprintf(fail_file,"DEBUG Got here\n");
328 
329 
330  // if restarting, then unew was read-in and then later assigned to unitial, so by the time init is done we have staggered fields in unew/unitial for any case
331  // from staggered field still need to fill pfield with centered version
332  // for first call to interpolation need real primitive, but don't yet have CENT field, so use staggered version as "guess"-- GODMARK not strictly grid-correct
333 
334 
335 
337  //
338  // convert average or quasi-deaveraged field to point field (ulast)
339  //
341 
342  if(numdirs==1){
343  if(DOENOFLUX == ENOFINITEVOLUME){
344  // unew and ulast both inputted so function compares results with original
345  deaverage_fields_fv(pfield,unew,ulast);
346  }
347  else if(DOENOFLUX == ENOFLUXRECON){
348  // unew and ulast both inputted so function compares results with original
349  field_integrate_fluxrecon(STAGEM1,pfield,unew,ulast);
350  }
351  else{
352  // second order methods have same average and point value
353  copy_3d_fieldonly_fullloop(unew,ulast);
354  }
355  }
356  else{
357  // FLUXB==FLUXCTHLL has point value as conserved field value like ENOFLUXRECON has for non-field values
358  copy_3d_fieldonly_fullloop(unew,ulast);
359  }
360 
361 
363  //
364  // Convert point staggered field to point CENT field for staggered field method
365  //
367 
368  if(FLUXB==FLUXCTSTAG){
369 
370  // ok to insert pfield for real primitive since any update to pfield is ok to be used since only used for shock indicator
371  interpolate_ustag2fieldcent(STAGEM1,boundtime, -1,-1,pfield,pstag,ulast,pcent);
372  // now pstagscratch will have correct staggered point value and ulast (if needed) will be replaced with center conserved value and pfield will contain centered field primitive value
373 
374  // now field sits in both centered and staggered positions with initial data
375 
376  }
377 
378 
379  return(0);
380 }
381 
382 
383 
388 {
390 
391 
392 #if(TRACKVPOT)
393  A=vpot; // real t=0 value put here and used to track A_i for diagnostics
394 #else
395  A=Atemp; // dummy memory space not used till computation so safe.
396 #endif
397 
398 
399 
400  // prim -> A using user function init_vpot_user()
401  init_vpot_justAcov(t, prim, A); // t is ok since always t=tstart
402 
403  // A->Flux if required
404  init_vpot_toF(A, F1, F2, F3);
405 
406  // assigns value to p and pstagscratch and unew (uses F1/F2/F3 if doing FLUXCTHLL)
407  // often user just uses init_vpot2field() unless not always using vector potential
408  init_vpot2field_user(t, A,prim,pstag,ucons,Bhat); // t is ok since always t=tstart
409 
410  // in case user perturbs vpot, need to ensure ghost cells updated.
411  if(1){
412  int boundvartype=BOUNDVPOTTYPE;
413  int finalstep=0; // assume user wants to know if initial conserved quants changed
414  int doboundmpi=1;
415  int doboundnonmpi=0;
416  bound_vpot(STAGEM1, finalstep, t, boundvartype, vpot, doboundmpi, doboundnonmpi);
417  }
418 
419 
420 
421  return(0);
422 
423 }
424 
425 
426 
428 int get_vpot_fluxctstag_primecoords(SFTYPE time, int i, int j, int k, FTYPE (*prim)[NSTORE2][NSTORE3][NPR], FTYPE *vpot)
429 {
430  int dir;
431  FTYPE X[NDIM],V[NDIM];
432  int loc;
433  FTYPE vpotuser[NDIM];
434  int ii,jj,kk;
435  int whichcoord;
436  int userdir;
437 
438 
439  // copied from init_vpot_justAcov()
440  // loop over A_l's
441  DIMENLOOP(dir){
442 
443  if(dir==1) loc=CORN1;
444  else if(dir==2) loc=CORN2;
445  else if(dir==3) loc=CORN3;
446 
447 
448  bl_coord_ijk_2(i, j, k, loc, X, V); // face[odir2] and flux[odir2]
449  // dxdxprim_ijk(i, j, k, loc, dxdxp);
450 
451  // get user vpot in user coordinates (assume same coordinates for all A_{userdir}
452  DLOOPA(userdir){
453  init_vpot_user(&whichcoord, userdir, time, i,j,k, loc, prim, V, &vpotuser[userdir]);
454  }
455 
456  // convert from user coordinate to PRIMECOORDS
457  ucov_whichcoord2primecoords(whichcoord, i, j, k, loc, vpotuser);
458 
459  // now copy the only component required
460  vpot[dir]=vpotuser[dir];
461 
462  }// loop over A_i
463 
464 
465  return(0);
466 
467 }
468 
469 
470 
474 {
475  int Nvec[NDIM];
476  int odir1[NDIM],odir2[NDIM];
477  int numdirs;
478  int locvpot[NDIM][NDIM];
479  int dir;
480 
481 
482 
483  Nvec[0]=0;
484  Nvec[1]=N1;
485  Nvec[2]=N2;
486  Nvec[3]=N3;
487 
488 
489 
490  // get location of vpot and number of locations to set
491  DIMENLOOP(dir){
492  set_location_fluxasemforvpot(dir, &numdirs, &odir1[dir], &odir2[dir], locvpot[dir]);
493 
494  // these quantities are associated with a single choice for relationship between A_i and F_j[B_k]
495  // get_fluxpldirs(Nvec, dir, &fluxdirlist[dir], &pldirlist[dir], &plforfluxlist[dir], &signforfluxlist[dir]);
496  }
497 
498 
499  if(numdirs==2){
500  // will be done in another function
501  }
502  else{
503  trifprintf("Initialize field from vector potential (really A)\n");
504  // DIMENLOOP(dir) COMPFULLLOOPP1 MACP1A0(A,dir,i,j,k) = 0.;
505  DIMENLOOP(dir) init_3dvpot_fullloopp1(0.0,A[dir]);
506 #if(TRACKVPOT)
507  init_3dvpot_fullloopp1(0.0,A[TT]);
508 #endif
509  }
510 
511 
512  trifprintf("Initialize field from vector potential assign: init_vpot_justAcov()\n");
513 
514 
515 
516  // GODMARK: Caution: Possible to use quantity off grid
517  // (e.g. density) to define lower corner value of A, which then
518  // defines B at center for lower cells.
519  // Do have *grid* quantities for everywhre A is.
520 
522 #pragma omp parallel private(dir) OPENMPGLOBALPRIVATEFULL // user could do anything
523  {
524  FTYPE X[NDIM],V[NDIM];
525  FTYPE dxdxp[NDIM][NDIM];
526  int otherdir;
527  FTYPE vpotuser[NDIM];
528  int userdir;
529  int whichcoord;
530  int loc;
531  int i,j,k,pl,pliter;
532  // int fluxdir,pldir,plforflux;
533  // int fluxdirlist[NDIM],pldirlist[NDIM],plforfluxlist[NDIM];
534  // FTYPE signforfluxlist[NDIM];
535  // FTYPE signforflux;
536 
538 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
540  OPENMP3DLOOPBLOCK2IJK(i,j,k);
541 
542 
543  // can't define F1/F2/F3 in outermost part ofCOMPFULLLOOPP1 since don't exist there
544  // can only define as if doing COMPFULLLOOP
545  if(numdirs==2 && (i>OUTFULL1 || j>OUTFULL2 || k>OUTFULL3) ) continue;
546 
547  // loop over A_l's
548  DIMENLOOP(dir){
549 
550  // these quantities are associated with a single choice for relationship between A_i and F_j[B_k]
551  // fluxdir=fluxdirlist[dir];
552  // pldir=pldirlist[dir];
553  // plforflux=plforfluxlist[dir];
554  // signforflux=signforfluxlist[dir];
555 
556 
557  // loop over positions to get vector potential
558  for(otherdir=1;otherdir<=numdirs;otherdir++){
559 
560  if(otherdir==1){
561  loc=locvpot[dir][odir1[dir]];
562  }
563  else if(otherdir==2){
564  loc=locvpot[dir][odir2[dir]];
565  }
566 
567  bl_coord_ijk_2(i, j, k, loc, X, V); // face[odir2] and flux[odir2]
568  // dxdxprim_ijk(i, j, k, loc, dxdxp);
569 
570 
571  // get user vpot in user coordinates (assume same coordinates for all A_{userdir}
572  DLOOPA(userdir){
573  init_vpot_user(&whichcoord, userdir, time, i,j,k, loc, prim, V, &vpotuser[userdir]);
574  }
575 
576  // convert from user coordinate to PRIMECOORDS
577  ucov_whichcoord2primecoords(whichcoord, i, j, k, loc, vpotuser);
578 
579  // for numdirs=anything (used for input for 2Flux and for 2Flux required if doing TRACKVPOT
580  MACP1A0(A,dir,i,j,k) = vpotuser[dir];
581 
582  }// end for loop over otherdirs
583  }// end over A_i
584 
585 
586  }// end over i,j,k
587 
588  }// end parallel region
589 
590 
591 
592 
593 
594  return(0);
595 
596 }
597 
598 
599 
604 {
605  int Nvec[NDIM];
606  FTYPE (*fluxvec[NDIM])[NSTORE2][NSTORE3][NPR+NSPECIAL];
607  int odir1[NDIM],odir2[NDIM];
608  int numdirs;
609  int locvpot[NDIM][NDIM];
610  int dir;
611 
612 
613 
614  Nvec[0]=0;
615  Nvec[1]=N1;
616  Nvec[2]=N2;
617  Nvec[3]=N3;
618 
619  fluxvec[1] = F1;
620  fluxvec[2] = F2;
621  fluxvec[3] = F3;
622 
623 
624  // get location of vpot and number of locations to set
625  DIMENLOOP(dir){
626  set_location_fluxasemforvpot(dir, &numdirs, &odir1[dir], &odir2[dir], locvpot[dir]);
627 
628  // these quantities are associated with a single choice for relationship between A_i and F_j[B_k]
629  // get_fluxpldirs(Nvec, dir, &fluxdirlist[dir], &pldirlist[dir], &plforfluxlist[dir], &signforfluxlist[dir]);
630  }
631 
632 
633  if(numdirs==2){
634  // then fill F1/F2/F3 instead of A[]
635  trifprintf("Initialize field from vector potential (really flux)\n");
636  DIMENLOOP(dir){
637  if(Nvec[dir]>1){
638  init_3dnpr_fullloop_flux(0.0,fluxvec[dir]);
639  }
640  }
641 
642  }
643  else{
644  // then A already initialized
645  }
646 
647 
648  trifprintf("Initialize field from vector potential assign: init_vpot_toF()\n");
649 
650 
651 
652  // GODMARK: Caution: Possible to use quantity off grid
653  // (e.g. density) to define lower corner value of A, which then
654  // defines B at center for lower cells.
655  // Do have *grid* quantities for everywhre A is.
656 
658 #pragma omp parallel private(dir) OPENMPGLOBALPRIVATEFULL // user could do anything
659  {
660  int otherdir;
661  int userdir;
662  int whichcoord;
663  int loc;
664  int i,j,k,pl,pliter;
665  // int fluxdir,pldir,plforflux;
666  // int fluxdirlist[NDIM],pldirlist[NDIM],plforfluxlist[NDIM];
667  // FTYPE signforfluxlist[NDIM];
668  // FTYPE signforflux;
669 
671 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
673  OPENMP3DLOOPBLOCK2IJK(i,j,k);
674 
675 
676  // can't define F1/F2/F3 in outermost part ofCOMPFULLLOOPP1 since don't exist there
677  // can only define as if doing COMPFULLLOOP
678  if(numdirs==2 && (i>OUTFULL1 || j>OUTFULL2 || k>OUTFULL3) ) continue;
679 
680  // loop over A_l's
681  DIMENLOOP(dir){
682 
683  // these quantities are associated with a single choice for relationship between A_i and F_j[B_k]
684  // fluxdir=fluxdirlist[dir];
685  // pldir=pldirlist[dir];
686  // plforflux=plforfluxlist[dir];
687  // signforflux=signforfluxlist[dir];
688 
689 
690  // loop over positions to get vector potential
691  for(otherdir=1;otherdir<=numdirs;otherdir++){
692 
693  if(otherdir==1){
694  loc=locvpot[dir][odir1[dir]];
695  }
696  else if(otherdir==2){
697  loc=locvpot[dir][odir2[dir]];
698  }
699 
700 
701  // normal ordering is A[dir] = fluxvec[fluxdir][plforflux] with fluxdir=odir1 and plforflux from odir2
702 
703  if(numdirs==2){
704  // then using F1/F2/F3
705  // Notice that fluxvec here has no \detg in it, as consistent with taking B = curlA ($\detg B^i = d_j A_k \epsilon^{ijk}$) when used
706  // Notice that both fluxes are assigned a value in some cases, as required
707  // e.g. F1[B2]=A3 and F2[B1]=-A3
708  if(otherdir==1 && Nvec[odir1[dir]]>1) MACP1A1(fluxvec,odir1[dir],i,j,k,B1-1+odir2[dir])=MACP1A0(A,dir,i,j,k);
709  if(otherdir==2 && Nvec[odir2[dir]]>1) MACP1A1(fluxvec,odir2[dir],i,j,k,B1-1+odir1[dir])=-MACP1A0(A,dir,i,j,k); // opposite ordering
710 
711 
712  }
713  else{
714  // then already assigned to A
715  }
716  }// end for loop over otherdirs
717  }// end over A_i
718 
719 
720  }// end over i,j,k
721 
722  }// end parallel region
723 
724 
725 
726 
727 
728  return(0);
729 
730 }
731 
732 
733 
734 
735 
736 
737 
738 
739 
740 
741 
742 
745 int copy_vpot2flux(FTYPE (*A)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3], FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL])
746 {
747  FTYPE (*fluxvec[NDIM])[NSTORE2][NSTORE3][NPR+NSPECIAL];
748  int Nvec[NDIM];
749  int odir1[NDIM],odir2[NDIM];
750  int numdirs;
751  int locvpot[NDIM][NDIM];
752  int dir;
753 
754 
755 
756 
757  Nvec[0]=0;
758  Nvec[1]=N1;
759  Nvec[2]=N2;
760  Nvec[3]=N3;
761 
762  fluxvec[1] = F1;
763  fluxvec[2] = F2;
764  fluxvec[3] = F3;
765 
766 
767  // get location of vpot and number of locations to set
768  DIMENLOOP(dir){
769  set_location_fluxasemforvpot(dir, &numdirs, &odir1[dir], &odir2[dir], locvpot[dir]);
770  }
771 
772 
773  if(numdirs==2){
774 
775  // 0-out flux (F1/F2/F3)
776  DIMENLOOP(dir){
777  if(Nvec[dir]>1){
778  init_3dnpr_fullloop_flux(0.0,fluxvec[dir]);
779  }
780  }
781 
782 
783 
784  // can't define F1/F2/F3 in outermost part of COMPFULLLOOPP1 since don't exist there
785  // can only define as if doing FULLLOOP
787 #pragma omp parallel private(dir) // no copyin since no use of non-array globals (yet)
788  {
789  int otherdir;
790  int i,j,k;
792 
793 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
795  OPENMP3DLOOPBLOCK2IJK(i,j,k);
796 
797  DIMENLOOP(dir){
798 
799  // loop over positions to get vector potential
800  for(otherdir=1;otherdir<=numdirs;otherdir++){
801 
802  // then using F1/F2/F3
803  // Notice that fluxvec here has no \detg in it, as consistent with taking B = curlA ($\detg B^i = d_j A_k \epsilon^{ijk}$) when used
804  // Notice that both fluxes are assigned a value in some cases, as required
805  if(otherdir==1 && Nvec[odir1[dir]]>1) MACP1A1(fluxvec,odir1[dir],i,j,k,B1-1+odir2[dir])=MACP1A0(A,dir,i,j,k);
806  if(otherdir==2 && Nvec[odir2[dir]]>1) MACP1A1(fluxvec,odir2[dir],i,j,k,B1-1+odir1[dir])=-MACP1A0(A,dir,i,j,k); // opposite ordering
807 
808  }// end for loop over otherdirs
809  }// end over A_i
810 
811 
812  }// end over i,j,k
813  }//end if parallel region
814  }// end if numdirs==2 (and so actually need to copy vpot to flux)
815 
816  return(0);
817 
818 }
819 
820 
821 
822 
823 
830 int evolve_withvpot(SFTYPE time, FTYPE (*prim)[NSTORE2][NSTORE3][NPR],FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],FTYPE (*unew)[NSTORE2][NSTORE3][NPR],FTYPE (*vpot)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3],FTYPE (*Bhat)[NSTORE2][NSTORE3][NPR], FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*Atemp)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3], FTYPE (*uconstemp)[NSTORE2][NSTORE3][NPR])
831 {
832 
833  if(EVOLVEWITHVPOT==0){
834 
835 
836 
837  }
838  else{
839 
840  // 1) fill F or vpot(A,prim);
841  // 2) call vpot2field()
842 
843  // perhaps split init_vpot so can be used for this function too
844  // **TODO** essentially need a separate function that takes point A_i and fills F if needed rather than all at once as in init_vpot()
845 
846  // only copies if necessary for how method is setup (e.g. staggered point evolution method)
847  // i.e. F is not really flux here, just place-holder for A_i at different positions as required by some other methods, such as FLUXCTTOTH or FLUXCTSTAG w/ higher-order corrections.
848  copy_vpot2flux(vpot,F1,F2,F3);
849 
850 
851  // Note that vpot2field bounds pstag and input prim as required since A_i doesn't exist everywhere
852  // GODMARK: use of many globals: ok for now since evolve_withvpot() not used for any other purpose
853  vpot2field(time, vpot,prim, pstag, unew, Bhat,F1,F2,F3,Atemp,uconstemp);
854 
855 
856 
857 #if(0)
858  // DEBUG: Trying to get test=1102 to work with EVOLVEWITHVPOT (also turned on bound_flux_fluxrecon() in update_vpot() so E_i fully periodic in BZs before A_i iterated
859  bound_pstag(STAGEM1,t,prim, pstag, unew);
860  bound_prim(STAGEM1,t,prim, pstag, unew);
861  bound_uavg(STAGEM1,t,prim, pstag, unew);
862 #endif
863  }
864 
865  return(0);
866 
867 }
868 
869 
870 
871 
872 
875 void setfdivb(FTYPE *divb, FTYPE (*p)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR], FTYPE (*U)[NSTORE2][NSTORE3][NPR], FTYPE (*Bhat)[NSTORE2][NSTORE3][NPR], int i, int j, int k)
876 {
877 
878 
879 
880  if((FLUXB==ATHENA1)||(FLUXB==ATHENA2)||(FLUXB==FLUXCTTOTH)){
881  if(DOENOFLUX==NOENOFLUX){ SETFDIVBFLUXCTTOTHPRIM((*divb),p,i,j,k);}
882  else{ SETFDIVBFLUXCTTOTH((*divb),U,i,j,k);}
883  }
884  else if(FLUXB==FLUXCD){
885  if(DOENOFLUX==NOENOFLUX){ SETFDIVBFLUXCDPRIM((*divb),p,i,j,k);}
886  else{ SETFDIVBFLUXCD((*divb),U,i,j,k);}
887  }
888  else if(FLUXB==FLUXCTHLL){
889  if(DOENOFLUX==NOENOFLUX){ SETFDIVBFLUXCTTOTHPRIM((*divb),p,i,j,k);} // fake
890  else{ SETFDIVBFLUXCTTOTH((*divb),U,i,j,k);} // fake
891  }
892  else if(FLUXB==FLUXCTSTAG){
893  // for STAG, always can use U since always used, but can use pstag too for lower order method
894  //if(DOENOFLUX==NOENOFLUX) SETFDIVBFLUXCTSTAG((*divb),pstag,i,j,k);
895 
897  // evolving point field but need Bhat to check divb=0
898  // apparently must use fixed stencil so could compute when divb requested instead of always
899  // now compute divBhat that should be 0 to machine accuracy
900  SETFDIVBFLUXCTSTAG((*divb),Bhat,i,j,k);
901  }
902  else{
903  if(DOENOFLUX==NOENOFLUX){
904  // then can use pstag itself that is always bounded properly
905  SETFDIVBFLUXCTSTAGPRIM((*divb),pstag,i,j,k);
906  }
907  else{
908  // then must use higher-order version
909  // for diagnostics in MPI can bound U before dumping, but should only bound MPI since no treatment of U for real boundaries
910  SETFDIVBFLUXCTSTAG((*divb),U,i,j,k);
911  }
912  }
913 
914  // *divb =
915  // +(MACP0A1(U,ip1mac(i),j,k,B1)-MACP0A1(U,i,j,k,B1))/dx[1]
916  // +(MACP0A1(U,i,jp1mac(j),k,B2)-MACP0A1(U,i,j,k,B2))/dx[2]
917  // +(MACP0A1(U,i,j,kp1mac(k),B3)-MACP0A1(U,i,j,k,B3))/dx[3]
918  // ;
919  }
920  else{
921  dualfprintf(fail_file,"No such FLUXB==%d in setfdivb()\n",FLUXB);
922  myexit(817163);
923  }
924 
925 }
926 
927 
928 
929 
930 
931 
932 
937 int vpot2field_useflux(int *fieldloc,FTYPE (*pfield)[NSTORE2][NSTORE3][NPR],FTYPE (*ufield)[NSTORE2][NSTORE3][NPR], FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL])
938 {
939  int Nvec[NDIM];
940  FTYPE (*fluxvec[NDIM])[NSTORE2][NSTORE3][NPR+NSPECIAL];
941 
942 
943 
944 
945 
946 
947  Nvec[0]=0;
948  Nvec[1]=N1;
949  Nvec[2]=N2;
950  Nvec[3]=N3;
951 
952  fluxvec[1] = F1;
953  fluxvec[2] = F2;
954  fluxvec[3] = F3;
955 
956 
957 
958  // Assumes defined vector potential with signature such that
959  // B = +curlA
960  // \detg B^i = +d_j ([tijk] A_k)
961  // and HARM conventions for what F1/F2/F3 mean in terms of EMF-like object
962  // Note that dB/dt = -curlE has opposite sign prefactor that is folded into E when doing flux calculation, so flux is really -E
963  // So when letting dA/dt = -E = +emf = +flux with consistent cyclic indices
964 
965 
966 
967 #pragma omp parallel
968  {
969 
970  int i,j,k;
971  FTYPE igdetgnosing[NDIM];
972  int dir;
973  int pl,pliter;
974  int odir1,odir2;
975  int jj;
976  struct of_geom geomfdontuse[NDIM];
977  struct of_geom *ptrgeomf[NDIM];
978  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUPFULL; // doesn't depend upon dir, but blockijk must be private, so put in parallel loop
979 
980  // assign memory
981  DLOOPA(jj) ptrgeomf[jj]=&(geomfdontuse[jj]);
982 
983 
985  //
986  // A_1
987  //
989 
990  dir=1;
991  get_odirs(dir,&odir1,&odir2);
992  if(!(Nvec[odir1]==1 && Nvec[odir2]==1)){
994 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait // no wait allowed as in fluxct.c
996  OPENMP3DLOOPBLOCK2IJK(i,j,k);
997 
998  // ufield doesn't require geometry
999 
1000  // myA[3]=-F2[B1]
1001  // myA[2]=F3[B1];
1002  MACP0A1(ufield,i,j,k,B1) = 0.0;
1003 #if(N2>1)
1004  MACP0A1(ufield,i,j,k,B1) += -(MACP0A1(F2,i,jp1mac(j),k,B1)-MACP0A1(F2,i,j,k,B1))/(dx[2]);
1005 #endif
1006 #if(N3>1)
1007  MACP0A1(ufield,i,j,k,B1) += -(MACP0A1(F3,i,j,kp1mac(k),B1)-MACP0A1(F3,i,j,k,B1))/(dx[3]);
1008 #endif
1009 
1010  get_geometry(i, j, k, fieldloc[dir], ptrgeomf[dir]);
1011  igdetgnosing[dir] = sign(ptrgeomf[dir]->gdet)/(fabs(ptrgeomf[dir]->gdet)+SMALL); // avoids 0.0 for any sign of ptrgeom->gdet
1012  MACP0A1(pfield,i,j,k,B1-1+dir) = MACP0A1(ufield,i,j,k,B1-1+dir)*igdetgnosing[dir];
1013  }// end 3D LOOP
1014  }// end if doing A1
1015 
1017  //
1018  // A_2
1019  //
1021 
1022  dir=2;
1023  get_odirs(dir,&odir1,&odir2);
1024  if(!(Nvec[odir1]==1 && Nvec[odir2]==1)){
1026 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait // no wait allowed as in fluxct.c
1028  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1029 
1030  // myA[1]=-F3[B2];
1031  // myA[3]=F1[B2];
1032 
1033  MACP0A1(ufield,i,j,k,B2) = 0.0;
1034 #if(N3>1)
1035  MACP0A1(ufield,i,j,k,B2) += -(MACP0A1(F3,i,j,kp1mac(k),B2)-MACP0A1(F3,i,j,k,B2))/(dx[3]);
1036 #endif
1037 #if(N1>1)
1038  MACP0A1(ufield,i,j,k,B2) += -(MACP0A1(F1,ip1mac(i),j,k,B2)-MACP0A1(F1,i,j,k,B2))/(dx[1]);
1039 #endif
1040 
1041  get_geometry(i, j, k, fieldloc[dir], ptrgeomf[dir]);
1042  igdetgnosing[dir] = sign(ptrgeomf[dir]->gdet)/(fabs(ptrgeomf[dir]->gdet)+SMALL); // avoids 0.0 for any sign of ptrgeom->gdet
1043  MACP0A1(pfield,i,j,k,B1-1+dir) = MACP0A1(ufield,i,j,k,B1-1+dir)*igdetgnosing[dir];
1044  }
1045  }
1046 
1048  //
1049  // A_3
1050  //
1052 
1053  dir=3;
1054  get_odirs(dir,&odir1,&odir2);
1055  if(!(Nvec[odir1]==1 && Nvec[odir2]==1)){
1057 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait // no wait allowed as in fluxct.c
1059  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1060 
1061  // myA[2]=-F1[B3];
1062  // myA[1]=F2[B3];
1063 
1064  MACP0A1(ufield,i,j,k,B3) = 0.0;
1065 #if(N1>1)
1066  MACP0A1(ufield,i,j,k,B3) += -(MACP0A1(F1,ip1mac(i),j,k,B3)-MACP0A1(F1,i,j,k,B3))/(dx[1]);
1067 #endif
1068 #if(N2>1)
1069  MACP0A1(ufield,i,j,k,B3) += -(MACP0A1(F2,i,jp1mac(j),k,B3)-MACP0A1(F2,i,j,k,B3))/(dx[2]);
1070 #endif
1071 
1072  get_geometry(i, j, k, fieldloc[dir], ptrgeomf[dir]);
1073  igdetgnosing[dir] = sign(ptrgeomf[dir]->gdet)/(fabs(ptrgeomf[dir]->gdet)+SMALL); // avoids 0.0 for any sign of ptrgeom->gdet
1074  MACP0A1(pfield,i,j,k,B1-1+dir) = MACP0A1(ufield,i,j,k,B1-1+dir)*igdetgnosing[dir];
1075  }
1076  }
1077 
1078 
1079  }// end parallel region (and implied barrier)
1080 
1081 
1082 
1083 
1084 
1085 
1086 
1087 
1088 
1089 #if(FLUXDUMP==1)
1090  {
1091  int i,j,k,dir,pl,pliter;
1092  // this accounts for final flux
1093  FULLLOOP{
1094  DIMENLOOP(dir){
1095  if(Nvec[dir]>1){
1096  PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,4*NPR + (dir-1)*NPR*5 + NPR*0 + pl)=MACP1A1(fluxvec,dir,i,j,k,pl);
1097  }
1098  else{
1099  PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,4*NPR + (dir-1)*NPR*5 + NPR*0 + pl)=0.0L;
1100  }
1101  }
1102  }
1103  }
1104 #endif
1105 
1106 
1107 
1108  return(0);
1109 }
1110 
1111 
1112 
1113 
1114 
1115 
1116 
1139 int evolve_vpotgeneral(int whichmethod, int stage,
1140  int initialstep, int finalstep,
1141  FTYPE (*pr)[NSTORE2][NSTORE3][NPR],
1142  int *Nvec,
1143  FTYPE (*fluxvec[NDIM])[NSTORE2][NSTORE3][NPR+NSPECIAL],
1145  FTYPE *CUf, FTYPE *CUnew, SFTYPE fluxdt, SFTYPE fluxtime,
1147  )
1148 {
1149  int dimen;
1153  vpot0 =vpot+1*NDIM;
1154  vpotlast=vpot+2*NDIM;
1155  vpotcum =vpot+3*NDIM;
1156 
1157 
1158 
1159  if(EVOLVEWITHVPOT==0 && TRACKVPOT==0){
1160  dualfprintf(fail_file,"Shouldn't be in evolve_vpotgeneral() with EVOLVEWITHVPOT==0 && TRACKVPOT==0\n");
1161  myexit(45986252);
1162  }
1163 
1164 
1166  //
1167  // Can either:
1168  // 1) user adjust only EMF
1169  // 2) user adjust both EMF and VPOT. Reason both: EMF reset on surfaces used to set new VPOT. VPOT adjusted to deal with interior so Bstag^i and Bcent^i are smooth through surfaces.
1170  // In case VPOT is adjusted, EMF is fixed-up to agree with VPOT by updating temporary VPOT that is then modified that is then used to back-create the EMF that is used to update to a final VPOT
1171  // This ensures consistency between user EMF and user VPOT modifications
1172  //
1174 
1175 
1176 
1177  // user adjust of EMFs
1178  if(MODIFYEMFORVPOT==MODIFYEMF || MODIFYEMFORVPOT==MODIFYVPOT) adjust_emfs(fluxtime, whichmethod, pr, Nvec, fluxvec, emf);
1179 
1180 
1181 
1182 
1184  if(initialstep==1){
1185  // For all current TIMEORDERs, Ui is always from pi so always from last ucum or vpotcum
1186  for(dimen=0;dimen<NDIM;dimen++){
1187  // copy over vpotcum -> vpot0
1188  copy_3dvpot_fullloopp1(vpot[dimen],vpot0[dimen]); // really copying vpotcum -> vpot0 since already copied vpotcum->vpot (below in this function, or at t=0 vpot is correct to use)
1189  // must first set 0->{vpotlast,vpotcum} if first step (i.e. vpotcum (like ucum) will add vpot0 as required, so starts at 0, not vpot0, here)
1190  init_3dvpot_fullloopp1(0.0,vpotlast[dimen]);
1191  init_3dvpot_fullloopp1(0.0,vpotcum[dimen]);
1192  }
1193  }
1194  else{
1195  // then no change in vpot0 for current TIMEORDER's
1196  }
1197  }
1198 
1199 
1200  // EVOLVEWITHVPOT==1 means use A_i as ultimate basis for B^i. So can modify A_i and affect resulting B^i while keeping divB=0
1201  // MODIFYEMFORVPOT==MODIFYVPOT means allow modification of fluxes/emfs using A_i (no point unless A_i is used to compute B^i)
1202 
1203 
1204  if(MODIFYEMFORVPOT==MODIFYVPOT && EVOLVEWITHVPOT>0){ // overall, get new emf/fluxes
1205 
1206 
1207  // flux->A_i : get new vpot using fluxes
1208  // like getting Uf from fluxes
1209  // vpotcum argument is set to NULL since don't want to update ucum-like quantity yet
1210  update_vpot(whichmethod, stage, pr, fluxvec, emf, CUf, CUnew, fluxdt, vpot, vpot0, vpotlast, NULL);
1211 
1212 
1213 
1214 
1216  //
1217  // User "boundary conditions" to modify A_i's before used
1218  // They will be used in step_ch.c calling evolve_withvpot() that resets B^i using A_i
1219  //
1221 
1222  // A_i -> Amod_i (-> A_i)
1223  adjust_vpot(fluxtime, whichmethod, pr, Nvec, vpot);
1224 
1225 
1226 
1227  // now obtain EMF_i from A_i and Aold_i
1228  // this sets EMFs so that one only has to adjust A_i and not also EMF_i
1229  // A_i,Aold_i -> EMF_i (in F_i)
1230  // like deriving flux from Uf and Ui (NOTE: not derived from Ucum)
1231  set_emfflux(whichmethod, stage,pr,fluxvec,emf,CUf, CUnew, fluxdt,vpot,vpot0,vpotlast);
1232 
1233 
1234  }
1235 
1236 
1237  if(MODIFYEMFORVPOT==MODIFYVPOT || TRACKVPOT>0 || EVOLVEWITHVPOT>0){ // overall, update A_i using emf/fluxes (either original or new from modified A_i)
1238 
1240  //
1241  // Update A_i from EMF_i (directly computed, and then either modified directly or through A_i)
1242  // Before higher-order operations on flux, track vector potential update
1243  // so updating point value of A_i
1244  //
1246 
1247  // EMF_i (in F_i) -> A_i
1248  // like regetting Uf and Ucum from fluxes
1249  // only cumulate at this "real" update_vpot() call
1250  update_vpot(whichmethod, stage, pr, fluxvec, emf, CUf, CUnew, fluxdt, vpot, vpot0, vpotlast, vpotcum);
1251 
1252 
1253 
1254  // update vpotlast
1255  for(dimen=0;dimen<NDIM;dimen++) copy_3dvpot_fullloopp1(vpot[dimen],vpotlast[dimen]);
1256 
1257 
1258  if(finalstep==1){
1259  // Doing this for 3 reasons:
1260  // 1) Copy to vpot so (at top of this function) the (vpotcum->vpot)->vpot0 sets up vpot0
1261  // 2) In post_advance() will use vpot to recompute all B's, so copy over vpotcum -> vpot so vpot ready for that computation (otherwise could reference vpotcum there)
1262  // 3) vpotcum will be what's reported in diagnostics with this assignment
1263  for(dimen=0;dimen<NDIM;dimen++) copy_3dvpot_fullloopp1(vpotcum[dimen],vpot[dimen]);
1264  }
1265 
1266 
1267  }
1268 
1269 
1270 
1271  return(0);
1272 }
1273 
1274 
1275 
1276 
1277 
1278 
1281 void adjust_emfs(SFTYPE fluxtime, int whichmethod, FTYPE (*pr)[NSTORE2][NSTORE3][NPR], int *Nvec, FTYPE (*fluxvec[NDIM])[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE (*emf)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3] )
1282 {
1283 
1284 
1285  if((whichmethod==FLUXCTTOTH)||(whichmethod==ATHENA2)||(whichmethod==ATHENA1)||(whichmethod==FLUXCD)){
1286  adjust_fluxcttoth_emfs(fluxtime,pr,emf);
1287  }
1288  else{
1289  adjust_fluxctstag_emfs(fluxtime,pr,Nvec,fluxvec);
1290  }
1291 
1292 
1293 }
1294 
1295 
1296 
1297 
1300 void adjust_vpot(SFTYPE fluxtime, int whichmethod, FTYPE (*pr)[NSTORE2][NSTORE3][NPR], int *Nvec, FTYPE (*vpot)[NSTORE1+SHIFTSTORE1][NSTORE2+SHIFTSTORE2][NSTORE3+SHIFTSTORE3])
1301 {
1302 
1303  if((whichmethod==FLUXCTTOTH)||(whichmethod==ATHENA2)||(whichmethod==ATHENA1)||(whichmethod==FLUXCD)){
1304  adjust_fluxcttoth_vpot(fluxtime,pr,Nvec,vpot);
1305  }
1306  else{
1307  adjust_fluxctstag_vpot(fluxtime,pr,Nvec,vpot);
1308  }
1309 
1310 
1311 }
1312 
1313 
1314 
1315 
1318 {
1319  extern int bound_flux_fluxrecon(int stage, FTYPE (*pr)[NSTORE2][NSTORE3][NPR], int *Nvec, FTYPE (*fluxvec[NDIM])[NSTORE2][NSTORE3][NPR+NSPECIAL]);
1320  int dir;
1321  int fluxdirlist[NDIM],pldirlist[NDIM],plforfluxlist[NDIM];
1322  FTYPE signforfluxlist[NDIM];
1323  int odir1[NDIM],odir2[NDIM];
1324  int locvpot[NDIM][NDIM];
1325  int Nvec[NDIM];
1326  int numdirs;
1327 
1328 
1329 
1330 
1331 
1332 
1333 
1334 #if(0)
1335  // DEBUG ONLY: Bound before vpot updated so EMF is bounded so vpot looks normal
1336  bound_flux_fluxrecon(stage,pr,Nvec,fluxvec);
1337 #endif
1338 
1339 
1340 
1341  Nvec[0]=0;
1342  Nvec[1]=N1;
1343  Nvec[2]=N2;
1344  Nvec[3]=N3;
1345 
1346 
1347  DIMENLOOP(dir){
1348  // GODMARK: Should synchronize how these functions operate/generate results
1349  // initialize directions and variables for cyclic access
1350  get_fluxpldirs(Nvec, dir, &fluxdirlist[dir], &pldirlist[dir], &plforfluxlist[dir], &signforfluxlist[dir]);
1351  // get location of vpot and number of locations to set
1352  set_location_fluxasemforvpot(dir, &numdirs, &odir1[dir], &odir2[dir], locvpot[dir]);
1353  }
1354 
1355 
1356 
1357 
1358 
1359 #pragma omp parallel private(dir) //nothing needed to copyin()
1360  {
1361  int is,ie,js,je,ks,ke;
1362  int i,j,k,pl,pliter;
1363  int fluxdir,pldir,plforflux;
1364  FTYPE signforflux;
1365  struct of_geom geomdontuse;
1366  struct of_geom *ptrgeom=&geomdontuse;
1367  FTYPE igdetvpot;
1368  FTYPE myemf;
1369 
1371 
1372 
1373 
1374  // GODMARK: time-part not updated and assumed to be 0
1375  DIMENLOOP(dir){
1376 
1377  //loop over the interfaces where fluxes are computed -- atch, useCOMPZSLOOP( is, ie, js, je, ks, ke ) { ... }
1378  // since looping over edges (emfs) and flux loop different than emf loop, then expand loops so consistent with both fluxes corresponding to that emf
1379  is=emffluxloop[dir][FIS];
1380  ie=emffluxloop[dir][FIE];
1381  js=emffluxloop[dir][FJS];
1382  je=emffluxloop[dir][FJE];
1383  ks=emffluxloop[dir][FKS];
1384  ke=emffluxloop[dir][FKE];
1385 
1386  fluxdir=fluxdirlist[dir];
1387  pldir=pldirlist[dir];
1388  plforflux=plforfluxlist[dir];
1389  signforflux=signforfluxlist[dir];
1390 
1391 #if(DEBUGNSBH)
1392  dualfprintf(fail_file,"nstep=%ld steppart=%d dir=%d fluxdir=%d plforflux=%d locvpot=%d geomeodir=%d pldir=%d signforflux=%21.15g\n",nstep,steppart,dir,fluxdir,plforflux,locvpot[dir][odir2[dir]],B1-1+odir1[dir],pldir,signforflux);
1393 #endif
1394 
1395 
1396  if(Nvec[fluxdir]>1){
1397 
1398  // \partial_t A_i = -\detg E_i = EMF
1399  // e.g. A_1 += -\detg E_1
1400  // GODMARK: vpot exists atCOMPFULLLOOPP1, but fluxvec does not
1401 
1402  // if(dir==3){
1403  // }
1404 
1405 
1409  //#endif
1411 
1412  OPENMP3DLOOPSETUP( is, ie, js, je, ks, ke );
1413 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait // Can use "nowait" since each vpot[dir] setting is independent from prior loops
1415  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1416 
1417 
1418  // GODMARK: Assume doesn't matter what order odir1/odir2 come in here
1419  // get_geometry(i, j, k, locvpot[dir][odir2[dir]], ptrgeom); // get geometry at CORN[dir] where emf is located
1420  // which field ptrgeom->e doesn't matter (see fluxctstag.c)
1421  // igdetvpot=sign(ptrgeom->e[B1-1+odir1[dir]])/(fabs(ptrgeom->e[B1-1+odir1[dir]])+SMALL); // avoids 0.0 for any sign of ptrgeom->gdet
1422 
1423  // \partial_t A_i = EMF = -\detg E_i where E_i=flux/\detg
1424  // Note that fluxvec as created in flux.c (etc.) has \detg in front of EMF, so remove for A_i as required
1425  // Note sign depends upon conventions of how associated flux in either direction with single EMF = -\detg E = dA/dt (hence + sign for cyclic indices)
1426  // MACP1A0(vpot,dir,i,j,k) += fluxdt*MACP1A1(fluxvec,fluxdir,i,j,k,plforflux)*igdetvpot;
1427 
1428  // e.g. from get_fluxpldirs:
1429  // dA_1 += dt F3[B2] if N3>1 else dA_1 += dt F2[B3] if N2>1 else don't do
1430 
1431 
1432  if((whichmethod==FLUXCTTOTH)||(whichmethod==ATHENA2)||(whichmethod==ATHENA1)||(whichmethod==FLUXCD)){
1433  // then need to use EMF not fluxes since only EMF is filled -- to update A_i
1434  // loop setup over fluxes so only reach this once (not twice) so only use EMF once as required
1435  // MACP1A0(vpot,dir,i,j,k) += fluxdt*MACP1A0(emf,dir,i,j,k);
1436  myemf=MACP1A0(emf,dir,i,j,k);
1437  }
1438  else{
1439  // then use fluxes directly to update A_i
1440  // note that only reach this once (not twice) so only use one flux, not its redundant partner
1441  // MACP1A0(vpot,dir,i,j,k) += signforflux*fluxdt*MACP1A1(fluxvec,fluxdir,i,j,k,plforflux);
1442  myemf=signforflux*MACP1A1(fluxvec,fluxdir,i,j,k,plforflux);
1443  }
1444 
1445  // update like in advance using flux2dUavg() & dUtoU(). But only 1 flux position rather than difference of fluxes.
1446  FTYPE ftemp[MAXTIMEORDER]={0.0};
1447  if(vpot!=NULL) MACP1A0(vpot,dir,i,j,k) = UFSET (CUf ,dt,MACP1A0(vpot0,dir,i,j,k),MACP1A0(vpotlast,dir,i,j,k),myemf,0.0,ftemp); // notice vpotlast[] used here not vpot
1448  if(vpotcum!=NULL) MACP1A0(vpotcum,dir,i,j,k) += UCUMUPDATE(CUnew,dt,MACP1A0(vpot0,dir,i,j,k),MACP1A0(vpot,dir,i,j,k) ,myemf,0.0,ftemp); // notice vpot[] used here, just like in dUtoU()
1449 
1450 
1451 #if(DEBUGNSBH)
1452  if(dir==2 && i==26 && j==40){
1453  dualfprintf(fail_file,"inside update_vpot: %21.15g (%21.15g %21.15g %21.15g) dt=%21.15g vpot0=%21.15g vpotlast=%21.15g myemf=%21.15g\n",MACP1A0(vpot,dir,i,j,k),CUf[0],CUf[1],CUf[2],dt,MACP1A0(vpot0,dir,i,j,k),MACP1A0(vpotlast,dir,i,j,k),myemf);
1454  }
1455 #endif
1456 
1457 
1458  // if(dir==3){
1459  // dualfprintf(fail_file,"i=%d j=%d k=%d fluxdt=%21.15g vpot=%21.15g fluxvec=%21.15g geomvpot=%21.15g\n",i,j,k,fluxdt,MACP1A0(vpot,dir,i,j,k),MACP1A1(fluxvec,fluxdir,i,j,k,plforflux),geomvpot);
1460  // }
1461 
1462  // after each full step (for example) could compute magnetic field from vpot so no roundoff error progression and not wasteful for higher-order timestepping
1463 
1464 
1465  }// end 3D LOOP
1466  }// end if fluxdir exists
1467  }// end over dirs
1468  }// end over parallel region (and implied barrier)
1469 
1470 
1471 
1472  return(0);
1473 
1474 }
1475 
1476 
1477 
1478 
1482 {
1483  int dir;
1484  int fluxdirlist[NDIM],pldirlist[NDIM],plforfluxlist[NDIM];
1485  FTYPE signforfluxlist[NDIM];
1486  int odir1[NDIM],odir2[NDIM];
1487  int locvpot[NDIM][NDIM];
1488  int Nvec[NDIM];
1489  int numdirs;
1490 
1491 
1492 
1493 
1494 
1495  Nvec[0]=0;
1496  Nvec[1]=N1;
1497  Nvec[2]=N2;
1498  Nvec[3]=N3;
1499 
1500 
1501  DIMENLOOP(dir){
1502  // GODMARK: Should synchronize how these functions operate/generate results
1503  // initialize directions and variables for cyclic access
1504  get_fluxpldirs(Nvec, dir, &fluxdirlist[dir], &pldirlist[dir], &plforfluxlist[dir], &signforfluxlist[dir]);
1505  // get location of vpot and number of locations to set
1506  set_location_fluxasemforvpot(dir, &numdirs, &odir1[dir], &odir2[dir], locvpot[dir]);
1507  }
1508 
1509 
1510 
1511 
1512 
1513 #pragma omp parallel private(dir) //nothing needed to copyin()
1514  {
1515  int is,ie,js,je,ks,ke;
1516  int i,j,k,pl,pliter;
1517  int fluxdir,pldir,plforflux;
1518  FTYPE signforflux;
1519  struct of_geom geomdontuse;
1520  struct of_geom *ptrgeom=&geomdontuse;
1521  FTYPE igdetvpot;
1522  FTYPE myemf;
1523 
1525 
1526 
1527 
1528  // GODMARK: time-part not updated and assumed to be 0
1529  DIMENLOOP(dir){
1530 
1531  //loop over the interfaces where fluxes are computed -- atch, useCOMPZSLOOP( is, ie, js, je, ks, ke ) { ... }
1532  // since looping over edges (emfs) and flux loop different than emf loop, then expand loops so consistent with both fluxes corresponding to that emf
1533  is=emffluxloop[dir][FIS];
1534  ie=emffluxloop[dir][FIE];
1535  js=emffluxloop[dir][FJS];
1536  je=emffluxloop[dir][FJE];
1537  ks=emffluxloop[dir][FKS];
1538  ke=emffluxloop[dir][FKE];
1539 
1540  fluxdir=fluxdirlist[dir];
1541  pldir=pldirlist[dir];
1542  plforflux=plforfluxlist[dir];
1543  signforflux=signforfluxlist[dir];
1544 
1545 
1546  if(Nvec[fluxdir]>1){
1547 
1548 
1549  OPENMP3DLOOPSETUP( is, ie, js, je, ks, ke );
1550 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait // Can use "nowait" since each vpot[dir] setting is independent from prior loops
1552  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1553 
1554 
1555  // \partial_t A_i = EMF = -\detg E_i where E_i=flux/\detg
1556  // e.g. from get_fluxpldirs:
1557  // dA_1 += dt F3[B2] if N3>1 else dA_1 += dt F2[B3] if N2>1 else don't do
1558 
1559 
1560  myemf = dUfromUFSET(CUf,dt,MACP1A0(vpot0,dir,i,j,k),MACP1A0(vpotlast,dir,i,j,k),MACP1A0(vpot,dir,i,j,k));
1561 
1562 
1563  if((whichmethod==FLUXCTTOTH)||(whichmethod==ATHENA2)||(whichmethod==ATHENA1)||(whichmethod==FLUXCD)){
1564  // then need to fill EMF since final flux is non-trivial
1565  MACP1A0(emf,dir,i,j,k)=myemf;
1566  }
1567  else{
1568  // So just invert from update_vpot(): roughly: dA = Anew - Aold = dt F
1569  // below memory flux is always there -- how chosen
1570  MACP1A1(fluxvec,fluxdir,i,j,k,plforflux)=myemf/signforflux;
1571  // below memory is not always there, so must check
1572  if(Nvec[plforflux-B1+1]>1){
1573  MACP1A1(fluxvec,plforflux-B1+1,i,j,k,B1+fluxdir-1)=-MACP1A1(fluxvec,fluxdir,i,j,k,plforflux);
1574  }
1575 
1576  }
1577 
1578 
1579  }// end 3D LOOP
1580  }// end if fluxdir exists
1581  }// end over dirs
1582  }// end over parallel region (and implied barrier)
1583 
1584 
1585 
1586 
1587 
1588 
1589  return(0);
1590 
1591 }
1592 
1593 
1594 
1599 {
1600 
1601 
1602 #pragma omp parallel
1603  {
1604  int i,j,k,pl,pliter;
1605 
1607 
1610 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait // next vpot assignment is independent
1612  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1613 
1614 
1615  // normalize primitive
1616  MACP0A1(prim,i,j,k,B1) *= norm;
1617  MACP0A1(prim,i,j,k,B2) *= norm;
1618  MACP0A1(prim,i,j,k,B3) *= norm;
1619 
1620  // normalize conserved quantity
1621  MACP0A1(ucons,i,j,k,B1) *= norm;
1622  MACP0A1(ucons,i,j,k,B2) *= norm;
1623  MACP0A1(ucons,i,j,k,B3) *= norm;
1624 
1625  // normalize staggered field primitive
1626  if(FLUXB==FLUXCTSTAG){
1627  MACP0A1(pstag,i,j,k,B1) *= norm;
1628  MACP0A1(pstag,i,j,k,B2) *= norm;
1629  MACP0A1(pstag,i,j,k,B3) *= norm;
1630  }
1631 
1632  // normalize higher-order field
1633  if(HIGHERORDERMEM){
1634  MACP0A1(Bhat,i,j,k,B1) *= norm;
1635  MACP0A1(Bhat,i,j,k,B2) *= norm;
1636  MACP0A1(Bhat,i,j,k,B3) *= norm;
1637  }
1638  }// end 3D LOOP
1639 
1640 
1641 
1642  // normalize vector potential if tracking
1643  if(TRACKVPOT){
1644 
1647 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize)) nowait // next vpot assignment is independent
1649  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1650 
1651  MACP1A0(vpot,1,i,j,k) *= norm;
1652  MACP1A0(vpot,2,i,j,k) *= norm;
1653  MACP1A0(vpot,3,i,j,k) *= norm;
1654  }// end 3D LOOP
1655  }
1656 
1657  }// end parallel region (and implied barrier)
1658 
1659  return(0);
1660 
1661 }
1662 
1663 
1664 
1665 
1666 
1667 
1671 {
1672 
1673 
1674 
1677 #pragma omp parallel
1678  {
1679  int i,j,k,pl,pliter;
1680  struct of_geom geomdontuse;
1681  struct of_geom *ptrgeom=&geomdontuse;
1682  struct of_geom geomfdontuse;
1683  struct of_geom *ptrgeomf=&geomfdontuse;
1684 
1686 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
1688  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1689 
1690  if(FLUXB==FLUXCTSTAG){
1691  PLOOPBONLY(pl){
1692  // get point value
1693  get_geometry(i, j, k, FACE1+(pl-B1), ptrgeomf);
1694  MACP0A1(ucons,i,j,k,pl)=MACP0A1(pstag,i,j,k,pl)*(ptrgeomf->gdet);
1695  }
1696  }
1697  else{
1698  PLOOPBONLY(pl){
1699  // assume field is centered
1700  get_geometry(i, j, k, CENT, ptrgeom);
1701  MACP0A1(ucons,i,j,k,pl)=MACP0A1(prim,i,j,k,pl)*(ptrgeom->gdet);
1702  }
1703  }
1704  }
1705  }// end parallel region
1706 
1707 
1708  return(0);
1709 }
1710 
1711 
1712 
1713 
1714 
1717 int assignrough_primitive_pstag(int i,int j, int k, FTYPE (*p)[NSTORE2][NSTORE3][NPR], FTYPE (*pstag)[NSTORE2][NSTORE3][NPR], FTYPE (*ucons)[NSTORE2][NSTORE3][NPR])
1718 {
1719 
1720  if(FLUXB==FLUXCTSTAG && pstag!=NULL && p!=NULL){
1721 
1722  int myim1,myjm1,mykm1;
1723  int myip1,myjp1,mykp1;
1724  int dir,jj,pl;
1725  struct of_gdetgeom geomfdontuse[NDIM];
1726  struct of_gdetgeom *ptrgeomf[NDIM];
1727 
1728  // generally ptr's are different inside parallel block
1729  DLOOPA(jj) ptrgeomf[jj]=&(geomfdontuse[jj]);
1730 
1731  // limit to avoid where have no data
1732  myim1=MAX(-N1BND,im1mac(i));
1733  myjm1=MAX(-N2BND,jm1mac(j));
1734  mykm1=MAX(-N3BND,km1mac(k));
1735 
1736  myip1=MIN(N1+N1BND-1,ip1mac(i));
1737  myjp1=MIN(N2+N2BND-1,jp1mac(j));
1738  mykp1=MIN(N3+N3BND-1,kp1mac(k));
1739 
1740 
1741  // do FACE1 for B1
1742  dir=1; pl=B1;
1743  MACP0A1(pstag,i,j,k,pl)=0.5*(MACP0A1(p,i,j,k,pl)+MACP0A1(p,myim1,j,k,pl));
1744  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgeomf[dir]);
1745  MACP0A1(ucons,i,j,k,B1-1+dir)=MACP0A1(pstag,i,j,k,pl)*ptrgeomf[dir]->IEOMFUNCNOSINGMAC(pl);
1746 
1747  // do FACE2 for B2
1748  dir=2; pl=B2;
1749  MACP0A1(pstag,i,j,k,pl)=0.5*(MACP0A1(p,i,j,k,pl)+MACP0A1(p,i,myjm1,k,pl));
1750  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgeomf[dir]);
1751  MACP0A1(ucons,i,j,k,B1-1+dir)=MACP0A1(pstag,i,j,k,pl)*ptrgeomf[dir]->IEOMFUNCNOSINGMAC(pl);
1752 
1753  // do FACE3 for B3
1754  dir=3; pl=B3;
1755  MACP0A1(pstag,i,j,k,pl)=0.5*(MACP0A1(p,i,j,k,pl)+MACP0A1(p,i,j,mykm1,pl));
1756  get_geometry_gdetonly(i, j, k, FACE1-1+dir, ptrgeomf[dir]);
1757  MACP0A1(ucons,i,j,k,B1-1+dir)=MACP0A1(pstag,i,j,k,pl)*ptrgeomf[dir]->IEOMFUNCNOSINGMAC(pl);
1758 
1759  }
1760 
1761 
1762 
1763 
1764  return(0);
1765 }
1766 
1767 
1768 
1771 {
1772 
1773 
1774 
1776 #pragma omp parallel
1777  {
1778  int i,j,k;
1779  int jj;
1781 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
1783  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1784 
1785 
1786  MACP0A1(prim,i,j,k,B1)=MACP0A1(prim,i,j,k,B2)=MACP0A1(prim,i,j,k,B3)=0.0;
1787  MACP0A1(ucons,i,j,k,B1)=MACP0A1(ucons,i,j,k,B2)=MACP0A1(ucons,i,j,k,B3)=0.0;
1788  if(HIGHERORDERMEM){
1789  MACP0A1(Bhat,i,j,k,B1)=MACP0A1(Bhat,i,j,k,B2)=MACP0A1(Bhat,i,j,k,B3)=0.0;
1790  }
1791  if(FLUXB==FLUXCTSTAG){
1792  MACP0A1(pstag,i,j,k,B1)=MACP0A1(pstag,i,j,k,B2)=MACP0A1(pstag,i,j,k,B3)=0.0;
1793  }
1794  }
1795  }// end parallel region
1796 
1797 
1798  if(TRACKVPOT){
1800 #pragma omp parallel
1801  {
1802  int i,j,k;
1803  int jj;
1805 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
1807  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1808 
1809  DLOOPA(jj) MACP1A0(vpot,jj,i,j,k) = 0.0;
1810  }
1811  }
1812  }// end parallel region
1813 
1814 
1815 
1816  return(0);
1817 }