HARM
harm and utilities
 All Data Structures Files Functions Variables Typedefs Macros Pages
advance.c
Go to the documentation of this file.
1 #include "decs.h"
2 
11 
12 static int compute_dt_fromsource(struct of_geom *ptrgeom, struct of_state *state, FTYPE *U, FTYPE *pr, FTYPE *dUevolve, FTYPE *dUgeomevolveUU, FTYPE *dtij, FTYPE *gravitydt);
13 static int dUtodt(struct of_geom *ptrgeom, struct of_state *state, FTYPE *pr, FTYPE *dUgeom, FTYPE *dUriemann, FTYPE *dUgeomgravity, FTYPE *accdt, FTYPE *gravitydt);
14 static int check_point_vs_average(int timeorder, int numtimeorders, PFTYPE *lpflag, FTYPE *pb, FTYPE *pf, FTYPE *upoint, FTYPE *uavg, struct of_geom *ptrgeom, struct of_newtonstats *newtonstats);
15 
16 
17 
18 static int prepare_globaldt(
19  int truestep,
20  FTYPE ndt1,FTYPE ndt2,FTYPE ndt3,
21  FTYPE accdt,int accdti,int accdtj,int accdtk,
22  FTYPE gravitydt,int gravitydti,int gravitydtj,int gravitydtk,
23  FTYPE *ndt);
24 
25 
26 //FTYPE globalgeom[NPR];
27 static void flux2dUavg(int whichpl, int i, int j, int k, FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE *dUavg1,FTYPE *dUavg2,FTYPE *dUavg3);
28 static void dUtoU(int timeorder, int whichpl, int i, int j, int k, int loc, FTYPE *dUgeom, FTYPE (*dUcomp)[NPR], FTYPE *dUriemann, FTYPE *CUf, FTYPE *CUnew, FTYPE *Ui, FTYPE *uf, FTYPE *ucum);
29 static void dUtoU_check(int timeorder, int i, int j, int k, int loc, int pl, FTYPE *dUgeom, FTYPE (*dUcomp)[NPR], FTYPE *dUriemann, FTYPE *CUf, FTYPE *CUnew, FTYPE *Ui, FTYPE *Uf, FTYPE *ucum);
30 static int asym_compute_1(FTYPE (*prim)[NSTORE2][NSTORE3][NPR]);
31 static int asym_compute_2(FTYPE (*prim)[NSTORE2][NSTORE3][NPR]);
32 
33 
34 static FTYPE fractional_diff( FTYPE a, FTYPE b );
35 
36 static FTYPE compute_dissmeasure(int timeorder, int i, int j, int k, int loc, FTYPE *pr, struct of_geom *ptrgeom, struct of_state *q, FTYPE *CUf, FTYPE *CUnew, FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE *Ui, FTYPE *Uf, FTYPE *tempucum);
37 
38 
39 // AVG_2_POINT functions:
40 static void debugeno_compute(FTYPE (*p)[NSTORE2][NSTORE3][NPR],FTYPE (*U)[NSTORE2][NSTORE3][NPR],FTYPE (*debugvars)[NSTORE2][NSTORE3][NUMENODEBUGS]);
41 
42 static void show_fluxes(int i, int j, int k, int loc, int pl,FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL]);
43 
44 
45 static int advance_standard(int truestep,int stage, FTYPE (*pi)[NSTORE2][NSTORE3][NPR],FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*pf)[NSTORE2][NSTORE3][NPR],
46  FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],
47  FTYPE (*pl_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pr_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP],
48  FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL],
50  FTYPE (*ui)[NSTORE2][NSTORE3][NPR], FTYPE (*uf)[NSTORE2][NSTORE3][NPR], FTYPE (*ucum)[NSTORE2][NSTORE3][NPR],
51  FTYPE *CUf,FTYPE *CUnew,SFTYPE fluxdt, SFTYPE boundtime, SFTYPE fluxtime, int stagenow, int numstages, FTYPE *ndt);
52 static int advance_standard_orig(int truestep,int stage, FTYPE (*pi)[NSTORE2][NSTORE3][NPR],FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*pf)[NSTORE2][NSTORE3][NPR],
53  FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],
54  FTYPE (*pl_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pr_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP],
55  FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL],
57  FTYPE (*ui)[NSTORE2][NSTORE3][NPR], FTYPE (*uf)[NSTORE2][NSTORE3][NPR], FTYPE (*ucum)[NSTORE2][NSTORE3][NPR],
58  FTYPE *CUf,FTYPE *CUnew,SFTYPE fluxdt, SFTYPE boundtime, SFTYPE fluxtime, int stagenow, int numstages, FTYPE *ndt);
59 static int advance_finitevolume(int truestep,int stage, FTYPE (*pi)[NSTORE2][NSTORE3][NPR],FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*pf)[NSTORE2][NSTORE3][NPR],
60  FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],
61  FTYPE (*pl_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pr_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP],
62  FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL],
64  FTYPE (*ui)[NSTORE2][NSTORE3][NPR],FTYPE (*uf)[NSTORE2][NSTORE3][NPR], FTYPE (*ucum)[NSTORE2][NSTORE3][NPR],
65  FTYPE *CUf,FTYPE *CUnew, SFTYPE fluxdt, SFTYPE boundtime, SFTYPE fluxtime, int stagenow, int numstages, FTYPE *ndt);
66 
67 
68 
69 
72 void pre_interpolate_and_advance(FTYPE (*pb)[NSTORE2][NSTORE3][NPR])
73 {
74 
76  //
77  // Compute and Store (globally) the get_state() data for the CENT position to avoid computing later and for merged-higher-order method
78  //
80 #if(STOREFLUXSTATE||STORESHOCKINDICATOR)
81  // NOTE: This is done before advance since always needed, and only needed once for all dimensions, and don't here instead of inside advance() since needed during fluxcalc() that is called first before any use of get_geometry() that we would use to put this call with
82  compute_and_store_fluxstatecent(pb);
83  // now flux_compute() and other flux-position-related things will obtain get_state() data for p_l and p_r from global arrays
84 #endif
85 
86 
87  // indicate to any needed piece of code that computed pre-interpolates if needed.
89 
90 }
91 
92 
102 int advance(int truestep, int stage, FTYPE (*pi)[NSTORE2][NSTORE3][NPR],FTYPE (*pb)[NSTORE2][NSTORE3][NPR], FTYPE (*pf)[NSTORE2][NSTORE3][NPR],
103  FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],
104  FTYPE (*pl_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pr_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP],
105  FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL],
107  FTYPE (*ui)[NSTORE2][NSTORE3][NPR],FTYPE (*uf)[NSTORE2][NSTORE3][NPR], FTYPE (*ucum)[NSTORE2][NSTORE3][NPR],
108  FTYPE *CUf, FTYPE *CUnew, SFTYPE fluxdt, SFTYPE boundtime, SFTYPE fluxtime, int timeorder, int numtimeorders, FTYPE *ndt)
109 {
110 
111 
113  //
114  // setup state and interpolation stuff for interpolation and advance calls
115  //
117  pre_interpolate_and_advance(pb);
118 
119 
120 
122  //
123  // advance
124  //
127  MYFUN(advance_finitevolume(truestep,stage,pi,pb,pf,pstag,pl_ct, pr_ct, F1, F2, F3, vpot,ui,uf,ucum,CUf,CUnew,fluxdt,boundtime,fluxtime,timeorder,numtimeorders,ndt),"advance.c:advance()", "advance_finitevolume()", 1);
128  }
130  // new standard preserves conserved quantities even when metric changes
131  // MYFUN(advance_standard_orig(truestep,stage,pi,pb,pf,pstag,pl_ct, pr_ct, F1, F2, F3, vpot,ui,uf,ucum,CUf,CUnew,fluxdt,boundtime,fluxtime,timeorder,numtimeorders,ndt),"advance.c:advance()", "advance_standard()", 1);
132  MYFUN(advance_standard(truestep,stage,pi,pb,pf,pstag,pl_ct, pr_ct, F1, F2, F3, vpot,ui,uf,ucum,CUf,CUnew,fluxdt,boundtime,fluxtime,timeorder,numtimeorders,ndt),"advance.c:advance()", "advance_standard()", 1);
133  }
134  else{
135  dualfprintf(fail_file,"No such DOENOFLUX=%d\n",DOENOFLUX);
136  myexit(1);
137  }
138 
139 
140  return(0);
141 
142 
143 }
144 
145 
146 
147 // Notes:
148 // loop range defined with +SHIFT? so consistent with requirement by IF3DSPCTHENMPITRANSFERATPOLE or consistent with setting upper face flux and using it, which is only used for FLUXBSTAG for evolving field on faces. This forces field on upper face to be evolved as required in some cases.
149 // This is bit excessive for non-face quantities, but fake partial evolution of centered value at "N" is ok as long as don't hit NaN's that slow down code.
150 
151 
152 
153 
154 
160 static int advance_standard(
161  int truestep,
162  int stage,
163  FTYPE (*pi)[NSTORE2][NSTORE3][NPR],
164  FTYPE (*pb)[NSTORE2][NSTORE3][NPR],
165  FTYPE (*pf)[NSTORE2][NSTORE3][NPR],
166  FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],
167  FTYPE (*pl_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pr_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP],
168  FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL],
170  FTYPE (*ui)[NSTORE2][NSTORE3][NPR],
171  FTYPE (*uf)[NSTORE2][NSTORE3][NPR],
172  FTYPE (*ucum)[NSTORE2][NSTORE3][NPR],
173  FTYPE *CUf,
174  FTYPE *CUnew,
175  SFTYPE fluxdt,
176  SFTYPE boundtime,
177  SFTYPE fluxtime,
178  int timeorder, int numtimeorders,
179  FTYPE *ndt)
180 {
181  FTYPE ndt1, ndt2, ndt3;
182  FTYPE dUtot;
183  FTYPE idx1,idx2;
184  SFTYPE dt4diag;
185  static SFTYPE dt4diag_willbe=0;
186  int finalstep,initialstep;
187  FTYPE accdt, accdt_ij;
188  int accdti,accdtj,accdtk;
189  FTYPE gravitydt, gravitydt_ij;
190  int gravitydti,gravitydtj,gravitydtk;
191  // FTYPE (*dUriemannarray)[NSTORE2][NSTORE3][NPR];
192  FTYPE (*ucumformetric)[NSTORE2][NSTORE3][NPR];
193  int enerregion;
194  int *localenerpos;
195  int jj;
196  FTYPE (*utoinvert)[NSTORE2][NSTORE3][NPR];
197  FTYPE *utoinvert1;
198  FTYPE (*tempucum)[NSTORE2][NSTORE3][NPR];
199  FTYPE (*useducum)[NSTORE2][NSTORE3][NPR];
200  FTYPE *useducum1;
201  FTYPE (*preupoint)[NSTORE2][NSTORE3][NPR];
202  FTYPE (*myupoint)[NSTORE2][NSTORE3][NPR];
203  FTYPE *myupoint1;
204  FTYPE (*myupointuf)[NSTORE2][NSTORE3][NPR];
205  FTYPE (*olduf)[NSTORE2][NSTORE3][NPR];
206  int whichpltoavg[NPR];
207  int ifnotavgthencopy[NPR];
208  int is,ie,js,je,ks,ke;
209  int doingextrashiftforstag;
210 
211 
212 
213 
214  if((GLOBALBCMOVEDWITHACTIVESECTION==0 || USEMPI) && truestep && DOGRIDSECTIONING){
215  // then need to fill pf with pi everywhere in global region, so that non-ACTIVE region will be set for boundary conditions within the domain.
216  int i,j,k,pliter,pl;
217  LOOPF{
218  PLOOP(pliter,pl) MACP0A1(pf,i,j,k,pl) = MACP0A1(pi,i,j,k,pl);
219  }
220  }
221 
222 
223  if(FLUXB==FLUXCTSTAG){
224  // fill in tempucum with changes that are not controlled well in space, but later fill in ucum from this in controlled way
225  tempucum=GLOBALPOINT(utemparray);
226  useducum=tempucum; // unless changed
227  }
228  else{
229  // no special shifting of indices occurs that requires loop shifting
230  tempucum=ucum;
231  useducum=ucum;
232  }
233  olduf=GLOBALPOINT(oldufstore);
234 
235 
236  ucumformetric=GLOBALPOINT(ucumformetric);// temporary space for ucum for metric that is same time as "pb", so not updated yet or is ui
237 
238 
239 
241  //
242  // Setup function tasks
243  //
245 
246 
247  // for ZLOOP:
248  // avoid looping over region outside active+ghost grid
249  // good because somewhat general and avoid bad inversions, etc.
250  enerregion=TRUEGLOBALWITHBNDENERREGION;
251  localenerpos=enerposreg[enerregion];
252 
253 
254  accdt=BIG; // initially no limit to dt due to acceleration
255  accdti=accdtj=accdtk=-100;
256  gravitydt=BIG; // initially no limit to dt due to time derivatives in gravity
257  gravitydti=gravitydtj=gravitydtk=-100;
258 
259 
260 
261 
262 
264  //
265  // set initialstep and finalstep to tell some procedures and diagnostic functions if should be accounting or not
266  //
268  if(timeorder==0){
269  initialstep=1;
270  }
271  else{
272  initialstep=0;
273  }
274 
275  if(timeorder==numtimeorders-1){
276  finalstep=1;
277  }
278  else{
279  finalstep=0;
280  }
281 
282 
284  //
285  // whether need to compute flux
286  // only compute flux if flux is added to get Uf or Ucum
288  int doflux = (CUf[2]!=0.0 || CUnew[1]!=0.0); // in reality, only do flux if CUf[2]!=0 as CUnew is just to accumulate to get U^{n+1}
289  // current implicit dt factor
290  // Since we don't pass CUnew[NUMPREDTCUFS+timeorder], we assume never try to add M^i into U^{n+1} unless computed for current U^i or previous U^i
291  FTYPE *CUimp=&CUf[NUMPREDTCUFS+timeorder];
292 
293 
295  //
296  // set dt4diag for source diagnostics
297  //
299  if(timeorder==numtimeorders-1 && (nstep%DIAGSOURCECOMPSTEP==0) ){
300  // every 4 full steps as well as on final step of full step (otherwise diag_source_comp() too expensive)
301  dt4diag=dt4diag_willbe;
302  dt4diag_willbe=0;
303  }
304  else{
305  dt4diag_willbe+=dt;
306  dt4diag=-1.0;
307  }
308 
309 
310 
312  //
313  // Setup loops [+1 extra compared to normal comp region if doing FLUXCTSTAG]
314  //
316  get_flux_startendindices(Uconsevolveloop,&is,&ie,&js,&je,&ks,&ke);
317 
318 
319 
321  //
322  // Set initial ui, temporary space, so ok that COMPZLOOP() goes over +1 in FLUXB==FLUXCTSTAG case
323  //
325  if(timeorder==0){
326  // last timestep's final ucum is stored into ucumformetric and ui as initial term in ucum
327  // copy ucum -> {ucumformetric,ui}
328  if(doingmetricsubstep()) copy_3dnpr_2ptrs(is,ie,js,je,ks,ke,ucum,ucumformetric,ui);
329  else copy_3dnpr(is,ie,js,je,ks,ke,ucum,ui); // only need to setup ui then
330  }
331  else{
332  // preserve this time's value of ucum for the metric (for timeorder==0 ucumformetric is assigned from ui)
333  // copy ucum -> ucumformetric
334  if(doingmetricsubstep()) copy_3dnpr(is,ie,js,je,ks,ke,ucum,ucumformetric);
335  }
336 
337 
338 
340  //
341  // Compute flux
342  //
344 
345 #if(PRODUCTION==0)
346  trifprintf( "#0f");
347 #endif
348 
349 
350 
351 
352  ndt1=ndt2=ndt3=BIG; // if doflux==0 or truestep==0, then setting ndt=BIG means doesn't affect any other sub-steps or steps that are trying to set dt as minimum over sub-step dt's.
353  if(doflux && truestep){ // only do if not just passing through
354  if(1){
355  // NORMAL:
356  // pb used here on a stencil, so if pb=pf or pb=pi in pointers, shouldn't change pi or pf yet -- don't currently
357  MYFUN(fluxcalc(stage,initialstep,finalstep,pb,pstag,pl_ct, pr_ct, vpot,F1,F2,F3,CUf,CUnew,fluxdt,fluxtime,&ndt1,&ndt2,&ndt3),"advance.c:advance_standard()", "fluxcalcall", 1);
358  }
359  }// end if not just passing through
360  // from here on, pi/pb/pf are only used a zone at a time rather than on a stencil
361 
362 
363 
364 #if(PRODUCTION==0)
365  trifprintf( "1f");
366 #endif
367 
368 
369 
370 
371 
372 
375  //
376  // now update get flux update [loop should go over normal computational region +1 on outer edges so automatically set field if staggered. Since we only set tempucum so far, ucum in that +1 region is unaffected]
377  //
379 
380 
381  int didreturnpf;
382  if(truestep){
383 
384 
385  // initialize uf and ucum if very first time here since ucum is cumulative (+=) [now tempucum is cumulative]
386  // copy 0 -> {uf,tempucum,olduf}
387  if(timeorder==0) init_3dnpr_3ptrs(is, ie, js, je, ks, ke,0.0, uf,tempucum,olduf);
388 
389 
390 
391 #if(WHICHEOM==WITHNOGDET && (NOGDETB1==1 || NOGDETB2==1 || NOGDETB3==1) )
392  // for FLUXB==FLUXCTSTAG, assume no source term for field
393  if(FLUXB==FLUXCTSTAG){
394  dualfprintf(fail_file,"Not setup for field source term if staggered field\n");
395  myexit(176023);
396  }
397 #endif
398 
399 
400 
401 
403  //
404  // FIRST UPDATE FIELD using its flux
405  //
407  int doother=DOALLPL; // default
408  if(FLUXB==FLUXCTSTAG){
409  doother=DONONBPL;
410 
411  // then field version of ui[] is stored as "conserved" value at FACE, not CENT
412  //PLOOPBONLY(pl) MACP0A1(ui,i,j,k,pl) is itself // FACE (see step_ch.c's setup_rktimestep and know that ui=unew for before first substep)
413 
414  if(NOGDETB1 ||NOGDETB2 ||NOGDETB3){
415  dualfprintf(fail_file,"This approach requires B have no source terms.\n");
416  myexit(34983463);
417  }
418 
419 #pragma omp parallel // OPENMPGLOBALPRIVATEFORINVERSION // don't need EOS stuff here since not getting state or doing inversion yet.
420  {
421  int pl,pliter,i,j,k;
422  // zero-out dUgeom in case non-B pl's used.
423  FTYPE dUgeom[NPR]={0.0},dUriemann[NPR+NSPECIAL]={0.0},dUriemann1[NPR+NSPECIAL]={0.0},dUriemann2[NPR+NSPECIAL]={0.0},dUriemann3[NPR+NSPECIAL]={0.0};
424  FTYPE dUcomp[NUMSOURCES][NPR];
425  int sc;
426  PLOOP(pliter,pl) SCLOOP(sc) dUcomp[sc][pl]=0.0;
427 
428 
430  // [Loop goes over up to +1 normal computational region for getting new staggered U if doing FLUXCTSTAG] so can do interpolation on it to get centered field
432  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
433 
434 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
436  OPENMP3DLOOPBLOCK2IJK(i,j,k);
437 
438  // dUriemann is actually average quantity, but we treat is as a point quantity at the zone center
439  if(doflux){
440  flux2dUavg(DOBPL,i,j,k,F1,F2,F3,dUriemann1,dUriemann2,dUriemann3);
441  PLOOPBONLY(pl) dUriemann[pl]=dUriemann1[pl]+dUriemann2[pl]+dUriemann3[pl]; // this addition is one type of avg->point mistake
442  }
443  else PLOOPBONLY(pl) dUriemann[pl]=0.0;
444 
445  // Get update
446  // ui is itself at FACE as already set
447  // this overwrites uf[B1,B2,B3], while need original uf[B1,B2,B3] for some RK methods, so store as olduf outside this loop, already.
448  dUtoU(timeorder,DOBPL,i,j,k,CENT,dUgeom, dUcomp, dUriemann, CUf, CUnew, MAC(ui,i,j,k), MAC(uf,i,j,k), MAC(tempucum,i,j,k));
449  if(finalstep==0){
450  PLOOP(pliter,pl) if(BPL(pl)) MACP0A1(olduf,i,j,k,pl) = MACP0A1(uf,i,j,k,pl);
451  }
452 
453  }//end loop
454  }// end parallel
455 
456 
457 
458  // first copy over all quantities as point, which is true except for fields if FLUXRECON active
459  // copy utoinvert -> myupoint
460  // only copy magnetic field pl's -- later copy rest when needed for inversion
461  // KORALNOTE: For general RK method, need to feed-into implicit solver field from Uf, not tempucum. So seems I need both fields to be processed for such RK methods. One for actual final field, and one for "initial+flux" form into implicit solver that just contributes to tempucum.
462 
463  // if using staggered grid for magnetic field, then need to convert ucum to pstag to new pb/pf
464  // GODMARK: Use of globals
465  myupoint=GLOBALPOINT(upointglobal);
466 
467  if(1){ // normal switching case
468 
469  if(finalstep==1) preupoint=tempucum;
470  else preupoint=uf;
471 
472  copy_tempucum_finalucum(DOBPL,Uconsevolveloop,preupoint,myupoint);
473 
474  // uses tempucum and gets reaveraged field into myupoint
475  if(extrazones4emf && dofluxreconevolvepointfield==0) field_integrate_fluxrecon(stage, pb, preupoint, myupoint);
476 
477  // first pb entry is used for shock indicator, second is filled with new field
478  // myupoint goes in as staggered point value of magnetic flux and returned as centered point value of magnetic flux
479  interpolate_ustag2fieldcent(stage, boundtime, timeorder, numtimeorders, pb, pstag, myupoint, NULL);
480  }
481 
482  // special higher-time-order uf-always calculation of field for when final ucum is different from final uf
483  // if CUnew[2]==1 on final step, then means Uf we compute is same as ucum.
484  if(finalstep==1 && CUnew[2]!=1.0){
485 
486  // still have to do uf calculation
487  myupointuf=GLOBALPOINT(upointglobaluf);
488  // get other non-field things in case used
489  // NO, not used, so can avoid.
490  // int pliter;
491  // // NOT RIGHT, shoud full copy: PLOOP(pliter,pl) MACP0A1(myupointuf,i,j,k,pl) = MACP0A1(myupoint,i,j,k,pl);
492 
493  preupoint=uf;
494 
495  copy_tempucum_finalucum(DOBPL,Uconsevolveloop,preupoint,myupointuf);
496 
497  // uses tempucum and gets reaveraged field into myupointuf
498  if(extrazones4emf && dofluxreconevolvepointfield==0) field_integrate_fluxrecon(stage, pb, preupoint, myupointuf);
499 
500  // first pb entry is used for shock indicator, second is filled with new field
501  // myupointuf goes in as staggered point value of magnetic flux and returned as centered point value of magnetic flux
502  interpolate_ustag2fieldcent(stage, boundtime, timeorder, numtimeorders, pb, pstag, myupointuf, NULL);
503 
504  }
505  else{
506  // then no need for separate myupointuf, so just point to same space
507  myupointuf=myupoint;
508  }
509 
510 
512  // now myupoint contain CENTered point conserved (to be converted to primitive quantity later) ready for MHD or RAD inversion procedures (or implicit use of such inversions)
513  // myupointuf contains always uf version of field
514  // myupoint constains uf version except for finalstep=1, when it contains tempucum version
516 
517  }// end if staggered field method
518 
519 
520 
521 
522 
523  // get loop range (only needs to be over same location as final centered primitive to invert.
524  get_inversion_startendindices(Uconsevolveloop,&is,&ie,&js,&je,&ks,&ke);
525 
526 
528  //
529  // UPDATE NON_FIELD using flux and source
530  // PERFORM INVERSION
531  // DO FIXUP1ZONE
532  //
534 #pragma omp parallel OPENMPGLOBALPRIVATEFORSTATEANDGEOM // <-- only includes more than OPENMPGLOBALPRIVATEFORINVERSION needed for inversion
535  {
536  int pl,pliter,i,j,k;
537  struct of_geom geomdontuse;
538  struct of_geom *ptrgeom=&geomdontuse;
539 
540  // for source()
541  FTYPE Uitemp[NPR];
542  // set all to zero in case doother=DONONBPL in which case need rest of calculations to know no change to field
543  FTYPE dUgeom[NPR]={0},dUriemann[NPR]={0},dUriemann1[NPR+NSPECIAL]={0},dUriemann2[NPR+NSPECIAL]={0},dUriemann3[NPR+NSPECIAL]={0},dUcomp[NUMSOURCES][NPR]={{0}};
544  struct of_state qdontuse;
545  struct of_state *qptr=&qdontuse;
546  struct of_state qdontuse2;
547  struct of_state *qptr2=&qdontuse2; // different qptr since call normal and special get_state()
548 
549 
550  // for inversion
551  FTYPE prbefore[NPR];
552  struct of_newtonstats newtonstats; setnewtonstatsdefault(&newtonstats);
553  int showmessages=1;
554  int allowlocalfailurefixandnoreport=1; // allow local fixups
555  // initialize counters
556  newtonstats.nstroke=newtonstats.lntries=0;
557  int eomtype;
558 
559 
560 
561  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
562 
563 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
565  OPENMP3DLOOPBLOCK2IJK(i,j,k);
566 
567  // setup default eomtype
568  eomtype=EOMDEFAULT;
569 
570 
571  // set geometry for centered zone to be updated
572  get_geometry(i, j, k, CENT, ptrgeom);
573 
574  // find Ui(pi)
575  // force use of primitive to set Ui since otherwise wherever corrected/changed primitive (in fixup, etc.) then would have to change conserved quantity, while same since both are point values
576  // only field for staggered method is special point value at faces that needs to come from conserved quantity
577  MYFUN(get_state(MAC(pi,i,j,k), ptrgeom, qptr),"step_ch.c:advance()", "get_state()", 1);
578  MYFUN(primtoU(UEVOLVE,MAC(pi,i,j,k), qptr, ptrgeom, Uitemp, NULL),"step_ch.c:advance()", "primtoU()", 1);
579 
580  if(FLUXB==FLUXCTSTAG || DOENOFLUX != NOENOFLUX ){
581  // then field version of ui[] is stored as "conserved" value at FACE, not CENT
582  PLOOPNOB1(pl) MACP0A1(ui,i,j,k,pl)=Uitemp[pl]; // CENT
583  //PLOOPBONLY(pl) MACP0A1(ui,i,j,k,pl) is itself // FACE (see step_ch.c's setup_rktimestep and know that ui=unew for before first substep)
584  PLOOPNOB2(pl) MACP0A1(ui,i,j,k,pl)=Uitemp[pl]; // CENT
585  }
586  else{
587  PLOOP(pliter,pl) MACP0A1(ui,i,j,k,pl)=Uitemp[pl]; // all at CENT
588  }
589 
590  // if(myid==5 && nstep==1 && steppart==0 && ptrgeom->i==19 && ptrgeom->j==15){
591  // PLOOP(pliter,pl) dualfprintf(fail_file,"pl=%d pi=%21.15g ui=%21.15g\n",MACP0A1(pi,i,j,k,pl),MACP0A1(ui,i,j,k,pl)*ptrgeom->igdetnosing);
592  // }
593 
594  // dUriemann is actually average quantity, but we treat is as a point quantity at the zone center
595  if(doflux){
596  flux2dUavg(doother,i,j,k,F1,F2,F3,dUriemann1,dUriemann2,dUriemann3);
597  PLOOP(pliter,pl) dUriemann[pl]=dUriemann1[pl]+dUriemann2[pl]+dUriemann3[pl]; // this addition is one type of avg->point mistake
598  }
599  else{
600  PLOOP(pliter,pl) dUriemann[pl]=0.0;
601  }
602 
603  // save pi before it gets modified in case pf=pi or pf=pb as a pointer.
604  FTYPE piorig[NPR],pborig[NPR];
605  PALLLOOP(pl){
606  piorig[pl] = MACP0A1(pi,i,j,k,pl);
607  pborig[pl] = MACP0A1(pb,i,j,k,pl);
608  }
609 
610 
612  // Utoprim as initial conditions : can't assume want these to be same in the end, so assign
613  // MAJORNOTE: final step often sets pointers of pi=pf, in order to use arbitrary guess, so must set pf ONLY once pi is done being used.
614  // pb is probably closer than pi for inversion
616  PALLLOOP(pl) MACP0A1(pf,i,j,k,pl) = MACP0A1(pb,i,j,k,pl);
617  if(FLUXB==FLUXCTSTAG){
618  // then upoint actually contains centered updated field used for source() and starting point for more readily getting inversion
619  // myupointuf contains always uf version, not tempucum version, of updated field.
620  PLOOPBONLY(pl) MACP0A1(pf,i,j,k,pl)=MACP0A1(myupointuf,i,j,k,pl)*ptrgeom->igdetnosing; // valid for this setup of NOGDETB1/B2/B3==0
621  }
622 
623 
625  // get state since both source() and dUtodt() need same state
626  // From pb, so different than state for Ui(pi)
627  // Inside source() might use pb,pf,etc. to get new state.
628  MYFUN(get_stateforsource(pborig, ptrgeom, &qptr2) ,"advance.c:()", "get_state() dir=0", 1);
629 
630 
631  // note that uf and ucum are initialized inside setup_rktimestep() before first substep
632 
633  // get dissmeasure
634  FTYPE dissmeasure=compute_dissmeasure(timeorder,i,j,k,ptrgeom->p,MAC(pf,i,j,k),ptrgeom,qptr2,CUf, CUnew, F1, F2, F3, MAC(ui,i,j,k),MAC(olduf,i,j,k), MAC(tempucum,i,j,k)); // GODMARK: If doflux==0, then this actually uses old F's.
635 
636  // find dU(pb)
637  // so pf contains updated field at cell center for use in (e.g.) implicit solver that uses inversion P(U)
638  // Note that uf[B1,B2,B3] is already updated, but need to pass old uf for RK3/RK4, so use olduf.
639  MYFUN(source(piorig, pborig, MAC(pf,i,j,k), &didreturnpf, &eomtype, ptrgeom, qptr2, MAC(ui,i,j,k), MAC(olduf,i,j,k), CUf, CUimp,dissmeasure, dUriemann, dUcomp, dUgeom),"step_ch.c:advance()", "source", 1);
640  // assumes final dUcomp is nonzero and representative of source term over this timestep
641 
642 
643 
644 #if(SPLITNPR)
645  // don't update metric if only doing B1-B3
647 #endif
648  {
649  if(DODIAGS){
650 #if(ACCURATESOURCEDIAG>=1)
651  diag_source_all(ptrgeom,dUgeom,fluxdt);
652 #else
653  diag_source_all(ptrgeom,dUgeom,dt4diag);
654 #endif
655 #if(ACCURATESOURCEDIAG>=2)
656  diag_source_comp(ptrgeom,dUcomp,fluxdt);
657 #else
658  diag_source_comp(ptrgeom,dUcomp,dt4diag);
659 #endif
660  }
661  }
662 
663 
665  //
666  // Get update: tempucum
667  //
669  // PLOOP(pliter,pl) globalgeom[pl]=ptrgeom->gdet;
670  // ok to use "uf" here instead of "olduf" since field is not done here.
671  FTYPE ufconsider[NPR],tempucumconsider[NPR];
672  PLOOP(pliter,pl){
673  ufconsider[pl]=MACP0A1(olduf,i,j,k,pl);
674  tempucumconsider[pl]=MACP0A1(tempucum,i,j,k,pl);
675  }
676  dUtoU(timeorder,doother,i,j,k,ptrgeom->p,dUgeom, dUcomp, dUriemann, CUf, CUnew, MAC(ui,i,j,k), ufconsider, tempucumconsider);
677 
678  // KORALNOTE: field dUtoU loses previous time uf needed for RK3 and RK4, so need to store it for safe keeping
679  // this oldud is used for B1,B2,B3 and required in cases when CUf[1]!=0.0, as even TVD RK2 method needs because previous Uf used even for updating new Uf.
681  // Save uf here because below modify uf to account for floors.
682  // The later modification of uf is required for >=RK3 methods that use olduf
683  FTYPE origolduf[NPR];
684  if(doother==DONONBPL){
685  PLOOP(pliter,pl){
686  if(BPL(pl)==0){
687  origolduf[pl] = MACP0A1(olduf,i,j,k,pl);
688  MACP0A1(olduf,i,j,k,pl) = ufconsider[pl];
689  }
690  }
691  }
692  else if(doother==DOALLPL){
693  PLOOP(pliter,pl){
694  origolduf[pl] = MACP0A1(olduf,i,j,k,pl);
695  MACP0A1(olduf,i,j,k,pl) = ufconsider[pl];
696  }
697  }
698 
699 
701  // Choose what to invert
703  if(finalstep){
704  // invert ucum on final step
705  utoinvert = tempucum;
706  useducum=tempucum;
707 
708  utoinvert1 = tempucumconsider;
709  useducum1 = tempucumconsider;
710 
711  }
712  else{
713  // invert uf on substeps
714  utoinvert = uf; // should always be uf, not olduf.
715  // tempucum just cumulates for now
716  useducum=tempucum;
717 
718  utoinvert1 = ufconsider;
719  useducum1 = tempucumconsider;
720  }
721  if(FLUXB==FLUXCTSTAG){
722  // copy over evolved field. If finalstep=1, then myupoint contains ucum field as required. Else has uf field as required.
723  PLOOPBONLY(pl) utoinvert1[pl] = MACP0A1(myupoint,i,j,k,pl);
724  } // else already there as point centered quantity
725 
726 
727 
728 #if(0)
729 
730  // setup myupoint to invert
732  if(FLUXB==FLUXCTSTAG){
733  // already have field in myupoint, just copy the others over
734  PLOOP(pliter,pl) if(doother==DOALLPL || doother==DONONBPL && BPL(pl)==0 || doother==DOBPL && BPL(pl)==1) MACP0A1(myupoint,i,j,k,pl)=MACP0A1(utoinvert,i,j,k,pl);
735  }
736  else{
737  // utoinvert never reassigned from global a_utoinvert assignment since if here not doing FLUXCTSTAG
738  myupoint=utoinvert;
739  }
740  myupoint1=utoinvert1;
741 #endif
742 
744  // INVERT [loop only over "centered" cells]
745  //
746  // Utoprimgen() properly uses eomtype as potentially changed in source() call
747  //
749 
751  //
752  // if doing inversion, then check if should use entropy or energy if originally assuming should use energy
753  //
755  int eomtypelocal;
756  eomtypelocal=eomtype;
757 
758 
759 
761  //
762  // Setup and Do inversion
763  //
765  if(finalstep){ // last call, so ucum is cooked and ready to eat!
766  // store guess for diss_compute before changed by normal inversion
767  PALLLOOP(pl) prbefore[pl]=MACP0A1(pf,i,j,k,pl);
768 
769  if(CUnew[2]==1.0){
770  // then use original eomtypelocal
771  }
772  else{
773  // then Uf is not ucum on finalstep=1, so any prior implicit inversion was not final inversion.
774  // So change any do nothing to do something
775  if(eomtypelocal==EOMDIDGRMHD) eomtypelocal=EOMGRMHD;
776  else if(eomtypelocal==EOMDIDENTROPYGRMHD) eomtypelocal=EOMENTROPYGRMHD;
777  else if(eomtypelocal==EOMDIDCOLDGRMHD) eomtypelocal=EOMCOLDGRMHD;
778  else if(eomtypelocal==EOMDIDFFDE) eomtypelocal=EOMFFDE;
779  else if(eomtypelocal==EOMDIDFFDE2) eomtypelocal=EOMFFDE2;
780  }
781  }
782 
783 
784 
785  // actual inversion
786  int whichcap=CAPTYPEBASIC;
787  int whichmethod=MODEPICKBEST; // try to choose best option for this "external" inversion
788  int modprim=0;
789  int checkoninversiongas=CHECKONINVERSION;
790  int checkoninversionrad=CHECKONINVERSIONRAD;
791  MYFUN(Utoprimgen(showmessages,checkoninversiongas,checkoninversionrad,allowlocalfailurefixandnoreport, finalstep,&eomtypelocal,whichcap,whichmethod,modprim,EVOLVEUTOPRIM,UEVOLVE,utoinvert1, qptr2, ptrgeom, dissmeasure, piorig, MAC(pf,i,j,k),&newtonstats),"step_ch.c:advance()", "Utoprimgen", 1);
792  nstroke+=newtonstats.nstroke; newtonstats.nstroke=newtonstats.lntries=0;
793 
794 
795 #if(DODISS||DODISSVSR)
796  if(finalstep){
797  // then see what entropy inversion would give
798  diss_compute(EVOLVEUTOPRIM,UEVOLVE,utoinvert1,ptrgeom,prbefore,MAC(pf,i,j,k),&newtonstats);
799  }
800 #endif
801 
802 
803 
805  //
806  // Do fixup1zone and adjust dUriemann, uf, and tempucum
807  //
809 #if(SPLITNPR)
810  // don't update metric if only doing B1-B3
812 #endif
813  {
814  // immediate local (i.e. 1-zone) fix
815 #if(FIXUPZONES==FIXUP1ZONE)
816  // SUPERGODMARK: Below should differentiate beteween whether want negative densities fixed or not, but right now fixup1zone() does all
818  FTYPE utoinvertlocal[NPR];
819  PLOOP(pliter,pl) utoinvertlocal[pl] = utoinvert1[pl];
820  int docorrectucons=0;
821  int didfixup=fixup1zone(docorrectucons,MAC(pf,i,j,k),utoinvertlocal, ptrgeom,finalstep);
822  }// if might do fixups
823 #endif
824  }// end doing single-point fixups
825 
826 
827 
828 
830  //
831  // Save results to uf and tempucum (whether fixup or not)
832  //
834  PLOOP(pliter,pl){
835  // only save if not already updated uf and tempucum separately
836  if(doother==DOALLPL || doother==DONONBPL && BPL(pl)==0 || doother==DOBPL && BPL(pl)==1){
837  MACP0A1(uf,i,j,k,pl)=ufconsider[pl];
838  MACP0A1(tempucum,i,j,k,pl)=tempucumconsider[pl];
839  }
840  }
841 
842 
843 
844 
846  //
847  // get timestep limit from acceleration
848  //
850 #if(LIMITDTWITHSOURCETERM)
851 #if(SPLITNPR)
852  // don't do dUtodt if only doing B1-B3
854 #endif
855  {
856  // geometry is post-metric update, but should still give good estimate of future dt
857  dUtodt(ptrgeom, qptr2, MAC(pb,i,j,k), dUgeom, dUriemann, dUcomp[GEOMSOURCE], &accdt_ij, &gravitydt_ij);
858 
859 #pragma omp critical
860  {
861  if(accdt_ij<accdt){
862  accdt=accdt_ij;
863  accdti=i;
864  accdtj=j;
865  accdtk=k;
866  }
867  if(gravitydt_ij<gravitydt){
868  gravitydt=gravitydt_ij;
869  gravitydti=i;
870  gravitydtj=j;
871  gravitydtk=k;
872  }
873  }// end critical region
874  }// end block that may mean: if not only doing B1-B3
875 
876 #endif // end if doing LIMITDTWITHSOURCETERM
877 
878 
879 
880 
881  } // end COMPZLOOP :: end looping to obtain dUriemann and full unew update
882  }// end parallel block
883  } // end if truestep
884  else{
885  // then nothing to do since nothing changed
886  // previously updated dU and got new ucum as fed into metric, but now metric has its own ucummetric so all that is not needed
887  // SUPERGODMARK: no, I guess I don't recall what was being done for metric and why when passing through with dt==0.0
888 
889  // just need to copy ui -> {uf,tempucum} to duplicate behavior of dUtoU()
890  copy_3dnpr_2ptrs(is,ie,js,je,ks,ke,ui,uf,tempucum);
891  }
892 
893 
894 
895 
896 
897 #if(PRODUCTION==0)
898  trifprintf( "#0m");
899 #endif
900 
901 
902 
903 
904 
906  //
907  // EVOLVE (update/compute) METRIC HERE
908  // In general computes stress-energy tensor (T) from pb and T is then used to compute metric
909  // Done here instead of after flux since horizon_flux() updates flux through boundary that would change metric
910  // want metric to be at same time as everything else done with pb so RK method is consistent
911  //
912  // uses unew that's NOT updated yet
914  if(truestep){
915  if(doingmetricsubstep()){
916 #if(SPLITNPR)
917  // don't update metric if only doing B1-B3
919 #endif
920  {
921  compute_new_metric_substep(CUf,CUnew,pb,ucumformetric); // CHANGINGMARK : Not sure if CUnew here is correct
922  }
923  }// end if doing metric substepping
924  }
925 
926 
927 
928 
929 
931  //
932  // compute flux diagnostics (accurately using all substeps)
933  //
935  if(doflux && truestep){
936  // must come after metric changes that can change where flux surface is since otherwise when flux surface changes, we won't track this substep's flux through the new surface but the old surface (which could even be at r=0 and have no flux)
937  // if using unew, then since metric update above uses old unew, need present flux at new horizon surface
938 #if(SPLITNPR)
939  // don't update metric if only doing B1-B3
941 #endif
942  {
943 #if(ACCURATEDIAG)
944  diag_flux_pureflux(pb,F1, F2, F3, fluxdt); // fluxdt is true dt for this flux as added in dUtoU() as part of ucum
945 #endif
946  }
947  }
948 
949 
950 
951 #if(PRODUCTION==0)
952  trifprintf( "#0s");
953 #endif
954 
955 
956 
958  //
959  // Copy over tempucum -> ucum per pl to account for staggered field
960  //
962  if(finalstep && FLUXB==FLUXCTSTAG){
963  // copy over new ucum in only desired locations irrespective of where tempucum was updated
964  // copy tempucum -> ucum
965  copy_tempucum_finalucum(DOALLPL,Uconsevolveloop,tempucum,ucum); // fill-in all pl's for storage and for next step.
966  }
967 
968 
969 
970 
972  //
973  // If not fixing up primitives after inversion immediately, then fix up all zones at once afterwards
974  //
976 
977 #if(SPLITNPR)
978  // don't update metric if only doing B1-B3
980 #endif
981  {
982 #if(FIXUPZONES==FIXUPALLZONES)
983  // fixup(stage,pf,useducum,finalstep); // GODMARK: if want to correct useducum, then have to be more careful like when doing fixup1zone()
984  fixup(stage,pf,utoinvert,finalstep);
985 #endif
986  }
987 
988 
989 
991  //
992  // Determine next timestep from waves, fluxes, and source updates
993  //
995 
996 
997  prepare_globaldt(truestep,ndt1,ndt2,ndt3,accdt,accdti,accdtj,accdtk,gravitydt,gravitydti,gravitydtj,gravitydtk,ndt);
998 
999 
1000 
1001 #if(PRODUCTION==0)
1002  trifprintf( "2f");
1003 #endif
1004 
1005 
1006  return (0);
1007 }
1008 
1009 
1010 
1011 
1012 
1013 
1014 
1015 
1016 
1017 
1019 static FTYPE compute_dissmeasure(int timeorder, int i, int j, int k, int loc, FTYPE *pr, struct of_geom *ptrgeom, struct of_state *q, FTYPE *CUf, FTYPE *CUnew, FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL], FTYPE *ui, FTYPE *uf, FTYPE *tempucum)
1020 {
1021  FTYPE dissmeasure;
1022  int pliter,pl;
1023 
1024  if(DODISSMEASURE==0) return(-1.0);
1025 
1026  if(NSPECIAL>0){
1027  FTYPE dUgeomtemp[NPR+NSPECIAL];
1028  FTYPE uitemp[NPR+NSPECIAL];
1029  FTYPE uftemp[NPR+NSPECIAL];
1030  FTYPE tempucumtemp[NPR+NSPECIAL];
1031  PLOOP(pliter,pl){
1032  dUgeomtemp[pl]=0.0; // geometry not relevant for this calculation
1033  uitemp[pl]=ui[pl];
1034  uftemp[pl]=uf[pl];
1035  tempucumtemp[pl]=tempucum[pl];
1036  }
1037  //
1038  int plsp;
1039  int specialfrom;
1040  int truenspecial=0;
1041 #if(NSPECIAL==6)
1042 
1043 #if(EOMRADTYPE!=EOMRADNONE)
1045  truenspecial=NSPECIAL;
1046 #else
1048  truenspecial=5;
1049 #endif
1050 
1051 #elif(NSPECIAL==2)
1052  int plspeciallist[NSPECIAL]={SPECIALPL1,SPECIALPL2};
1053  truenspecial=NSPECIAL;
1054 #elif(NSPECIAL==1)
1055  int plspeciallist[NSPECIAL]={SPECIALPL1};
1056  truenspecial=NSPECIAL;
1057 #endif
1058  PLOOPSPECIALONLY(plsp,truenspecial){
1059  specialfrom=plspeciallist[plsp-NPR];
1060  dUgeomtemp[plsp]=0.0;
1061  uitemp[plsp] = uitemp[specialfrom];
1062  uftemp[plsp] = uftemp[specialfrom];
1063  tempucumtemp[plsp] = tempucumtemp[specialfrom];
1064  }
1065  //
1066  FTYPE dUriemanntemp[NPR+NSPECIAL]={0},dUriemann1temp[NPR+NSPECIAL]={0},dUriemann2temp[NPR+NSPECIAL]={0},dUriemann3temp[NPR+NSPECIAL]={0};
1067  //
1068  // get flux update for all NPR and NSEPCIAL quantities
1069  flux2dUavg(DOSPECIALPL,i,j,k,F1,F2,F3,dUriemann1temp,dUriemann2temp,dUriemann3temp);
1070  //
1071  // get dUriemann for NPR and truenspecial quantities
1072  PLOOP(pliter,pl) dUriemanntemp[pl]=dUriemann1temp[pl]+dUriemann2temp[pl]+dUriemann3temp[pl];
1073  PLOOPSPECIALONLY(plsp,truenspecial){
1074  dUriemanntemp[plsp]=dUriemann1temp[plsp]+dUriemann2temp[plsp]+dUriemann3temp[plsp];
1075  }
1076  // Get final U for NPR and NSPECIAL quantities
1077  // FTYPE dUcomptemp[NUMSOURCES][NPR+NSPECIAL];
1078  FTYPE dUcomptemp[NUMSOURCES][NPR];
1079  int sc;
1080  PLOOP(pliter,pl) SCLOOP(sc) dUcomptemp[sc][pl]=0.0;
1081  // PLOOPSPECIALONLY(plsp,truenspecial){
1082  // SCLOOP(sc) dUcomptemp[sc][plsp]=0.0;
1083  // }
1084  dUtoU(timeorder,DOSPECIALPL,i,j,k,loc,dUgeomtemp, dUcomptemp, dUriemanntemp, CUf, CUnew, uitemp, uftemp, tempucumtemp);
1085 
1086 
1087 
1089  //
1090  // now get dissipation measure. dissmeasure<0.0 means dissipation occuring (e.g. in density field)
1091  //
1093 
1094  // First, get dUnondiss and dUdiss and norm
1095  FTYPE dUdissplusnondiss[NPR];
1096  FTYPE dUnondiss[NPR];
1097  FTYPE dUdiss[NPR];
1098  FTYPE dissmeasurepl[NPR];
1099  FTYPE signdiss;
1100  FTYPE norm[NPR];
1101  PLOOPSPECIALONLY(plsp,truenspecial){
1102  specialfrom=plspeciallist[plsp-NPR];
1103  dUdissplusnondiss[specialfrom]=(uftemp[specialfrom] - uitemp[specialfrom]);
1104  dUnondiss[specialfrom]=(uftemp[plsp] - uitemp[plsp]);
1105  dUdiss[specialfrom]=dUdissplusnondiss[specialfrom] - dUnondiss[specialfrom];
1106 
1107  norm[specialfrom]=SMALL+(fabs(dUdiss[specialfrom])+fabs(dUnondiss[specialfrom]));
1108  }
1109 
1110  // get actual norm that's over multiple components for the magentic field
1111  FTYPE actualnorm[NPR];
1112  PLOOPSPECIALONLY(plsp,truenspecial){
1113  specialfrom=plspeciallist[plsp-NPR];
1114  if(specialfrom==RHO || specialfrom==UU){
1115  actualnorm[specialfrom] = SMALL + norm[specialfrom];
1116  }
1117  else if(specialfrom==B1 || specialfrom==B2 || specialfrom==B3){
1118  // for magnetic field, actualnorm is computed as:
1119  // |dUdiss(B1)|^2 |dUnondiss(B1)|^2 + |dUdiss(B2)|^2 + |dUnondiss(B2)|^2 + |dUdiss(B3)|^2 + |dUnondiss(B3)|^2 + |dUdiss(UU)| + |dUnondiss(UU)|
1120  // So we account for any magnetic energy change and help with normalization by also using total energy change
1121  actualnorm[specialfrom]=0.0;
1122  int jj;
1123  SLOOPA(jj){
1124  pl=B1+jj-1;
1125  actualnorm[specialfrom] += SMALL+(fabs(dUdiss[pl]*dUdiss[pl])+fabs(dUnondiss[pl]*dUnondiss[pl]));
1126  }
1127  actualnorm[specialfrom] += fabs(dUdiss[UU]) + fabs(dUnondiss[UU]); // add energy as reference for normalization to avoid weak magnetic fields suggesting strong dissipation. GODMARK: But, kinda risky, because nominally want to use energy to capture any field dissipation, not just when the field is important to total energy dissipation.
1128  // But much better than (say) using total energy density as reference. We use actual energy dissipation as reference. So if reconnection is at all important to total dissipation, it will be accounted for. When total energy dissipation is dominated by non-reconnection, that missed dissipation is a small correction.
1129  // But, because total energy dissipation is less trustable due to average vs. point issue in general creating artificial heating or cooling, this is a bit less trustable as even a normalization.
1130  }
1131  else if(specialfrom==URAD0){
1132  actualnorm[specialfrom] = SMALL + norm[specialfrom];
1133  }
1134  }
1135 
1137  //
1138  // compute dissmeasure for each quantity using actualnorm
1139  //
1141  PLOOPSPECIALONLY(plsp,truenspecial){
1142  specialfrom=plspeciallist[plsp-NPR];
1143 
1144  // set sign in front of dissmeasure
1145  if(specialfrom==RHO) signdiss=+1.0; // dUdiss>0 means adding density due to dissipation (i.e. convergence, not divergence)
1146  else if(specialfrom==UU) signdiss=-1.0; // dUdiss<0 means adding energy due to dissipation (i.e. dissipation)
1147  else if(specialfrom==B1 || specialfrom==B2 || specialfrom==B3) signdiss=-1.0; // dUdiss<0 means lost magentic energy due to dissipation (i.e. dissipation)
1148  else if(specialfrom==URAD0) signdiss=-1.0; // dUdiss<0 means adding energy due to dissipation (i.e. dissipation)
1149 
1150  // get dissmeasure, which is normalized dUdiss with correct sign
1151  if(specialfrom==RHO || specialfrom==UU || specialfrom==URAD0){
1152  // standard dUdiss/actualnorm
1153  dissmeasurepl[specialfrom] = -signdiss*(dUdiss[specialfrom])/actualnorm[specialfrom];
1154  }
1155  else if(specialfrom==B1 || specialfrom==B2 || specialfrom==B3){
1156  // special use of square of dUdiss: dUdiss^2(B1,B2,B3)/actualnorm
1157  dissmeasurepl[specialfrom] = -signdiss*(sign(dUdiss[specialfrom])*dUdiss[specialfrom]*dUdiss[specialfrom])/actualnorm[specialfrom];
1158  }
1159 
1160  // dualfprintf(fail_file,"plsp=%d specialfrom=%d dissmeasurepl=%g\n",plsp,specialfrom,dissmeasurepl[specialfrom]);
1161 
1162  // dualfprintf(fail_file,"DISS (ijk=%d %d %d): (%d %d) ui=%g %g : uf=%g %g : dUdiss=%g dUnondiss=%g : dU1=%g %g : dU2=%g %g : dissmeasure=%g\n",i,j,k,specialfrom,plsp,uitemp[specialfrom],uitemp[plsp],uftemp[specialfrom],uftemp[plsp],dUdiss,dUnondiss,dUriemann1temp[specialfrom]*CUf[2]*dt,dUriemann1temp[plsp]*CUf[2]*dt,dUriemann2temp[specialfrom]*CUf[2]*dt,dUriemann2temp[plsp]*CUf[2]*dt,dissmeasure);
1163 
1164  // DEBUG
1165  if(DODISSMEASURE){
1166  GLOBALMACP0A1(dissmeasurearray,i,j,k,plsp-NPR)=dissmeasurepl[specialfrom];
1167  }
1168 
1169  }
1170 
1172  //
1173  // Choose which *total* dissipation measurement to use. Must somehow combine different original equations of motion into a single measure since energy vs. entropy changes involve energy equation that combines both shocks and reconnection.
1174  //
1176  if(truenspecial==1){
1177  dissmeasure=dissmeasurepl[SPECIALPL1];
1178  }
1179  // Can't trust energy, since average vs. point issue itself leads to erreoneous apparent dissipation (which when using energy equation alone is what leads to inappropriate heating in divergent flows, as well as inappropriate cooling in divergent flows, often in stripes in u_g due to sensitivity to higher-order interpolation schemes like PPM).
1180  // dissmeasure=dissmeasurepl[SPECIALPL2];
1181  else if(truenspecial>=5){
1182  // can't trust energy, but density doesn't account for magnetic energy. So use density for shocks and magnetic energy flux for reconnection.
1183  dissmeasure=dissmeasurepl[SPECIALPL1];
1184 
1185  FTYPE dissmeasurefield=dissmeasurepl[B1];
1186  dissmeasurefield=MIN(dissmeasurefield,dissmeasurepl[B2]);
1187  dissmeasurefield=MIN(dissmeasurefield,dissmeasurepl[B3]);
1188 
1189  // add field dissipation measure, but only account if above machine error (i.e. relative to total energy as defined above)
1190  dissmeasure=MIN(dissmeasure,10.0*NUMEPSILON+dissmeasurefield);
1191 
1192  if(truenspecial>=6 && SPECIALPL6>=0){
1193  // add radiation pressure to total pressure if optically thick
1194  FTYPE tautot[NDIM],tautotmax;
1195  calc_tautot(pr, ptrgeom, NULL, tautot, &tautotmax); // high accuracy not required
1196 
1197  FTYPE dissswitch=MIN(tautotmax/TAUTOTMAXSWITCH,1.0);
1198 
1199  dissmeasure = MIN(dissmeasure,dissmeasurepl[SPECIALPL6])*dissswitch + dissmeasure*(1.0-dissswitch);
1200  }
1201  }
1202 
1203  if(truenspecial>0 && DODISSMEASURE){
1204  // DEBUG
1205  GLOBALMACP0A1(dissmeasurearray,ptrgeom->i,ptrgeom->j,ptrgeom->k,NSPECIAL)=dissmeasure;
1206  }
1207 
1208 
1209  }
1210 
1211  dissmeasure=-1.0; // force use of energy unless energy fails.
1212 
1213  return(dissmeasure);
1214 }
1215 
1216 
1217 
1218 
1219 
1220 
1221 
1222 
1223 
1224 
1225 
1226 
1227 
1228 
1229 
1230 
1231 
1236  int truestep,
1237  int stage,
1238  FTYPE (*pi)[NSTORE2][NSTORE3][NPR],
1239  FTYPE (*pb)[NSTORE2][NSTORE3][NPR],
1240  FTYPE (*pf)[NSTORE2][NSTORE3][NPR],
1241  FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],
1242  FTYPE (*pl_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pr_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP],
1243  FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL],
1245  FTYPE (*ui)[NSTORE2][NSTORE3][NPR],
1246  FTYPE (*uf)[NSTORE2][NSTORE3][NPR],
1247  FTYPE (*ucum)[NSTORE2][NSTORE3][NPR],
1248  FTYPE *CUf,
1249  FTYPE *CUnew,
1250  SFTYPE fluxdt,
1251  SFTYPE boundtime,
1252  SFTYPE fluxtime,
1253  int timeorder, int numtimeorders,
1254  FTYPE *ndt)
1255 {
1256  FTYPE ndt1, ndt2, ndt3;
1257  FTYPE dUtot;
1258  FTYPE idx1,idx2;
1259  SFTYPE dt4diag;
1260  static SFTYPE dt4diag_willbe=0;
1261  int finalstep,initialstep;
1262  FTYPE accdt, accdt_ij;
1263  int accdti,accdtj,accdtk;
1264  FTYPE gravitydt, gravitydt_ij;
1265  int gravitydti,gravitydtj,gravitydtk;
1266  // FTYPE (*dUriemannarray)[NSTORE2][NSTORE3][NPR];
1267  FTYPE (*ucumformetric)[NSTORE2][NSTORE3][NPR];
1268  int enerregion;
1269  int *localenerpos;
1270  int jj;
1271  FTYPE (*utoinvert)[NSTORE2][NSTORE3][NPR];
1272  FTYPE (*tempucum)[NSTORE2][NSTORE3][NPR];
1273  FTYPE (*useducum)[NSTORE2][NSTORE3][NPR];
1274  FTYPE (*myupoint)[NSTORE2][NSTORE3][NPR];
1275  int whichpltoavg[NPR];
1276  int ifnotavgthencopy[NPR];
1277  int is,ie,js,je,ks,ke;
1278  int doingextrashiftforstag;
1279 
1280 
1281 
1282 
1283 
1284 
1285  if(FLUXB==FLUXCTSTAG){
1286  // fill in tempucum with changes that are not controlled well in space, but later fill in ucum from this in controlled way
1287  tempucum=GLOBALPOINT(utemparray);
1288  useducum=tempucum; // unless changed
1289  }
1290  else{
1291  // no special shifting of indices occurs that requires loop shifting
1292  tempucum=ucum;
1293  useducum=ucum;
1294  }
1295 
1296 
1297  ucumformetric=GLOBALPOINT(ucumformetric);// temporary space for ucum for metric that is same time as "pb", so not updated yet or is ui
1298 
1299 
1300 
1302  //
1303  // Setup function tasks
1304  //
1306 
1307 
1308  // for ZLOOP:
1309  // avoid looping over region outside active+ghost grid
1310  // good because somewhat general and avoid bad inversions, etc.
1311  enerregion=TRUEGLOBALWITHBNDENERREGION;
1312  localenerpos=enerposreg[enerregion];
1313 
1314 
1315  accdt=BIG; // initially no limit to dt due to acceleration
1316  accdti=accdtj=accdtk=-100;
1317  gravitydt=BIG; // initially no limit to dt due to time derivatives in gravity
1318  gravitydti=gravitydtj=gravitydtk=-100;
1319 
1320 
1321 
1322 
1323 #if(ASYMDIAGCHECK)
1324  dualfprintf(fail_file,"BEGINNING steppart=%d nstep=%ld\n",steppart,nstep);
1325 
1326  dualfprintf(fail_file,"pi in advance\n");
1327  asym_compute_1(pi);
1328 
1329  dualfprintf(fail_file,"pb in advance\n");
1330  asym_compute_1(pb);
1331 #endif
1332 
1334  //
1335  // set initialstep and finalstep to tell some procedures and diagnostic functions if should be accounting or not
1336  //
1338  if(timeorder==0){
1339  initialstep=1;
1340  }
1341  else{
1342  initialstep=0;
1343  }
1344 
1345  if(timeorder==numtimeorders-1){
1346  finalstep=1;
1347  }
1348  else{
1349  finalstep=0;
1350  }
1351 
1353  //
1354  // whether need to compute flux
1355  // only compute flux if flux is added to get Uf or Ucum
1357  int doflux = (CUf[2]!=0.0 || CUnew[1]!=0.0);
1358  // current implicit dt factor
1359  // Since we don't pass CUnew[NUMPREDTCUFS+timeorder], we assume never try to add M^i into U^{n+1} unless computed for current U^i or previous U^i
1360  FTYPE *CUimp=&CUf[NUMPREDTCUFS+timeorder];
1361 
1362 
1363 
1365  //
1366  // set dt4diag for source diagnostics
1367  //
1369  if(timeorder==numtimeorders-1 && (nstep%DIAGSOURCECOMPSTEP==0) ){
1370  // every 4 full steps as well as on final step of full step (otherwise diag_source_comp() too expensive)
1371  dt4diag=dt4diag_willbe;
1372  dt4diag_willbe=0;
1373  }
1374  else{
1375  dt4diag_willbe+=dt;
1376  dt4diag=-1.0;
1377  }
1378 
1379 
1380 
1382  //
1383  // Setup loops [+1 extra compared to normal comp region if doing FLUXCTSTAG]
1384  //
1386  get_flux_startendindices(Uconsevolveloop,&is,&ie,&js,&je,&ks,&ke);
1387 
1388 
1389 
1391  //
1392  // Set initial ui, temporary space, so ok that COMPZLOOP() goes over +1 in FLUXB==FLUXCTSTAG case
1393  //
1395  if(timeorder==0){
1396  // last timestep's final ucum is stored into ucumformetric and ui as initial term in ucum
1397  // copy ucum -> {ucumformetric,ui}
1398  if(doingmetricsubstep()) copy_3dnpr_2ptrs(is,ie,js,je,ks,ke,ucum,ucumformetric,ui);
1399  else copy_3dnpr(is,ie,js,je,ks,ke,ucum,ui); // only need to setup ui then
1400  }
1401  else{
1402  // preserve this time's value of ucum for the metric (for timeorder==0 ucumformetric is assigned from ui)
1403  // copy ucum -> ucumformetric
1404  if(doingmetricsubstep()) copy_3dnpr(is,ie,js,je,ks,ke,ucum,ucumformetric);
1405  }
1406 
1407 
1409  //
1410  // Compute flux
1411  //
1413 
1414 #if(PRODUCTION==0)
1415  trifprintf( "#0f");
1416 #endif
1417 
1418 
1419 
1420 
1421  ndt1=ndt2=ndt3=BIG;
1422  if(doflux && truestep){ // only do if not just passing through
1423 
1424  if(1){
1425  // NORMAL:
1426  // pb used here on a stencil, so if pb=pf or pb=pi in pointers, shouldn't change pi or pf yet -- don't currently
1427  MYFUN(fluxcalc(stage,initialstep,finalstep,pb,pstag,pl_ct, pr_ct, vpot,F1,F2,F3,CUf,CUnew,fluxdt,fluxtime,&ndt1,&ndt2,&ndt3),"advance.c:advance_standard_orig()", "fluxcalcall", 1);
1428  }
1429 
1430 
1431 #if(0)// DEBUG:
1432  if(1){
1433  ndt1donor=ndt2donor=ndt3donor=BIG;
1434  MYFUN(fluxcalc_donor(stage,pb,pstag,pl_ct, pr_ct, vpot,GLOBALPOINT(F1EM),GLOBALPOINT(F2EM),GLOBALPOINT(F3EM),CUf,CUnew,fluxdt,fluxtime,&ndt1donor,&ndt2donor,&ndt3donor),"advance.c:advance_standard_orig()", "fluxcalcall", 1);
1435  }
1436  // DEBUG:
1437  if(1){
1438  int i,j,k,pl,pliter;
1439  FULLLOOP{
1440  PLOOP(pliter,pl){
1441  if(N1>1) MACP0A1(F1,i,j,k,pl)=GLOBALMACP0A1(F1EM,i,j,k,pl);
1442  if(N2>1) MACP0A1(F2,i,j,k,pl)=GLOBALMACP0A1(F2EM,i,j,k,pl);
1443  if(N3>1) MACP0A1(F3,i,j,k,pl)=GLOBALMACP0A1(F3EM,i,j,k,pl);
1444  }
1445  }
1446  ndt1=ndt1donor;
1447  ndt2=ndt2donor;
1448  ndt3=ndt3donor;
1449  }
1450 #endif
1451 
1452 
1453 #if(0)// DEBUG:
1454  if(1){
1455  int i,j,k,pliter,pl;
1456  dualfprintf(fail_file, "BADLOOPCOMPARE: nstep=%ld steppart=%d\n",nstep,steppart);
1457  dualfprintf(fail_file, "ndt1orig=%21.15g ndt1new=%21.15g ndt2orig=%21.15g ndt2new=%21.15g\n",ndt1,ndt1donor,ndt2,ndt2donor);
1458  COMPFULLLOOP{
1459  if(i==390 && j==1 && k==0){
1460  dualfprintf(fail_file, "i=%d j=%d k=%d\n",i,j,k);
1461  PLOOP(pliter,pl) dualfprintf(fail_file," pl=%d F1orig=%21.15g F1new=%21.15g :: F2orig=%21.15g F2new=%21.15g \n",pl,MACP0A1(F1,i,j,k,pl),GLOBALMACP0A1(F1EM,i,j,k,pl),MACP0A1(F2,i,j,k,pl),GLOBALMACP0A1(F2EM,i,j,k,pl));
1462  }
1463  }
1464  }
1465 #endif
1466 
1467 #if(0)// DEBUG:
1468  if(1){
1469  int i,j,k,pliter,pl;
1470  FTYPE diff1,diff2;
1471  FTYPE sum1,sum2;
1472  dualfprintf(fail_file, "BADLOOPCOMPARE: nstep=%ld steppart=%d\n",nstep,steppart);
1473  dualfprintf(fail_file, "ndt1orig=%21.15g ndt1new=%21.15g ndt2orig=%21.15g ndt2new=%21.15g\n",ndt1,ndt1donor,ndt2,ndt2donor);
1474  COMPFULLLOOP{
1475  PLOOP(pliter,pl){
1476  diff1=fabs(MACP0A1(F1,i,j,k,pl)-GLOBALMACP0A1(F1EM,i,j,k,pl));
1477  sum1=fabs(MACP0A1(F1,i,j,k,pl))+fabs(GLOBALMACP0A1(F1EM,i,j,k,pl))+SMALL;
1478  diff2=fabs(MACP0A1(F2,i,j,k,pl)-GLOBALMACP0A1(F2EM,i,j,k,pl));
1479  sum2=fabs(MACP0A1(F2,i,j,k,pl))+fabs(GLOBALMACP0A1(F2EM,i,j,k,pl))+SMALL;
1480  if(diff1/sum1>100.0*NUMEPSILON || diff2/sum2>100.0*NUMEPSILON){
1481  dualfprintf(fail_file, "i=%d j=%d k=%d\n",i,j,k);
1482  dualfprintf(fail_file," pl=%d diff1/sum1=%21.15g F1orig=%21.15g F1new=%21.15g :: diff2/sum2=%21.15g F2orig=%21.15g F2new=%21.15g \n",pl,diff1/sum1,MACP0A1(F1,i,j,k,pl),GLOBALMACP0A1(F1EM,i,j,k,pl),diff2/sum2,MACP0A1(F2,i,j,k,pl),GLOBALMACP0A1(F2EM,i,j,k,pl));
1483  }
1484  }
1485  }
1486  }
1487 #endif
1488 
1489  }// end if not just passing through
1490 
1491 
1492 
1493 
1494 
1495 
1496 #if(PRODUCTION==0)
1497  trifprintf( "1f");
1498 #endif
1499 
1500 
1501 
1502 
1503  // from here on, pi/pb/pf are only used a zone at a time rather than on a stencil
1504 
1505 
1506 
1507 
1508 
1509 
1510 
1513  //
1514  // now update get flux update [loop should go over normal computational region +1 on outer edges so automatically set field if staggered. Since we only set tempucum so far, ucum in that +1 region is unaffected]
1515  //
1517 
1518 
1519  int didreturnpf;
1520  if(truestep){
1521 
1522 
1523  // initialize uf and ucum if very first time here since ucum is cumulative (+=) [now tempucum is cumulative]
1524  // copy 0 -> {uf,tempucum}
1525  if(timeorder==0) init_3dnpr_2ptrs(is, ie, js, je, ks, ke,0.0, uf,tempucum);
1526 
1527 
1528 
1529 #if(WHICHEOM==WITHNOGDET && (NOGDETB1==1 || NOGDETB2==1 || NOGDETB3==1) )
1530  // for FLUXB==FLUXCTSTAG, assume no source term for field
1531  if(FLUXB==FLUXCTSTAG){
1532  dualfprintf(fail_file,"Not setup for field source term if staggered field\n");
1533  myexit(176023);
1534  }
1535 #endif
1536 
1537 
1538 #pragma omp parallel OPENMPGLOBALPRIVATEFORSTATEANDGEOM
1539  {
1540  int pl,pliter,i,j,k;
1541  struct of_geom geomdontuse;
1542  struct of_geom *ptrgeom=&geomdontuse;
1543  FTYPE Uitemp[NPR];
1544  FTYPE dUgeom[NPR],dUriemann[NPR],dUriemann1[NPR+NSPECIAL],dUriemann2[NPR+NSPECIAL],dUriemann3[NPR+NSPECIAL],dUcomp[NUMSOURCES][NPR];
1545  struct of_state qdontuse;
1546  struct of_state *qptr=&qdontuse;
1547  struct of_state qdontuse2;
1548  struct of_state *qptr2=&qdontuse2; // different qptr since call normal and special get_state()
1549  // setup default eomtype
1550  int eomtype;
1551 
1552 
1553  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
1554 
1555 
1556 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
1558  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1559 
1560  // setup default eomtype
1561  eomtype=EOMDEFAULT;
1562 
1563 
1564  // set geometry for centered zone to be updated
1565  get_geometry(i, j, k, CENT, ptrgeom);
1566 
1567  // find Ui(pi)
1568  // force use of primitive to set Ui since otherwise wherever corrected/changed primitive (in fixup, etc.) then would have to change conserved quantity, while same since both are point values
1569  // only field for staggered method is special point value at faces that needs to come from conserved quantity
1570  MYFUN(get_state(MAC(pi,i,j,k), ptrgeom, qptr),"step_ch.c:advance()", "get_state()", 1);
1571  MYFUN(primtoU(UEVOLVE,MAC(pi,i,j,k), qptr, ptrgeom, Uitemp, NULL),"step_ch.c:advance()", "primtoU()", 1);
1572 
1573  if(FLUXB==FLUXCTSTAG || DOENOFLUX != NOENOFLUX ){
1574  // then field version of ui[] is stored as "conserved" value at FACE, not CENT
1575  PLOOPNOB1(pl) MACP0A1(ui,i,j,k,pl)=Uitemp[pl]; // CENT
1576  //PLOOPBONLY(pl) MACP0A1(ui,i,j,k,pl) is itself // FACE (see step_ch.c's setup_rktimestep and know that ui=unew for before first substep)
1577  PLOOPNOB2(pl) MACP0A1(ui,i,j,k,pl)=Uitemp[pl]; // CENT
1578  }
1579  else{
1580  PLOOP(pliter,pl) MACP0A1(ui,i,j,k,pl)=Uitemp[pl]; // all at CENT
1581  }
1582 
1583  // dUriemann is actually average quantity, but we treat is as a point quantity at the zone center
1584  if(doflux){
1585  flux2dUavg(DOALLPL,i,j,k,F1,F2,F3,dUriemann1,dUriemann2,dUriemann3);
1586  PLOOP(pliter,pl) dUriemann[pl]=dUriemann1[pl]+dUriemann2[pl]+dUriemann3[pl]; // this addition is one type of avg->point mistake
1587  }
1588  else{
1589  PLOOP(pliter,pl) dUriemann[pl]=0.0;
1590  }
1591 
1592 
1594  //
1595  // Utoprim as initial conditions : can't assume want these to be same in the end, so assign
1596  //
1597  // MAJORNOTE: Since final step often sets pointers of pi=pf, in order to use arbitrary guess, must set here once done with pi,pb,pf.
1598  //
1600  // copy pb->pf as initial pf
1601  // can do this now that don't need pi anymore
1602  PALLLOOP(pl) MACP0A1(pf,i,j,k,pl) = MACP0A1(pb,i,j,k,pl);
1603 
1604 
1607  //
1608  // now update get source update (only affects stress-energy tensor in general)
1609  // [Loop goes over up to +1 normal computational region for getting new staggered U if doing FLUXCTSTAG]
1610  //
1612 
1613  // get state since both source() and dUtodt() need same state
1614  // From pb, so different than state for Ui(pi)
1615  MYFUN(get_stateforsource(MAC(pb,i,j,k), ptrgeom, &qptr2) ,"advance.c:()", "get_state() dir=0", 1);
1616 
1617 
1618  // note that uf and ucum are initialized inside setup_rktimestep() before first substep
1619 
1620 
1621  // find dU(pb)
1622  MYFUN(source(MAC(pi,i,j,k), MAC(pb,i,j,k), MAC(pf,i,j,k), &didreturnpf, &eomtype, ptrgeom, qptr2, MAC(ui,i,j,k), MAC(uf,i,j,k), CUf, CUimp, 0.0, dUriemann, dUcomp, dUgeom),"step_ch.c:advance()", "source", 1);
1623  // assumes final dUcomp is nonzero and representative of source term over this timestep
1624  // KORALTODO: Not using eomtype for this method because outside loop. Would have to store eomtype in array or something!
1625 
1626  // DEBUG (to check if source updated pf guess)
1627  // if(didreturnpf==1) dualfprintf(fail_file,"didreturnpf=%d\n",didreturnpf);
1628 
1629 
1630 #if(SPLITNPR)
1631  // don't update metric if only doing B1-B3
1632  if(advancepassnumber==-1 || advancepassnumber==1)
1633 #endif
1634  {
1635  if(DODIAGS){
1636 #if(ACCURATESOURCEDIAG>=1)
1637  diag_source_all(ptrgeom,dUgeom,fluxdt);
1638 #else
1639  diag_source_all(ptrgeom,dUgeom,dt4diag);
1640 #endif
1641 #if(ACCURATESOURCEDIAG>=2)
1642  diag_source_comp(ptrgeom,dUcomp,fluxdt);
1643 #else
1644  diag_source_comp(ptrgeom,dUcomp,dt4diag);
1645 #endif
1646  }
1647  }
1648 
1649 
1650 
1651  // Get update
1652  dUtoU(timeorder,DOALLPL, i,j,k,ptrgeom->p,dUgeom, dUcomp, dUriemann, CUf, CUnew, MAC(ui,i,j,k), MAC(uf,i,j,k), MAC(tempucum,i,j,k));
1653 
1654 
1655 
1656  // get timestep limit from acceleration
1657 #if(LIMITDTWITHSOURCETERM)
1658 #if(SPLITNPR)
1659  // don't do dUtodt if only doing B1-B3
1660  if(advancepassnumber==-1 || advancepassnumber==1)
1661 #endif
1662  {
1663  // geometry is post-metric update, but should still give good estimate of future dt
1664  dUtodt(ptrgeom, qptr2, MAC(pb,i,j,k), dUgeom, dUriemann, dUcomp[GEOMSOURCE], &accdt_ij, &gravitydt_ij);
1665 
1666 #pragma omp critical
1667  {
1668  if(accdt_ij<accdt){
1669  accdt=accdt_ij;
1670  accdti=i;
1671  accdtj=j;
1672  accdtk=k;
1673  }
1674  if(gravitydt_ij<gravitydt){
1675  gravitydt=gravitydt_ij;
1676  gravitydti=i;
1677  gravitydtj=j;
1678  gravitydtk=k;
1679  }
1680  }// end critical region
1681  }// end block that may mean: if not only doing B1-B3
1682 
1683 #endif // end if doing LIMITDTWITHSOURCETERM
1684 
1685 
1686 
1687 
1688 
1689 
1690 #if(FLUXDUMP==1)
1691  fluxdumpdt=dt; // store current dt so when dump fluxdump use that dt instead of updated dt
1693  // DEBUG - DIAG:
1694  PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,0*NPR + pl)=dUgeom[pl];
1695 
1696  if(N1>1) PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,1*NPR + pl)=dUriemann1[pl];
1697  else PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,1*NPR + pl)=0.0;
1698 
1699  if(N2>1) PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,2*NPR + pl)=dUriemann2[pl];
1700  else PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,2*NPR + pl)=0.0;
1701 
1702  if(N3>1) PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,3*NPR + pl)=dUriemann3[pl];
1703  else PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,3*NPR + pl)=0.0;
1704 #endif
1705 
1706  } // end COMPZLOOP :: end looping to obtain dUriemann and full unew update
1707  }// end parallel block
1708  } // end if truestep
1709  else{
1710  // then nothing to do since nothing changed
1711  // previously updated dU and got new ucum as fed into metric, but now metric has its own ucummetric so all that is not needed
1712  // SUPERGODMARK: no, I guess I don't recall what was being done for metric and why when passing through with dt==0.0
1713 
1714  // just need to copy ui -> {uf,tempucum} to duplicate behavior of dUtoU()
1715  copy_3dnpr_2ptrs(is,ie,js,je,ks,ke,ui,uf,tempucum);
1716  }
1717 
1718 
1719 
1720 
1721 
1722 
1723 
1724 #if(PRODUCTION==0)
1725  trifprintf( "#0m");
1726 #endif
1727 
1728 
1729 
1731  //
1732  // EVOLVE (update/compute) METRIC HERE
1733  // In general computes stress-energy tensor (T) from pb and T is then used to compute metric
1734  // Done here instead of after flux since horizon_flux() updates flux through boundary that would change metric
1735  // want metric to be at same time as everything else done with pb so RK method is consistent
1736  //
1737  // uses unew that's NOT updated yet
1739  if(truestep){
1740  if(doingmetricsubstep()){
1741 #if(SPLITNPR)
1742  // don't update metric if only doing B1-B3
1743  if(advancepassnumber==-1 || advancepassnumber==1)
1744 #endif
1745  {
1746  compute_new_metric_substep(CUf,CUnew,pb,ucumformetric); // CHANGINGMARK : Not sure if CUnew here is correct
1747  }
1748  }// end if doing metric substepping
1749  }
1750 
1751 
1752 
1753 
1755  //
1756  // compute flux diagnostics (accurately using all substeps)
1757  //
1759  if(doflux && truestep){
1760  // must come after metric changes that can change where flux surface is since otherwise when flux surface changes, we won't track this substep's flux through the new surface but the old surface (which could even be at r=0 and have no flux)
1761  // if using unew, then since metric update above uses old unew, need present flux at new horizon surface
1762 #if(SPLITNPR)
1763  // don't update metric if only doing B1-B3
1764  if(advancepassnumber==-1 || advancepassnumber==1)
1765 #endif
1766  {
1767 #if(ACCURATEDIAG)
1768  diag_flux_pureflux(pb,F1, F2, F3, fluxdt); // fluxdt is true dt for this flux as added in dUtoU() as part of ucum
1769 #endif
1770  }
1771  }
1772 
1773 
1774 
1775 
1776 
1777 
1778 
1779 #if(PRODUCTION==0)
1780  trifprintf( "#0s");
1781 #endif
1782 
1783 
1784 
1785 
1786 
1788  //
1789  // Copy over tempucum -> ucum per pl to account for staggered field
1790  //
1791  // And choose which RK-quantity to invert
1792  //
1794  if(finalstep){
1795  if(FLUXB==FLUXCTSTAG){
1796  // copy over new ucum in only desired locations irrespective of where tempucum was updated
1797  // copy tempucum -> ucum
1798  copy_tempucum_finalucum(DOALLPL,Uconsevolveloop,tempucum,ucum);
1799  }
1800  utoinvert = ucum;
1801  useducum=ucum;
1802  }
1803  else{
1804  // tempucum cumulates for now
1805  utoinvert = uf;
1806  // tempucum cumulates for now
1807  useducum=tempucum;
1808  }
1809 
1810 
1811 
1812 
1813 
1815  //
1816  // split ZLOOP above and below to allow staggered field method
1817  // [loop only over "centered" cells]
1818  //
1820  if(FLUXB==FLUXCTSTAG){
1821  // if using staggered grid for magnetic field, then need to convert ucum to pstag to new pb/pf
1822 
1823 
1824  // GODMARK: Use of globals
1825  myupoint=GLOBALPOINT(upointglobal);
1826 
1827  // first copy over all quantities as point, which is true except for fields if FLUXRECON active
1828  // copy utoinvert -> myupoint
1829  // copy all pl's since myupoint eventually used to invert rest of non-field quantities
1830  copy_tempucum_finalucum(DOALLPL,Uconsevolveloop,utoinvert,myupoint);
1831 
1832 
1834  //bound_uavg(STAGEM1,utoinvert); // DEBUG
1835  // uses utoinvert and gets reaveraged field into myupoint
1836  field_integrate_fluxrecon(stage, pb, utoinvert, myupoint);
1837  }
1838 
1839 
1840  // first pb entry is used for shock indicator, second is filled with new field
1841  // myupoint goes in as staggered point value of magnetic flux and returned as centered point value of magnetic flux
1842  // first pb entry is used for shock indicator, second is filled with new field
1843  // myupoint goes in as staggered point value of magnetic flux and returned as centered point value of magnetic flux
1844  if(1){ // must manually override to use below donor version
1845  interpolate_ustag2fieldcent(stage, boundtime, timeorder, numtimeorders, pb, pstag, myupoint, pf);
1846  }
1847  else{
1848  // interpolate_ustag2fieldcent_donor(stage, boundtime, timeorder, numtimeorders, pb, pstag, myupoint, pf);
1849  }
1850 
1852  // now myupoint contains centered point conserved quantities ready for inversion
1854 
1855  }
1856  else{
1857  // utoinvert never reassigned from global a_utoinvert assignment since if here not doing FLUXCTSTAG
1858  myupoint=utoinvert;
1859  }
1860 
1861 
1862 
1863 
1864 
1865 
1866 
1867 
1869  //
1870  // INVERT [loop only over "centered" cells]
1871  //
1873 
1874 
1875  // get loop range
1876  get_inversion_startendindices(Uconsevolveloop,&is,&ie,&js,&je,&ks,&ke);
1877 
1878 #pragma omp parallel OPENMPGLOBALPRIVATEFORINVERSION
1879  {
1880  int pl,pliter,i,j,k;
1881  struct of_geom geomdontuse;
1882  struct of_geom *ptrgeom=&geomdontuse;
1883  FTYPE prbefore[NPR];
1884  struct of_newtonstats newtonstats; setnewtonstatsdefault(&newtonstats);
1885  int showmessages=1;
1886  int allowlocalfailurefixandnoreport=1; // allow local fixups
1887 
1888  // setup default eomtype
1889  int eomtype;
1890 
1891  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
1892 
1893  // initialize counters
1894  newtonstats.nstroke=newtonstats.lntries=0;
1895 
1896 
1897 #pragma omp for schedule(OPENMPVARYENDTIMESCHEDULE(),OPENMPCHUNKSIZE(blocksize)) reduction(+: nstroke)
1899  OPENMP3DLOOPBLOCK2IJK(i,j,k);
1900 
1901  // setup default eomtype
1902  // KORALTODO: Note that eomtype should have been set from source(), but different loop. But not using this "orig" method for koral evolution, so ok.
1903  eomtype=EOMDEFAULT;
1904 
1905  // set geometry for centered zone to be updated
1906  get_geometry(i, j, k, CENT, ptrgeom);
1907 
1908 
1909  // invert U->p
1910  if(finalstep){ // last call, so ucum is cooked and ready to eat!
1911  // store guess for diss_compute before changed by normal inversion
1912  PALLLOOP(pl) prbefore[pl]=MACP0A1(pf,i,j,k,pl);
1913 
1914  FTYPE dissmeasure=-1.0; // assume energy try ok
1915  int whichcap=CAPTYPEBASIC;
1916  int whichmethod=MODEPICKBEST; // try to choose best option for this "external" inversion
1917  int modprim=0;
1918  int checkoninversiongas=CHECKONINVERSION;
1919  int checkoninversionrad=CHECKONINVERSIONRAD;
1920  MYFUN(Utoprimgen(showmessages,checkoninversiongas,checkoninversionrad,allowlocalfailurefixandnoreport, finalstep,&eomtype,whichcap,whichmethod,modprim,EVOLVEUTOPRIM,UEVOLVE,MAC(myupoint,i,j,k), NULL, ptrgeom, dissmeasure, MAC(pi,i,j,k), MAC(pf,i,j,k),&newtonstats),"step_ch.c:advance()", "Utoprimgen", 1);
1921  nstroke+=newtonstats.nstroke; newtonstats.nstroke=newtonstats.lntries=0;
1922 
1923 
1924 #if(DODISS||DODISSVSR)
1925  // then see what entropy inversion would give
1926  diss_compute(EVOLVEUTOPRIM,UEVOLVE,MAC(myupoint,i,j,k),ptrgeom,prbefore,MAC(pf,i,j,k),&newtonstats);
1927 #endif
1928 
1929  }
1930  else{ // otherwise still iterating on primitives
1931  FTYPE dissmeasure=-1.0; // assume energy try ok
1932  int whichcap=CAPTYPEBASIC;
1933  int whichmethod=MODEPICKBEST; // try to choose best option for this "external" inversion
1934  int modprim=0;
1935  int checkoninversiongas=CHECKONINVERSION;
1936  int checkoninversionrad=CHECKONINVERSIONRAD;
1937  MYFUN(Utoprimgen(showmessages,checkoninversiongas,checkoninversionrad,allowlocalfailurefixandnoreport, finalstep,&eomtype,whichcap,whichmethod,modprim,EVOLVEUTOPRIM,UEVOLVE,MAC(myupoint,i,j,k), NULL, ptrgeom, dissmeasure, MAC(pi,i,j,k), MAC(pf,i,j,k),&newtonstats),"step_ch.c:advance()", "Utoprimgen", 1);
1938  nstroke+=newtonstats.nstroke; newtonstats.nstroke=newtonstats.lntries=0;
1939  }
1940 
1941 
1942 
1943 
1944 
1945 #if(SPLITNPR)
1946  // don't update metric if only doing B1-B3
1947  if(advancepassnumber==-1 || advancepassnumber==1)
1948 #endif
1949  {
1950  // immediate local (i.e. 1-zone) fix
1951 #if(FIXUPZONES==FIXUP1ZONE)
1952  // SUPERGODMARK: Below should differentiate beteween whether want negative densities fixed or not, but right now fixup1zone() does all
1953  if((STEPOVERNEGU==0)||(STEPOVERNEGRHO==0)||(STEPOVERNEGRHOU==0)||(finalstep)){
1954  int docorrectucons=0;
1955  MYFUN(fixup1zone(docorrectucons,MAC(pf,i,j,k),MAC(useducum,i,j,k), ptrgeom,finalstep),"fixup.c:fixup()", "fixup1zone()", 1);
1956  }
1957 #endif
1958  }
1959 
1960 
1961  }// end COMPZLOOP
1962  }// end parallel section
1963 
1964 
1965 
1966 
1967 
1968 
1969 
1970 
1971 
1972 #if(ASYMDIAGCHECK)
1973  dualfprintf(fail_file,"useducum in advance\n");
1974  asym_compute_2(useducum);
1975 
1976  dualfprintf(fail_file,"ENDING steppart=%d nstep=%ld\n",steppart,nstep);
1977 #endif
1978 
1979 
1980 
1981 
1983  //
1984  // If not fixing up primitives after inversion immediately, then fix up all zones at once afterwards
1985  //
1987 
1988 #if(SPLITNPR)
1989  // don't update metric if only doing B1-B3
1990  if(advancepassnumber==-1 || advancepassnumber==1)
1991 #endif
1992  {
1993 #if(FIXUPZONES==FIXUPALLZONES)
1994  fixup(stage,pf,useducum,finalstep);
1995 #endif
1996  }
1997 
1998 
2000  //
2001  // Determine next timestep from waves, fluxes, and source updates
2002  //
2004 
2005 
2006  prepare_globaldt(truestep,ndt1,ndt2,ndt3,accdt,accdti,accdtj,accdtk,gravitydt,gravitydti,gravitydtj,gravitydtk,ndt);
2007 
2008 
2009 
2010 #if(PRODUCTION==0)
2011  trifprintf( "2f");
2012 #endif
2013 
2014  return (0);
2015 }
2016 
2017 
2018 
2019 
2020 
2021 
2022 
2023 
2024 
2025 
2026 
2027 
2028 
2029 
2030 
2031 
2032 
2035 static int advance_finitevolume(
2036  int truestep,
2037  int stage,
2038  FTYPE (*pi)[NSTORE2][NSTORE3][NPR],
2039  FTYPE (*pb)[NSTORE2][NSTORE3][NPR],
2040  FTYPE (*pf)[NSTORE2][NSTORE3][NPR],
2041  FTYPE (*pstag)[NSTORE2][NSTORE3][NPR],
2042  FTYPE (*pl_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP], FTYPE (*pr_ct)[NSTORE1][NSTORE2][NSTORE3][NPR2INTERP],
2043  FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL],
2045  FTYPE (*ui)[NSTORE2][NSTORE3][NPR],
2046  FTYPE (*uf)[NSTORE2][NSTORE3][NPR],
2047  FTYPE (*ucum)[NSTORE2][NSTORE3][NPR],
2048  FTYPE *CUf,
2049  FTYPE *CUnew,
2050  SFTYPE fluxdt,
2051  SFTYPE boundtime,
2052  SFTYPE fluxtime,
2053  int timeorder, int numtimeorders,
2054  FTYPE *ndt)
2055 {
2056  int sc;
2057  FTYPE ndt1, ndt2, ndt3;
2058  FTYPE dUtot;
2059  FTYPE idx1,idx2;
2060  SFTYPE dt4diag;
2061  static SFTYPE dt4diag_willbe=0;
2062  int finalstep,initialstep;
2063  FTYPE accdt, accdt_ij;
2064  int accdti,accdtj,accdtk;
2065  FTYPE gravitydt, gravitydt_ij;
2066  int gravitydti,gravitydtj,gravitydtk;
2067  int enerregion;
2068  int *localenerpos;
2069  int jj;
2070  FTYPE (*utoinvert)[NSTORE2][NSTORE3][NPR];
2071  FTYPE (*tempucum)[NSTORE2][NSTORE3][NPR];
2072  FTYPE (*useducum)[NSTORE2][NSTORE3][NPR];
2073  FTYPE (*myupoint)[NSTORE2][NSTORE3][NPR];
2074  FTYPE (*ucumformetric)[NSTORE2][NSTORE3][NPR];
2075  FTYPE (*dUgeomarray)[NSTORE2][NSTORE3][NPR];
2076  // staggered field function:
2077  int whichpltoavg[NPR];
2078  int ifnotavgthencopy[NPR];
2079  int docons,dosource;
2080  int locpl[NPR];
2081  int is,ie,js,je,ks,ke;
2082  int doingextrashiftforstag;
2083 
2084 
2085  if(FLUXB==FLUXCTSTAG){
2086  tempucum=GLOBALPOINT(utemparray);
2087  useducum=tempucum; // unless changed
2088  }
2089  else{
2090  // no special shifting of indices occurs that requires loop shifting
2091  tempucum=ucum;
2092  useducum=ucum;
2093  }
2094 
2095 
2096  ucumformetric=GLOBALPOINT(ucumformetric);// temporary space for ucum for metric that is same time as "pb", so not updated yet or is ui
2097  dUgeomarray=GLOBALPOINT(dUgeomarray);// temporary space for dUgeomarray
2098 
2099 
2100 
2101  {// begin block
2102  int pl,pliter;
2103  // any cons
2104  docons=0;
2105  PLOOP(pliter,pl) docons+=do_conserved_integration[pl];
2106  docons*=(DOENOFLUX == ENOFINITEVOLUME);
2107 
2108  // any source
2109  dosource=0;
2110  PLOOP(pliter,pl) dosource+=do_source_integration[pl];
2111  dosource*=(DOENOFLUX == ENOFINITEVOLUME);
2112  }// end block
2113 
2114 
2116  //
2117  // Setup loops and dt's
2118  //
2120 
2121 
2122  // for CZLOOP:
2123  // avoid looping over region outside active+ghost grid
2124  // good because somewhat general and avoid bad inversions, etc.
2125  enerregion=TRUEGLOBALWITHBNDENERREGION;
2126  localenerpos=enerposreg[enerregion];
2127 
2128 
2129  accdt=BIG; // initially no limit to dt due to acceleration
2130  accdti=accdtj=accdtk=-100;
2131  gravitydt=BIG; // initially no limit to dt due to time-changes in gravity
2132  gravitydti=gravitydtj=gravitydtk=-100;
2133 
2134 
2136  //
2137  // set initialstep and finalstep to tell some procedures and diagnostic functions if should be accounting or not
2138  //
2140  if(timeorder==0){
2141  initialstep=1;
2142  }
2143  else{
2144  initialstep=0;
2145  }
2146 
2147  if(timeorder==numtimeorders-1){
2148  finalstep=1;
2149  }
2150  else{
2151  finalstep=0;
2152  }
2153 
2155  //
2156  // whether need to compute flux
2157  // only compute flux if flux is added to get Uf or Ucum
2159  int doflux = (CUf[2]!=0.0 || CUnew[1]!=0.0);
2160  // current implicit dt factor
2161  // Since we don't pass CUnew[NUMPREDTCUFS+timeorder], we assume never try to add M^i into U^{n+1} unless computed for current U^i or previous U^i
2162  FTYPE *CUimp=&CUf[NUMPREDTCUFS+timeorder];
2163 
2165  //
2166  // set dt4diag for source diagnostics
2167  //
2169  if(timeorder==numtimeorders-1 && (nstep%DIAGSOURCECOMPSTEP==0) ){
2170  // every 4 full steps as well as on final step of full step (otherwise diag_source_comp() too expensive)
2171  dt4diag=dt4diag_willbe;
2172  dt4diag_willbe=0;
2173  }
2174  else{
2175  dt4diag_willbe+=dt;
2176  dt4diag=-1.0;
2177  }
2178 
2179 
2181  //
2182  // Setup loops
2183  //
2185  get_flux_startendindices(Uconsevolveloop,&is,&ie,&js,&je,&ks,&ke);
2186 
2187 
2188 
2190  //
2191  // Setup RK stuff
2192  //
2194 
2195  // setup RK's uinitial (needed since sometimes set ui=0 inside advance())
2196  // unew should be read in, now assign to uinitial for finite volume method or normal method when dt=0.0 or moving grid
2197  // below can't be CZLOOP since need uinitial in ghost+active region
2198  // GODMARK: since ui=ucum (average quantities) then if change primitive somehow (fixup, etc.) then must change corresponding average conserved quantity somehow (this is one reason why using average values is annoying, although in some cases we use Sasha's method to treat average like point for *change* in average conserved quantity)
2199  // otherwise assume ui didn't change. Present RK schemes assume this. Otherwise have to keep track of pf/Uf pairs in RK stepping
2201  //
2202  // Set initial ui, temporary space, so ok that COMPZLOOP() goes over +1 in FLUXB==FLUXCTSTAG case
2203  //
2205  if(timeorder==0){
2206  // last timestep's final ucum is stored into ucumformetric and ui as initial term in ucum
2207  // copy ucum -> {ucumformetric,ui}
2208  if(doingmetricsubstep()) copy_3dnpr_2ptrs(is,ie,js,je,ks,ke,ucum,ucumformetric,ui);
2209  else copy_3dnpr(is,ie,js,je,ks,ke,ucum,ui); // only need to setup ui then
2210  }
2211  else{
2212  // preserve this time's value of ucum for the metric (for timeorder==0 ucumformetric is assigned from ui)
2213  // copy ucum -> ucumformetric
2214  if(doingmetricsubstep()) copy_3dnpr(is,ie,js,je,ks,ke,ucum,ucumformetric);
2215  }
2216 
2217 
2218 
2220  //
2221  // Compute flux
2222  //
2224 
2225 #if(PRODUCTION==0)
2226  trifprintf( "#0f");
2227 #endif
2228 
2229  ndt1=ndt2=ndt3=BIG;
2230  if(doflux && truestep){
2231  // pb used here on a stencil, so if pb=pf or pb=pi in pointers, shouldn't change pi or pf yet -- don't currently
2232  MYFUN(fluxcalc(stage,initialstep,finalstep,pb,pstag,pl_ct, pr_ct, vpot,F1,F2,F3,CUf,CUnew,fluxdt,fluxtime,&ndt1,&ndt2,&ndt3),"advance.c:advance_standard_orig()", "fluxcalcall", 1);
2233  }
2234 
2235 #if(PRODUCTION==0)
2236  trifprintf( "1f");
2237 #endif
2238  // from here on, pi/pb/pf are only used a zone at a time rather than on a stencil
2239 
2240 
2241 
2242 
2243 
2244 
2245 
2246 #if(PRODUCTION==0)
2247  trifprintf( "#0m");
2248 #endif
2249 
2250 
2252  //
2253  // Utoprim as initial conditions : can't assume want these to be same in the end, so assign
2254  //
2255  // Since final step often sets pointers of pi=pf, in order to use arbitrary guess, must set here once done with pi,pb,pf.
2256  //
2258  // setup initial guess for inversion
2259  // use pb since should be closer to pf
2260  // copy pb->pf
2261  // OK to do here, because never really use pi
2262  copy_3dnpr_fullloop(pb,pf);
2263 
2264 
2265 
2267  //
2268  // SOURCE TERM
2269  //
2271  int didreturnpf; // used to have source() pass back better guess for Utoprimgen() than pb.
2272 
2273  if(truestep){
2274  // GODMARK: other/more special cases?
2275 #if(WHICHEOM==WITHNOGDET && (NOGDETB1==1 || NOGDETB2==1 || NOGDETB3==1) )
2276  // for FLUXB==FLUXCTSTAG, assume no source term for field
2277  if(FLUXB==FLUXCTSTAG){
2278  dualfprintf(fail_file,"Not setup for field source term if staggered field\n");
2279  myexit(176023);
2280  }
2281 #endif
2282 
2283  // COMPZSLOOP(is,ie,js,je,ks,ke){
2284 #if(STOREFLUXSTATE)
2285  // call get_stateforsource, which just reads existing data instead of generating from EOS, etc.
2286 #pragma omp parallel
2287 #else
2288 #pragma omp parallel OPENMPGLOBALPRIVATEFORSTATEANDGEOM
2289 #endif
2290  {
2291  int i,j,k,pl,pliter;
2292  FTYPE dUgeom[NPR],dUriemann[NPR],dUriemann1[NPR+NSPECIAL],dUriemann2[NPR+NSPECIAL],dUriemann3[NPR+NSPECIAL],dUcomp[NUMSOURCES][NPR];
2293  struct of_geom geomdontuse;
2294  struct of_geom *ptrgeom=&geomdontuse;
2295  struct of_state qdontuse;
2296  struct of_state *qptr=&qdontuse;
2297  // setup default eomtype
2298  int eomtype;
2299 
2300  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
2301 
2302 
2303 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
2305  OPENMP3DLOOPBLOCK2IJK(i,j,k);
2306 
2307  // setup default eomtype
2308  eomtype=EOMDEFAULT;
2309 
2310  // find dU(pb)
2311  // only find source term if non-Minkowski and non-Cartesian
2312  // set geometry for centered zone to be updated
2313  get_geometry(i, j, k, CENT, ptrgeom);
2314 
2315  // get state
2316  MYFUN(get_stateforsource(MAC(pb,i,j,k), ptrgeom, &qptr) ,"advance.c:()", "get_state() dir=0", 1);
2317 
2318 
2319  // dUriemann is volume averaged quantity (here this calcuation is done in case want to limit sources)
2320  if(doflux){
2321  flux2dUavg(DOALLPL,i,j,k,F1,F2,F3,dUriemann1,dUriemann2,dUriemann3);
2322  PLOOP(pliter,pl) dUriemann[pl]=dUriemann1[pl]+dUriemann2[pl]+dUriemann3[pl]; // this addition is entirely consistent with point->averages
2323  }
2324  else{
2325  PLOOP(pliter,pl) dUriemann[pl]=0.0;
2326  }
2327 
2328 
2329  // get source term (point source, don't use to update diagnostics)
2330  MYFUN(source(MAC(pi,i,j,k), MAC(pb,i,j,k), MAC(pf,i,j,k), &didreturnpf, &eomtype, ptrgeom, qptr, MAC(ui,i,j,k), MAC(uf,i,j,k), CUf, CUimp, 0.0, dUriemann, dUcomp, MAC(dUgeomarray,i,j,k)),"step_ch.c:advance()", "source", 1);
2331  }// end COMPZLOOP
2332 
2333 
2334  // Store diagnostics related to component form of sources. Done here since don't integrate-up compnents of source. So only point accurate
2335 #if(SPLITNPR)
2336  // don't update metric if only doing B1-B3
2337  if(advancepassnumber==-1 || advancepassnumber==1)
2338 #endif
2339  {
2340 #pragma omp critical // since diagnostics store in same global cumulative variables
2341  {
2342  if(DODIAGS){
2343 #if(ACCURATESOURCEDIAG>=2)
2344  diag_source_comp(ptrgeom,dUcomp,fluxdt);
2345 #else
2346  diag_source_comp(ptrgeom,dUcomp,dt4diag);
2347 #endif
2348  }
2349  }
2350  }
2351 
2352 
2353  // volume integrate dUgeom
2354  // c2a_1 c2a_2 c2a_3
2355  if(dosource){
2356  // need to limit source averaging -- GODMARK
2357  PALLLOOP(pl) locpl[pl]=CENT;
2358  PALLLOOP(pl) whichpltoavg[pl]=do_source_integration[pl];// default
2359  PALLLOOP(pl) ifnotavgthencopy[pl]=1-do_source_integration[pl];// default
2360  avg2cen_interp(locpl,whichpltoavg, ifnotavgthencopy, ENOSOURCETERM, ENOCENT2AVGTYPE, pb, POINT(dUgeomarray), POINT(dUgeomarray));
2361  }
2362  }// end parallel region
2363  }// end if truestep
2364 
2365 
2366 
2367 
2368 
2369 
2370 
2371 
2372 
2373 
2375  //
2376  // update Ui to Uf (ultimately to ucum)
2377  //
2379 
2380  // COMPZSLOOP(is,ie,js,je,ks,ke){
2381 #if(STOREFLUXSTATE)
2382  // call get_stateforsource, which just reads existing data instead of generating from EOS, etc.
2383 #pragma omp parallel
2384 #else
2385 #pragma omp parallel OPENMPGLOBALPRIVATEFORSTATEANDGEOM
2386 #endif
2387  {
2388  int i,j,k,pl,pliter;
2389  FTYPE fdummy;
2390  FTYPE dUgeom[NPR],dUriemann[NPR],dUriemann1[NPR+NSPECIAL],dUriemann2[NPR+NSPECIAL],dUriemann3[NPR+NSPECIAL],dUcomp[NUMSOURCES][NPR];
2391  struct of_geom geomdontuse;
2392  struct of_geom *ptrgeom=&geomdontuse;
2393  struct of_state qdontuse;
2394  struct of_state *qptr=&qdontuse;
2395  // GODMARK: KORALTODO: setup default eomtype (not using source() from above!)
2396  int eomtype;
2397 
2398  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
2399 
2400 
2401 #pragma omp for schedule(OPENMPSCHEDULE(),OPENMPCHUNKSIZE(blocksize))
2403  OPENMP3DLOOPBLOCK2IJK(i,j,k);
2404 
2405  // setup default eomtype
2406  eomtype=EOMDEFAULT;
2407 
2408 
2409  // get geometry at center where source is located
2410  get_geometry(i, j, k, CENT, ptrgeom);
2411 
2412  // get state
2413  MYFUN(get_stateforsource(MAC(pb,i,j,k), ptrgeom, &qptr) ,"advance.c:()", "get_state() dir=0", 1);
2414 
2416  //
2417  // Utoprim as initial conditions : can't assume want these to be same in the end, so assign
2418  //
2420 
2421  // initialize uf and ucum if very first time here since ucum is cumulative (+=)
2422  // if(timeorder==0) PLOOP(pliter,pl) MACP0A1(uf,i,j,k,pl)=MACP0A1(tempucum,i,j,k,pl)=MACP0A1(ucum,i,j,k,pl)=0.0;
2423  if(timeorder==0) PLOOP(pliter,pl) MACP0A1(uf,i,j,k,pl)=MACP0A1(tempucum,i,j,k,pl)=0.0;
2424 
2425  // NEED TO DEFINE Ui on other substeps besides the 0th one
2426  // find Ui(pi)
2427 
2428 
2429 
2430  if(truestep){
2431  // get source term (volume integrated)
2432  PLOOP(pliter,pl) dUgeom[pl]=MACP0A1(dUgeomarray,i,j,k,pl);
2433 
2434 
2435  // store diagnostics related to source. Totals, so use volume-integrated source.
2436 #if(SPLITNPR)
2437  // don't update metric if only doing B1-B3
2438  if(advancepassnumber==-1 || advancepassnumber==1)
2439 #endif
2440  {
2441 #pragma omp critical // since diagnostics store in same global cumulative variables
2442  {
2443  if(DODIAGS){
2444 #if(ACCURATESOURCEDIAG>=1)
2445  diag_source_all(ptrgeom,dUgeom,fluxdt);
2446 #else
2447  diag_source_all(ptrgeom,dUgeom,dt4diag);
2448 #endif
2449  }
2450  }
2451  }
2452 
2453 
2454  // dUriemann is volume averaged quantity
2455  if(doflux){
2456  flux2dUavg(DOALLPL,i,j,k,F1,F2,F3,dUriemann1,dUriemann2,dUriemann3);
2457  PLOOP(pliter,pl) dUriemann[pl]=dUriemann1[pl]+dUriemann2[pl]+dUriemann3[pl]; // this addition is entirely consistent with point->averages
2458  }
2459  else{
2460  PLOOP(pliter,pl) dUriemann[pl]=0.0;
2461  }
2462  }
2463  else{
2464  PLOOP(pliter,pl){
2465  dUriemann[pl]=0.0;
2466  dUgeom[pl]=0.0;
2467  }
2468  }
2469 
2470  // find uf==Uf and additional terms to ucum
2471  dUtoU(timeorder,DOALLPL, i,j,k,ptrgeom->p,dUgeom, dUcomp, dUriemann, CUf, CUnew, MAC(ui,i,j,k), MAC(uf,i,j,k), MAC(tempucum,i,j,k));
2472 
2473 
2474 
2475 #if(LIMITDTWITHSOURCETERM)
2476  // SUPERGODMARK: no longer have access to dUcomp : NEED TO FIX
2477  // below is correct, but excessive
2478  // get source term again in order to have dUcomp (NEED TO FIX)
2479  MYFUN(source(MAC(pi,i,j,k), MAC(pb,i,j,k), MAC(pf,i,j,k), &didreturnpf, &eomtype, ptrgeom, qptr, MAC(ui,i,j,k), MAC(uf,i,j,k), CUf, CUimp, 0.0, dUriemann, dUcomp, &fdummy),"step_ch.c:advance()", "source", 2);
2480 
2481 
2482  dUtodt(ptrgeom, qptr, MAC(pb,i,j,k), dUgeom, dUriemann, dUcomp[GEOMSOURCE], &accdt_ij, &gravitydt_ij);
2483  // below is old before grid sectioning
2484  //#if( (DOEVOLVEMETRIC || DOSELFGRAVVSR) && (RESTRICTDTSETTINGINSIDEHORIZON>=1) )
2485  // // avoid limiting dt if inside horizon
2486  // if(WITHINENERREGION(enerposreg[OUTSIDEHORIZONENERREGION],i,j,k))
2487  //#endif
2488 #pragma omp critical
2489  {
2490  if(accdt_ij<accdt){
2491  accdt=accdt_ij;
2492  accdti=i;
2493  accdtj=j;
2494  accdtk=k;
2495  }
2496  if(gravitydt_ij<gravitydt){
2497  gravitydt=gravitydt_ij;
2498  gravitydti=i;
2499  gravitydtj=j;
2500  gravitydtk=k;
2501  }
2502  }// end critical region
2503 #endif
2504 
2505 
2506 
2507 
2508 #if(FLUXDUMP==1)
2509  PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,0*NPR + pl)=dUgeom[pl];
2510 
2511  if(N1>1) PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,1*NPR + pl)=dUriemann1[pl];
2512  else PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,1*NPR + pl)=0.0;
2513 
2514  if(N2>1) PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,2*NPR + pl)=dUriemann2[pl];
2515  else PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,2*NPR + pl)=0.0;
2516 
2517  if(N3>1) PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,3*NPR + pl)=dUriemann3[pl];
2518  else PLOOP(pliter,pl) GLOBALMACP0A1(fluxdump,i,j,k,3*NPR + pl)=0.0;
2519 #endif
2520 
2521 
2522  }// end 3D LOOP
2523  }//end parallel region
2524 
2525 
2526 
2527 
2528 
2530  //
2531  // EVOLVE (update/compute) METRIC HERE
2532  // In general computes stress-energy tensor (T) from pb and T is then used to compute metric
2533  // Done here instead of after flux since horizon_flux() updates flux through boundary that would change metric
2534  // want metric to be at same time as everythin else done with pb so RK method is consistent
2535  //
2536  // uses unew that's NOT updated yet
2538  if(truestep){
2539 #if(SPLITNPR)
2540  // don't update metric if only doing B1-B3
2541  if(advancepassnumber==-1 || advancepassnumber==1)
2542 #endif
2543  {
2544  compute_new_metric_substep(CUf,CUnew,pb,ucumformetric); // CHANGINGMARK : Not sure if CUnew here is correct
2545  }
2546  }
2547 
2548 
2549 
2551  //
2552  // compute flux diagnostics (accurately using all substeps)
2553  //
2555  if(doflux && truestep){
2556  // must come after metric changes that can change where flux surface is since otherwise when flux surface changes, we won't track this substep's flux through the new surface but the old surface (which could even be at r=0 and have no flux)
2557  // if using unew, then since metric update above uses old unew, need present flux at new horizon surface
2558 #if(SPLITNPR)
2559  // don't update metric if only doing B1-B3
2560  if(advancepassnumber==-1 || advancepassnumber==1)
2561 #endif
2562  {
2563 #if(ACCURATEDIAG)
2564  diag_flux_pureflux(pb,F1, F2, F3, fluxdt); // fluxdt is true dt for this flux as added in dUtoU() as part of ucum update
2565 #endif
2566  }
2567  }
2568 
2569 
2570 
2571 
2572 
2573 
2574 
2576  //
2577  // Copy over tempucum -> ucum per pl to account for staggered field
2578  //
2579  // and volume differentiate the conserved quantity
2580  //
2582  if(finalstep){
2583  // last call, so ucum is cooked and ready to eat!
2584  if(FLUXB==FLUXCTSTAG){
2585  copy_tempucum_finalucum(DOALLPL,Uconsevolveloop,tempucum,ucum);
2586  }
2587  // useducum only used after ucum assigned to ui above
2588  utoinvert=ucum;
2589  useducum=ucum;
2590  // ubound=utoinvert;
2591  }
2592  else{ // otherwise still iterating on primitives
2593  // don't need to copy over tempucum->ucum yet
2594  utoinvert=uf;
2595  useducum=tempucum;
2596  // ubound=utoinvert;
2597  }
2598 
2599  // GODMARK: use of globals
2600  myupoint=GLOBALPOINT(upointglobal);
2601 
2602 
2603 
2604  // to debug ENO
2605  //#if(DOENODEBUG)
2606  //debugeno_compute(pb,utoinvert,enodebugarray); //SASDEBUG -- OLD USE: now assign debugs inside reconstructeno code
2607  //#endif
2608 
2609 
2610 
2611 
2612 
2613  // a2c_1 a2c_2 a2c_3
2614  if(docons){
2615  int pl,pliter;
2616  // conserved quantity is limited later after primitive is obtained
2617  PALLLOOP(pl) locpl[pl]=CENT;
2618  PALLLOOP(pl) whichpltoavg[pl]=do_conserved_integration[pl];// default
2619  PALLLOOP(pl) ifnotavgthencopy[pl]=1-do_conserved_integration[pl];// default
2620  avg2cen_interp(locpl,whichpltoavg, ifnotavgthencopy, ENOCONSERVED, ENOAVG2CENTTYPE, pb, utoinvert, myupoint); //SASMARK: pb's for shock indicators should be defined on ALL grid, not only on ghost+active. Maybe should use pi instead because define everywhere?
2621  }
2622  else{
2623  // myupoint=utoinvert;
2624  copy_tempucum_finalucum(DOALLPL,Uconsevolveloop,utoinvert,myupoint);
2625  }
2626 
2627 
2628 
2630  //
2631  // split CZLOOP above and below to allow staggered field method
2632  //
2634  if(FLUXB==FLUXCTSTAG){
2635  // if using staggered grid for magnetic field, then need to convert ucum to pstag to new pb/pf
2636 
2637  // GODMARK: If had c2a/a2c with 3-point outputs, then could do avg2cen_interp and below at once
2638 
2639  // first pb entry is used for shock indicator, second is filled with new field
2640  interpolate_ustag2fieldcent(stage, boundtime, timeorder, numtimeorders, pb, pstag, myupoint, pf);
2641 
2643  // now utoinvert contains centered point conserved quantities ready for inversion
2645 
2646  }
2647 
2648 
2649 
2650 
2652  //
2653  // Invert U -> p
2654  //
2655  // and fixup p if inversion bad
2656  // and compute dissipation rate if requested
2657  //
2659 
2660 
2661  // get loop range
2662  get_inversion_startendindices(Uconsevolveloop,&is,&ie,&js,&je,&ks,&ke);
2663 
2664 #pragma omp parallel OPENMPGLOBALPRIVATEFORINVERSION
2665  {
2666  int i,j,k,pl,pliter;
2667  FTYPE prbefore[NPR];
2668  struct of_geom geomdontuse;
2669  struct of_geom *ptrgeom=&geomdontuse;
2670  struct of_newtonstats newtonstats; setnewtonstatsdefault(&newtonstats);
2671  int showmessages=1;
2672  int allowlocalfailurefixandnoreport=1; // allow local fixups
2673 
2674  // setup default eomtype
2675  int eomtype;
2676 
2677 
2678  OPENMP3DLOOPVARSDEFINE; OPENMP3DLOOPSETUP(is,ie,js,je,ks,ke);
2679 
2680  // initialize counters
2681  newtonstats.nstroke=newtonstats.lntries=0;
2682  // ptr different when in parallel region
2683  ptrgeom=&geomdontuse;
2684 
2685 #pragma omp for schedule(OPENMPVARYENDTIMESCHEDULE(),OPENMPCHUNKSIZE(blocksize)) reduction(+: nstroke)
2687  OPENMP3DLOOPBLOCK2IJK(i,j,k);
2688 
2689  // setup default eomtype (KORALTODO: GODMARK: Doesn't use source() version of eomtype from above)
2690  eomtype=EOMDEFAULT;
2691 
2692  // set geometry for centered zone to be updated
2693  get_geometry(i, j, k, CENT, ptrgeom);
2694 
2695 
2696  // store guess for diss_compute before changed by normal inversion
2697  PALLLOOP(pl) prbefore[pl]=MACP0A1(pf,i,j,k,pl);
2698 
2699 
2700  // invert point U-> point p
2701  int dissmeasure=-1.0; // assume ok to try energy
2702  int whichcap=CAPTYPEBASIC;
2703  int whichmethod=MODEPICKBEST; // try to choose best option for this "external" inversion
2704  int modprim=0;
2705  int checkoninversiongas=CHECKONINVERSION;
2706  int checkoninversionrad=CHECKONINVERSIONRAD;
2707  MYFUN(Utoprimgen(showmessages,checkoninversiongas,checkoninversionrad,allowlocalfailurefixandnoreport, finalstep,&eomtype,whichcap,whichmethod,modprim,EVOLVEUTOPRIM, UEVOLVE, MAC(myupoint,i,j,k), NULL, ptrgeom, dissmeasure, MAC(pi,i,j,k), MAC(pf,i,j,k),&newtonstats),"step_ch.c:advance()", "Utoprimgen", 1);
2708  nstroke+=newtonstats.nstroke; newtonstats.nstroke=newtonstats.lntries=0;
2709 
2710  //If using a high order scheme, need to choose whether to trust the point value
2711  if(docons){
2712  MYFUN(check_point_vs_average(timeorder, numtimeorders, GLOBALMAC(pflag,i,j,k),MAC(pb,i,j,k),MAC(pf,i,j,k),MAC(myupoint,i,j,k),MAC(utoinvert,i,j,k),ptrgeom,&newtonstats),"advance.c:advance_finitevolume()", "check_point_vs_average()", 1);
2713  }
2714 
2715 
2716 #if(DODISS||DODISSVSR)
2717  if(finalstep){
2718  // then see what entropy inversion would give
2719  diss_compute(EVOLVEUTOPRIM,UEVOLVE,MAC(useducum,i,j,k),ptrgeom,prbefore, MAC(pf,i,j,k),&newtonstats);
2720  }
2721 #endif
2722 
2723 
2724 #if(SPLITNPR)
2725  // don't update metric if only doing B1-B3
2726  if(advancepassnumber==-1 || advancepassnumber==1)
2727 #endif
2728  {
2729  // immediate local (i.e. 1-zone) fix
2730 #if(FIXUPZONES==FIXUP1ZONE)
2731  // SUPERGODMARK: Below should differentiate beteween whether want negative densities fixed or not, but right now fixup1zone() does all
2732  if((STEPOVERNEGU==0)||(STEPOVERNEGRHO==0)||(STEPOVERNEGRHOU==0)||(finalstep)){
2733  int docorrectucons=0;
2734  MYFUN(fixup1zone(docorrectucons,MAC(pf,i,j,k), MAC(useducum,i,j,k), ptrgeom, finalstep),"advance.c:advance_finitevolume()", "fixup1zone()", 1);
2735  }
2736 #endif
2737  }
2738  }// end COMPZLOOP
2739  }// end parallel region
2740 
2741 
2742 
2743 
2744 
2746  //
2747  // If not fixing up primitives after inversion immediately, then fix up all zones at once afterwards
2748  //
2750 
2751 #if(SPLITNPR)
2752  // don't update metric if only doing B1-B3
2753  if(advancepassnumber==-1 || advancepassnumber==1)
2754 #endif
2755  {
2756 #if(FIXUPZONES==FIXUPALLZONES)
2757  fixup(stage,pf,useducum,finalstep);
2758 #endif
2759  }
2760 
2761 
2762 
2764  //
2765  // Determine next timestep from waves, fluxes, and source updates
2766  //
2768 
2769  prepare_globaldt(truestep,ndt1,ndt2,ndt3,accdt,accdti,accdtj,accdtk,gravitydt,gravitydti,gravitydtj,gravitydtk,ndt);
2770 
2771 
2772 #if(PRODUCTION==0)
2773  trifprintf( "2f");
2774 #endif
2775 
2776  return (0);
2777 }
2778 
2779 
2780 
2781 
2782 
2784 static int prepare_globaldt(
2785  int truestep,
2786  FTYPE ndt1,FTYPE ndt2,FTYPE ndt3,
2787  FTYPE accdt,int accdti,int accdtj,int accdtk,
2788  FTYPE gravitydt,int gravitydti,int gravitydtj,int gravitydtk,
2789  FTYPE *ndt)
2790 {
2791  FTYPE wavedt;
2792  int jj;
2793 
2794 
2795 
2797  //
2798  // unsplit multidimensional Courant condition
2799  //
2801  if(PERCELLDT==0){
2802  wavedt = MINDTSET(ndt1,ndt2,ndt3);
2803  }
2804  else{
2805  wavedt = ndt1; // full result stored in *any* of ndt1,2,3 regardless of whether dimension is relevant
2806  }
2807 
2808 
2809 
2811  //
2812  // minimize dt over all "operators"
2813  //
2815  *ndt = defcon * MIN(wavedt , accdt);
2816 
2817 #if(USEGRAVITYDTINDTLIMIT)
2818  // use gravitydt (often too small, but sometimes accdt/ndt not small enough)
2819  *ndt = MIN(*ndt,gravitydt);
2820 #endif
2821 
2822 
2824  //
2825  // Store some global variables for timestep
2826  //
2828 
2829  gravitydtglobal = gravitydt;
2830  sourcedtglobal = accdt; // accdt includes gravitydtglobal
2831  wavedtglobal = wavedt;
2832 
2833 #if(PRODUCTION==0)
2834  if(truestep){
2835  // report per-CPU time-step limited every 100 time steps
2836 
2837  // GODMARK: 1 : do always
2838  if(1|| nstep%DTr==0){
2839  logdtfprintf("nstep=%ld steppart=%d :: dt=%g ndt=%g ndt1=%g ndt2=%g ndt3=%g\n",nstep,steppart,dt,*ndt,ndt1,ndt2,ndt3);
2840  SLOOPA(jj) logdtfprintf("dir=%d wavedti=%d wavedtj=%d wavedtk=%d\n",jj,waveglobaldti[jj],waveglobaldtj[jj],waveglobaldtk[jj]);
2841  logdtfprintf("accdt=%g (accdti=%d accdtj=%d accdtk=%d) :: gravitydt=%g (gravitydti=%d gravitydtj=%d gravitydtk=%d) :: gravityskipstep=%d\n",accdt,accdti,accdtj,accdtk,gravitydt,gravitydti,gravitydtj,gravitydtk,gravityskipstep);
2842  }
2843  }
2844 #endif
2845 
2846 
2847  return(0);
2848 }
2849 
2850 
2851 
2852 
2853 
2854 
2855 
2856 
2857 
2858 
2859 
2865 static int check_point_vs_average(int timeorder, int numtimeorders, PFTYPE *lpflag, FTYPE *pb, FTYPE *pf, FTYPE *upoint, FTYPE *uavg, struct of_geom *ptrgeom, struct of_newtonstats *newtonstats)
2866 {
2867  FTYPE pavg[NPR]; //atch for temporary storage of primitives obtained from inverting the averaged conserved quantities
2868  PFTYPE invert_from_point_flag, invert_from_average_flag;
2869  FTYPE frac_avg_used; //this is be used for flux interpolation limiting
2870  int pl,pliter;
2871  int is_convergence_failure;
2872  int avgschemeatall;
2873  int finalstep;
2874  FTYPE limit_prim_correction( FTYPE fractional_difference_threshold, struct of_geom *geom, FTYPE *pin, FTYPE *pout );
2875  int showmessages=1;
2876  int allowlocalfailurefixandnoreport=1; // allow local fixups
2877 
2878  // setup default eomtype
2879  int eomtype=EOMDEFAULT;
2880 
2881 
2882  finalstep=timeorder == numtimeorders-1;
2883 
2884 
2885 
2886  avgschemeatall=(interporder[avgscheme[1]]>3) || (interporder[avgscheme[2]]>3) || (interporder[avgscheme[3]]>3);
2887  if(avgschemeatall==0) return(0); // since nothing to do
2888 
2889 
2890  invert_from_point_flag = lpflag[FLAGUTOPRIMFAIL];
2891 
2892 
2893  if( 0 && debugfail >= 1 && (IFUTOPRIMFAILSOFT(invert_from_point_flag)) ) {
2894  dualfprintf( fail_file, "t = %g, nstep = %ld, steppart = %d, i = %d, j = %d, rho = %21.15g, u = %21.15g, fracneg = %21.15g\n",
2895  t, realnstep, steppart, ptrgeom->i + startpos[1], ptrgeom->j + startpos[2],
2896  pf[RHO], pf[UU], (pf[RHO]>0)?(-pf[UU]/(pf[RHO]+DBL_MIN)):(-pf[RHO]/(pf[UU]+DBL_MIN)) );
2897  }
2898 
2899 
2900  //WHAT IF INTERNAL ENERGY BECOMES SLIGHTLY NEGATIVE? WE STILL CAN DO THE LIMITING IN PRIM QUANTITIES! -- coorrected but check! -- SUPERSASMARK TODO atch
2902  (
2903  IFUTOPRIMNOFAILORFIXED(invert_from_point_flag) || //atch added the below to still do the pt. vs. avg. check on primitives if the internal energy goes neg.
2904  ( (IFUTOPRIMFAILSOFTNOTRHORELATED(invert_from_point_flag)) && (0 != STEPOVERNEGU) ) || //intermediate substep with stepping over u < 0
2905  ( (IFUTOPRIMFAILSOFTRHORELATED(invert_from_point_flag)) && (0 != STEPOVERNEGRHO) ) //intermediate substep with stepping over rho < 0
2906  )
2907  ) {
2908 
2909 
2910  //make a copy of the initial guess so that not to modify the original pb's
2911  PLOOP(pliter,pl) pavg[pl] = pb[pl];
2912  //invert the average U -> "average" p
2913  int dissmeasure=-1.0; // assume ok to try energy
2914  int whichcap=CAPTYPEBASIC;
2915  int whichmethod=MODEPICKBEST; // try to choose best option for this "external" inversion
2916  int modprim=0;
2917  int checkoninversiongas=CHECKONINVERSION;
2918  int checkoninversionrad=CHECKONINVERSIONRAD;
2919  MYFUN(Utoprimgen(showmessages,checkoninversiongas,checkoninversionrad,allowlocalfailurefixandnoreport, finalstep,&eomtype,whichcap,whichmethod,modprim,EVOLVEUTOPRIM, UEVOLVE, uavg, NULL, ptrgeom, dissmeasure, pavg, pavg,newtonstats),"step_ch.c:advance()", "Utoprimgen", 3);
2920 
2921  invert_from_average_flag = GLOBALMACP0A1(pflag,ptrgeom->i,ptrgeom->j,ptrgeom->k,FLAGUTOPRIMFAIL);
2922 
2923  //Inversion from the average value succeeded or has a negative density or internal energy
2924  if( IFUTOPRIMNOFAILORFIXED(invert_from_average_flag) || IFUTOPRIMFAILSOFT(invert_from_average_flag) ) {
2925  //Inversion from both from the point and the average values succeeded
2926  //checks if the states' gamma factors and densities are different by more than a certain fraction
2927  //and if different, modify the point values such that they are not further than by MAX_AC_PRIM_FRAC_CHANGE
2928  //from the average ones
2929  frac_avg_used = limit_prim_correction(MAX_AC_PRIM_FRAC_CHANGE, ptrgeom, pavg, pf);
2930 
2931 #if( DOENODEBUG ) //atch debug; note that use the location with pl =0 , interporflux = 0, & dir = 1 since limiting the change in prim quantities is not a per-component operation
2932  if( frac_avg_used > 0.01 ) {
2933  MACP0A4(enodebugarray,ptrgeom->i,ptrgeom->j,ptrgeom->k,1-1,0,0,ENODEBUGPARAM_LIMCORR_PRIM)++;
2934  }
2935 #endif
2936 
2937  if( pf[UU] < 0.0 && timeorder == numtimeorders-1 ) {
2939  }
2940 
2941  //lpflag[FLAGUTOPRIMFAIL] = invert_from_point_flag; //unneeded since it is alrady == UTOPRIMNOFAIL
2942 
2943  } // end if both point and average did NOT fail
2944  else {
2945  //Inversion from the point values succeeded but that from the average failed:
2946  //retain the point value
2947 
2948  //set the inversion error flag to correspond to the inversion from the average value
2949  lpflag[FLAGUTOPRIMFAIL] = invert_from_point_flag;
2950  frac_avg_used = 0.0; //used point value, i.e. zero fracion of the average value
2951  }
2952  }
2953  else if( INVERTFROMAVERAGEIFFAILED && (IFUTOPRIMFAIL(invert_from_point_flag)) ) { //failure //atch correct
2954  //inversion from the point value failed
2955 
2956  // if last substep -> revert to the average value, else if only negative densities then allow for substep. If other type of failures, then never allow and revert to Uavg
2957 
2958 
2959  // GODMARK:
2960  // CHECK IF INVERSION FAILED. IF FAILED, TRY TO USE uavg:
2961  // invert U->p
2962 
2963  // GODMARK: decide whether best to revert to average or not
2964 
2965  //=1 if it is a non-convergence failure; =0 if it is an occurrence of a negative density
2966  is_convergence_failure = !IFUTOPRIMFAILSOFT(invert_from_point_flag);
2967 
2968  if((timeorder==numtimeorders-1 /*&& (1 == is_nonconvergence_failure || FIXUPZONES == FIXUPNOZONES)*/ ) || // last substep, then DO invert from average IF no fixups or non-convergence failure (ADT) SASMARKx
2969 
2970  ( 1 == is_convergence_failure ) || //non-convergence (no solution in primitive quantities) error, so have to fix it up
2971 
2972  ( (timeorder<numtimeorders-1) && (
2973  ((IFUTOPRIMFAILSOFTNOTRHORELATED(invert_from_point_flag)) && (0 == STEPOVERNEGU))||
2974  ((invert_from_point_flag==UTOPRIMFAILRHOUNEG) && (0 == STEPOVERNEGRHOU)) ||
2975  ((IFUTOPRIMFAILSOFTRHORELATED(invert_from_point_flag)) && (0 == STEPOVERNEGRHO))
2976  )
2977  ) //intermediate substep with no stepping over u < 0, rho<0, or both <0
2978  ) {
2979  if(debugfail >= 1) {
2980  dualfprintf( fail_file, "Inversion from the point value failed. Using the inversion from the average value.\n" );
2981  }
2982 
2983  //make a copy of the initial guess so that not to modify the original pb's
2984  PLOOP(pliter,pl) pf[pl] = pb[pl];
2985  //invert the average U -> "average" p
2986  int dissmeasure=-1.0; // assume ok to try energy
2987  int whichcap=CAPTYPEBASIC;
2988  int whichmethod=MODEPICKBEST; // try to choose best option for this "external" inversion
2989  int modprim=0;
2990  int checkoninversiongas=CHECKONINVERSION;
2991  int checkoninversionrad=CHECKONINVERSIONRAD;
2992  MYFUN(Utoprimgen(showmessages,checkoninversiongas,checkoninversionrad,allowlocalfailurefixandnoreport, finalstep,&eomtype,whichcap,whichmethod,modprim,EVOLVEUTOPRIM, UEVOLVE, uavg, NULL, ptrgeom, dissmeasure, pb, pf,newtonstats),"step_ch.c:advance()", "Utoprimgen", 3);
2993  // invert_from_average_flag = lpflag[FLAGUTOPRIMFAIL];
2994 
2995 
2996  //Have the results from the inversion from the average value -- copy the result over
2997  // PLOOP(pliter,pl) pf[pl] = pavg[pl];
2998  // lpflag[FLAGUTOPRIMFAIL] = invert_from_average_flag;
2999 
3000  //old code:
3001  //MYFUN(Utoprimgen(showmessages,checkoninversiongas,checkoninversionrad,allowlocalfailurefixandnoreport, finalstep,&eomtype,EVOLVEUTOPRIM, UEVOLVE, avg, NULL, ptrgeom, dissmeasure, pb, pf,&newtonstats),"step_ch.c:advance()", "Utoprimgen", 2);
3002 
3003  frac_avg_used = 1.0; //reverted to the average value
3004 
3005  }
3006  else {
3007  frac_avg_used = 0.0; //used the point value
3008  }
3009  }
3010 
3011  return(0);
3012 }
3013 
3014 
3015 
3016 
3017 
3018 #define COMPARE_GAMMA 0
3019 
3023 FTYPE limit_prim_correction( FTYPE fractional_difference_threshold, struct of_geom *geom, FTYPE *pin, FTYPE *pout )
3024 {
3025  FTYPE gammain = 0.0, gammaout = 0.0;
3026  FTYPE frac_start, frac_end, frac_diff;
3027  FTYPE fraction_input_value;
3028  FTYPE comovingenergyin, comovingenergyout;
3029  int pl,pliter;
3030  FTYPE bsqin,bsqout;
3031  struct of_state qin, qout;
3032  int jj;
3033  FTYPE bdotuin, bdotuout;
3034 
3035 
3036 #if( COMPARE_GAMMA )
3037  gamma_calc( pin, geom, &gammain );
3038  gamma_calc( pout, geom, &gammaout );
3039 #endif
3040 
3041  get_state(pin, geom, &qin);
3042  get_state(pout, geom, &qout);
3043 
3044  bsqout = dot(qout.bcon, qout.bcov);
3045  bsqin = dot(qin.bcon, qin.bcov);
3046 
3047  bdotuin = 0.0; DLOOPA(jj) bdotuin+=(qin.ucov[jj])*(qin.bcon[jj]);
3048  bdotuout = 0.0; DLOOPA(jj) bdotuout+=(qout.ucov[jj])*(qout.bcon[jj]);
3049 
3050  // u.T.u comoving energy density
3051  comovingenergyin = pin[RHO] + pin[UU] + bsqin*0.5 - bdotuin*bdotuin;
3052  comovingenergyout = pout[RHO] + pout[UU] + bsqout*0.5 - bdotuout*bdotuout;
3053 
3054 
3055 
3056 #if( COMPARE_GAMMA )
3057  frac_diff = MAX( fractional_diff(gammain, gammaout),
3058  fractional_diff( comovingenergyin, comovingenergyout ) );
3059 #else
3060  frac_diff = fractional_diff( comovingenergyin, comovingenergyout );
3061 #endif
3062 
3063  //fractional difference at which the reduction to the input value starts
3064  frac_start = 0.5 * fractional_difference_threshold;
3065 
3066  //fractional difference after which only the input value is used
3067  frac_end = fractional_difference_threshold;
3068 
3069  //the fraction of the input value used in the output; increases linearly from 0 to 1 for fractions going from frac_start to frac_end
3070  fraction_input_value = MAX( 0., MIN(1., (frac_diff - frac_start)/(frac_end - frac_start) ) );
3071 
3072  if( 0.0 != fraction_input_value ){
3073  //states are too different: reverted to primitives that correspond to average conserved quantities because trust them more than point values
3074  dualfprintf( fail_file, "States are too different, using %3d%% of the average values: i = %d, j = %d, k = %d, nstep = %ld, steppart = %d, t = %21.15g\n",
3075  (int)(100. * fraction_input_value), geom->i, geom->j, geom->k, nstep, steppart, t );
3076  if( debugfail >= 2 ){
3077  dualfprintf( fail_file, "Prim. pt. value (gamma, rho, u): " );
3078  dualfprintf( fail_file, "%21.15g %21.15g %21.15g\n", gammaout, pout[RHO], pout[UU] );
3079  dualfprintf( fail_file, "Prim. avg value (gamma, rho, u): " );
3080  dualfprintf( fail_file, "%21.15g %21.15g %21.15g\n", gammain, pin[RHO], pin[UU] );
3081  dualfprintf( fail_file, "Frac. difference(ganna, rho, u): " );
3082  dualfprintf( fail_file, "%21.15g %21.15g %21.15g\n",
3083  fractional_diff(gammain, gammaout),
3084  fractional_diff(pin[RHO], pout[RHO]),
3085  fractional_diff(pin[UU], pout[UU])
3086  );
3087  }
3088  }
3089 
3090  PLOOP(pliter,pl) {
3091  pout[pl] = fraction_input_value * pin[pl] + (1. - fraction_input_value) * pout[pl];
3092  }
3093 
3094  return( fraction_input_value );
3095 }
3096 
3097 
3098 
3101 {
3102  FTYPE frac_diff;
3103 
3104  frac_diff = 2. * fabs( a - b ) / ( fabs(a) + fabs(b) + DBL_MIN );
3105 
3106  return( frac_diff );
3107 
3108 }
3109 
3110 
3111 
3112 
3113 
3114 
3115 
3116 
3117 
3118 
3119 
3120 
3121 
3122 
3123 
3124 
3125 
3126 
3127 
3128 
3129 
3130 
3131 
3132 
3133 
3135 static void flux2dUavg(int whichpl, int i, int j, int k, FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE *dU1avg,FTYPE *dU2avg,FTYPE *dU3avg)
3136 {
3137  FTYPE idx1,idx2,idx3;
3138  int pl,pliter;
3139 
3140 #if(VOLUMEDIFF==0)
3141  idx1=1.0/dx[RR];
3142  idx2=1.0/dx[TH];
3143  idx3=1.0/dx[PH];
3144 #else
3145  idx1=GLOBALMETMACP0A1(idxvol,i,j,k,RR);
3146  idx2=GLOBALMETMACP0A1(idxvol,i,j,k,TH);
3147  idx3=GLOBALMETMACP0A1(idxvol,i,j,k,PH);
3148 #endif
3149 
3150  int special;
3151  if(whichpl==DOSPECIALPL){
3152  special=NSPECIAL;
3153  whichpl=DOALLPL; // override
3154  }
3155  else special=0;
3156 
3157  // initialize for simplicity so don't have to do it conditionally on N>1
3158  PALLLOOPSPECIAL(pl,special){
3159  dU1avg[pl]=0;
3160  dU2avg[pl]=0;
3161  dU3avg[pl]=0;
3162  }
3163 
3164  if(FLUXB==FLUXCD){ // don't use volume reg. since differencing is large
3165 
3166  if(whichpl==DOALLPL || whichpl==DONONBPL){
3167 
3168  PLOOPNOB1(pl){
3169 #if(N1>1)
3170  dU1avg[pl]=(
3171  - (MACP0A1(F1,ip1mac(i),j,k,pl) - MACP0A1(F1,i,j,k,pl)) *idx1
3172  );
3173 #endif
3174 #if(N2>1)
3175  dU2avg[pl]=(
3176  - (MACP0A1(F2,i,jp1mac(j),k,pl) - MACP0A1(F2,i,j,k,pl)) *idx2
3177  );
3178 #endif
3179 
3180 #if(N3>1)
3181  dU3avg[pl]=(
3182  - (MACP0A1(F3,i,j,kp1mac(k),pl) - MACP0A1(F3,i,j,k,pl)) *idx3
3183  );
3184 #endif
3185 
3186  }
3187 
3188  // rest of variables (if any) are normal
3189  PLOOPNOB2SPECIAL(pl,special){
3190 #if(N1>1)
3191  dU1avg[pl]=(
3192  - (MACP0A1(F1,ip1mac(i),j,k,pl) - MACP0A1(F1,i,j,k,pl)) *idx1
3193  );
3194 #endif
3195 #if(N2>1)
3196  dU2avg[pl]=(
3197  - (MACP0A1(F2,i,jp1mac(j),k,pl) - MACP0A1(F2,i,j,k,pl)) *idx2
3198  );
3199 #endif
3200 #if(N3>1)
3201  dU3avg[pl]=(
3202  - (MACP0A1(F3,i,j,kp1mac(k),pl) - MACP0A1(F3,i,j,k,pl)) *idx3
3203  );
3204 #endif
3205 
3206  }
3207  }// end if doing non-B U
3208 
3209  if(whichpl==DOALLPL || whichpl==DOBPL){
3210 
3211  // simple version that assumes Fi[Bi] is set to 0 in flux.c for FLUXCD (which it is currently)
3212  PLOOPBONLY(pl){
3213 #if(N1>1)
3214  dU1avg[pl]=(
3215  - (MACP0A1(F1,ip1mac(i),j,k,pl) - MACP0A1(F1,im1mac(i),j,k,pl)) *idx1
3216  );
3217 #endif
3218 #if(N2>1)
3219  dU2avg[pl]=(
3220  - (MACP0A1(F2,i,jp1mac(j),k,pl) - MACP0A1(F2,i,jm1mac(j),k,pl)) *idx2
3221  );
3222 #endif
3223 #if(N3>1)
3224  dU3avg[pl]=(
3225  - (MACP0A1(F3,i,j,kp1mac(k),pl) - MACP0A1(F3,i,j,km1mac(k),pl)) *idx3
3226  );
3227 #endif
3228  }
3229  }// end if doing B U
3230 
3231  }// end FLUXCD
3232 
3233  else{
3234 
3235 
3236  FTYPE lowerF2,upperF2;
3237 #if(IF3DSPCTHENMPITRANSFERATPOLE==1)
3238  // Ensure that spherical polar axis flux only contributes to B2 for special3dspc=1 with polar cut-out.
3239  // Allows more arbitrary interpolations across axis (including with gdet factors)
3240  // "lower" means we will zero-out lower F2, while "upper" means we will zero-out upper F2 in terms of j in Du2avg expression
3241  int preconditionF2lower=(ISSPCMCOORD(MCOORD) && FLUXB==FLUXCTSTAG && special3dspc && (startpos[2]+j==0 || startpos[2]+j==totalsize[2]));
3242  int preconditionF2upper=(ISSPCMCOORD(MCOORD) && FLUXB==FLUXCTSTAG && special3dspc && (startpos[2]+j==-1 || startpos[2]+j==totalsize[2]-1));
3243 #endif
3244 
3245  // other (normal) FLUXB methods, including FLUXCTSTAG
3246  PALLLOOPSPECIAL(pl,special) {
3247  if(whichpl==DONONBPL && BPL(pl)==1 || whichpl==DOBPL && BPL(pl)==0) continue;
3248 
3249 
3250 #if(IF3DSPCTHENMPITRANSFERATPOLE==1)
3251  if(pl!=B2 && preconditionF2lower) lowerF2=0.0;
3252  else lowerF2=1.0;
3253  if(pl!=B2 && preconditionF2upper) upperF2=0.0;
3254  else upperF2=1.0;
3255 #else
3256  lowerF2=1.0;
3257  upperF2=1.0;
3258 #endif
3259 
3260 
3261 #if(N1>1)
3262  dU1avg[pl]=(
3263  - (MACP0A1(F1,ip1mac(i),j,k,pl) - MACP0A1(F1,i,j,k,pl)) *idx1
3264  );
3265 #endif
3266 #if(N2>1)
3267  dU2avg[pl]=(
3268  - (upperF2*MACP0A1(F2,i,jp1mac(j),k,pl) - lowerF2*MACP0A1(F2,i,j,k,pl)) *idx2
3269  );
3270 #endif
3271 #if(N3>1)
3272  dU3avg[pl]=(
3273  - (MACP0A1(F3,i,j,kp1mac(k),pl) - MACP0A1(F3,i,j,k,pl)) *idx3
3274  );
3275 #endif
3276  }
3277 
3278 
3279 
3280 
3281  }
3282 
3283 
3284 
3285 
3286 }
3287 
3288 
3289 
3290 
3291 
3293 static void dUtoU(int timeorder, int whichpl, int i, int j, int k, int loc, FTYPE *dUgeom, FTYPE (*dUcomp)[NPR], FTYPE *dUriemann, FTYPE *CUf, FTYPE *CUnew, FTYPE *Ui, FTYPE *Uf, FTYPE *ucum)
3294 {
3295  int pl,pliter;
3296  void dUtoU_check(int timeorder, int i, int j, int k, int loc, int pl, FTYPE *dUgeom, FTYPE (*dUcomp)[NPR], FTYPE *dUriemann, FTYPE *CUf, FTYPE *CUnew, FTYPE *Ui, FTYPE *Uf, FTYPE *ucum);
3297 
3298  int special;
3299  if(whichpl==DOSPECIALPL){
3300  special=NSPECIAL;
3301  whichpl=DOALLPL; // override
3302  }
3303  else special=0;
3304 
3305 
3306 
3307  // get physics non-geometry source terms
3308  FTYPE dUrad[NPR+NSPECIAL],dUnonrad[NPR+NSPECIAL]; // NSPECIAL part only used if whichpl==DOSPECIALPL
3309  int sc;
3310  PALLLOOPSPECIAL(pl,special){
3311  dUrad[pl]=0.0; // init as zero
3312  // only sc=RADSOURCE is in implicit part, so only separate that out
3313  sc=RADSOURCE;
3314  if(pl<NPR) dUrad[pl] = dUcomp[sc][pl]; // dUcomp always NPR, but dUrad over full range possible
3315 
3316  // all terms except RADSOURCE
3317  dUnonrad[pl] = dUgeom[pl] - dUrad[pl];
3318  }
3319 
3320  // initialize dUradall as zero. Ensure initialized for any possible pl's
3321  FTYPE dUradall[NPR+NSPECIAL][MAXTIMEORDER];
3322  int ii,jj;
3323  for(ii=0;ii<MAXTIMEORDER;ii++){
3324  PLOOP(pliter,pl) dUradall[pl][ii]=0.0;
3325  PALLLOOPSPECIAL(pl,special) dUradall[pl][ii]=0.0;
3326  PLOOPBONLY(pl) dUradall[pl][ii]=0.0;
3327  }
3328 
3329 
3330  // store physics dU's that could need an implicit treatment
3331  if(EOMRADTYPE!=EOMRADNONE && special==0){ // don't access Mradk if from compute_dissmeasure that uses special!=0
3332  // only non-field case
3333  if(whichpl==DOALLPL || whichpl==DONONBPL){
3334  PLOOP(pliter,pl){
3335  GLOBALMACP1A1(Mradk,timeorder,i,j,k,pl) = dUrad[pl]; // USE OF GLOBALS // only NPR pl's exist for Mradk
3336  }
3337 
3338  // now assign dUradall for radiation
3339  for(ii=0;ii<=timeorder;ii++){ // timeorder goes from 0..TIMEORDER-1 inclusive
3340  PLOOP(pliter,pl) dUradall[pl][ii] = GLOBALMACP1A1(Mradk,ii,i,j,k,pl); // radiation could affect any pl's, but only NPR pl's exist for Mradk GODMARK -- issue with dissmeasure?
3341  }
3342  }
3343  }
3344  else{
3345  // then assume not related to implicit radiation but still done per timeorder as if explicit
3346  ii=timeorder;
3347  PALLLOOPSPECIAL(pl,special) dUradall[pl][ii] = dUrad[pl];
3348  }
3349 
3350 
3351  if(whichpl==DOALLPL){
3352  // finally assign new Uf and ucum
3353  // store uf to avoid recomputing U(pf) used later as pb for advance()
3354  PALLLOOPSPECIAL(pl,special) Uf[pl] = UFSET(CUf,dt,Ui[pl],Uf[pl],dUriemann[pl],dUnonrad[pl],dUradall[pl]);
3355 
3356 
3357  // how much of Ui, dU, and Uf to keep for final solution
3358  // ultimately ucum is actual solution used to find final pf
3359  PALLLOOPSPECIAL(pl,special) ucum[pl] += UCUMUPDATE(CUnew,dt,Ui[pl],Uf[pl],dUriemann[pl],dUnonrad[pl],dUradall[pl]);
3360 
3361 #if(PRODUCTION==0)
3362  if(FLUXB!=FLUXCTSTAG){// turned off by default for FLUXB==FLUXCTSTAG since even with PRODUCTION==0, FLUXB==FLUXCTSTAG's extended loop causes output at edges.
3363  PLOOP(pliter,pl) dUtoU_check(timeorder,i,j,k,loc,pl, dUgeom, dUcomp, dUriemann, CUf, CUnew, Ui, Uf, ucum);
3364  }
3365 #endif
3366 
3367  }
3368  else if(whichpl==DOBPL){
3369  PLOOPBONLY(pl) Uf[pl] = UFSET(CUf,dt,Ui[pl],Uf[pl],dUriemann[pl],dUnonrad[pl],dUradall[pl]);
3370  PLOOPBONLY(pl) ucum[pl] += UCUMUPDATE(CUnew,dt,Ui[pl],Uf[pl],dUriemann[pl],dUnonrad[pl],dUradall[pl]);
3371  }
3372  else if(whichpl==DONONBPL){
3373  PALLLOOPSPECIAL(pl,special) if(!BPL(pl)) Uf[pl] = UFSET(CUf,dt,Ui[pl],Uf[pl],dUriemann[pl],dUnonrad[pl],dUradall[pl]);
3374  PALLLOOPSPECIAL(pl,special) if(!BPL(pl)) ucum[pl] += UCUMUPDATE(CUnew,dt,Ui[pl],Uf[pl],dUriemann[pl],dUnonrad[pl],dUradall[pl]);
3375  }
3376 
3377  // if(nstep==4 && steppart==0 && whichpl==DONONBPL){
3378  // PALLLOOPSPECIAL(pl,special) dualfprintf(fail_file,"UtoU: %21.15g %21.15g %21.15g %21.15g\n",(CUf[0])*(Ui[pl]/globalgeom[pl]),(CUf[1])*(Uf[pl]/globalgeom[pl]),(CUf[2])*(dt)*((dUriemann[pl]/globalgeom[pl])+(dUgeom[pl]/globalgeom[pl])),CUf[2]*dt);
3379  // }
3380 
3381 
3382 }
3383 
3384 
3385 
3387 static void dUtoU_check(int timeorder, int i, int j, int k, int loc, int pl, FTYPE *dUgeom, FTYPE (*dUcomp)[NPR], FTYPE *dUriemann, FTYPE *CUf, FTYPE *CUnew, FTYPE *Ui, FTYPE *Uf, FTYPE *ucum)
3388 {
3389  int showfluxes;
3390  void show_fluxes(int i, int j, int k, int loc, int pl,FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL]);
3391 
3392 
3393  // default
3394  showfluxes=0;
3395 
3396  if(!isfinite(Uf[pl])){
3397  dualfprintf(fail_file,"dUtoU after: nan found for Uf[%d]=%21.15g\n",pl,Uf[pl]);
3398  dualfprintf(fail_file,"pl=%d Ui=%21.15g dUriemann=%21.15g dugeom=%21.15g\n",pl,Ui[pl],dUriemann[pl],dUgeom[pl]);
3399  showfluxes=1;
3400  }
3401  if(!isfinite(ucum[pl])){
3402  dualfprintf(fail_file,"dUtoU after: nan found for ucum[%d]=%21.15g\n",pl,ucum[pl]);
3403  dualfprintf(fail_file,"pl=%d Ui=%21.15g dUriemann=%21.15g dugeom=%21.15g\n",pl,Ui[pl],dUriemann[pl],dUgeom[pl]);
3404  showfluxes=1;
3405  }
3406 
3407  if(showfluxes){
3408  show_fluxes(i,j,k,loc,pl,GLOBALPOINT(F1),GLOBALPOINT(F2),GLOBALPOINT(F3));
3409  }
3410 
3411 
3412 }
3413 
3414 
3417 void ucum_check(int i, int j, int k, int loc, int pl, FTYPE *ucum)
3418 {
3419  int showfluxes;
3420 
3421 
3422  // default
3423  showfluxes=0;
3424 
3425  if(!isfinite(ucum[pl])){
3426  dualfprintf(fail_file,"ucum_check: nan found at i=%d j=%d k=%d loc=%d for ucum[pl=%d]=%21.15g\n",i,j,k,loc,pl,ucum[pl]);
3427  showfluxes=1;
3428  }
3429 
3430  if(showfluxes){
3431  show_fluxes(i,j,k,loc,pl,GLOBALPOINT(F1),GLOBALPOINT(F2),GLOBALPOINT(F3));
3432  }
3433 
3434 
3435 }
3436 
3438 static void show_fluxes(int i, int j, int k, int loc, int pl,FTYPE (*F1)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F2)[NSTORE2][NSTORE3][NPR+NSPECIAL],FTYPE (*F3)[NSTORE2][NSTORE3][NPR+NSPECIAL])
3439 {
3440  if(N1>1){
3441  dualfprintf(fail_file,"pl=%d i=%d j=%d k=%d :: F1[i]=%21.15g F1[i+1]=%21.15g dF1/dx1=%21.15g \n",pl,i,j,k,MACP0A1(F1,i,j,k,pl),MACP0A1(F1,i+SHIFT1,j,k,pl),(MACP0A1(F1,i+SHIFT1,j,k,pl)-MACP0A1(F1,i,j,k,pl))/dx[1]);
3442  }
3443  if(N2>1){
3444  dualfprintf(fail_file,"pl=%d i=%d j=%d k=%d :: F2[j]=%21.15g F2[j+1]=%21.15g dF2/dx2=%21.15g\n",pl,i,j,k,MACP0A1(F2,i,j,k,pl),MACP0A1(F2,i,j+SHIFT2,k,pl),(MACP0A1(F2,i,j+SHIFT2,k,pl)-MACP0A1(F2,i,j,k,pl))/dx[2]);
3445  }
3446  if(N3>1){
3447  dualfprintf(fail_file,"pl=%d i=%d j=%d k=%d :: F3[k]=%21.15g F3[k+1]=%21.15g dF3/dx3=%21.15g \n",pl,i,j,k,MACP0A1(F3,i,j,k,pl),MACP0A1(F3,i,j,k+SHIFT3,pl),(MACP0A1(F3,i,j,k+SHIFT3,pl)-MACP0A1(F3,i,j,k,pl))/dx[3]);
3448  }
3449 
3450 }
3451 
3452 
3453 
3456 int set_dt(FTYPE (*prim)[NSTORE2][NSTORE3][NPR], SFTYPE *dt)
3457 {
3458  struct of_state state;
3459  struct of_geom geomdontuse;
3460  struct of_geom *ptrgeom=&geomdontuse;
3461  int i,j,k;
3462  int pl,pliter;
3463  int jj,kk,ll;
3464  int dir,ignorecourant;
3465  FTYPE cmax1,cmin1;
3466  FTYPE cmax2,cmin2;
3467  FTYPE cmax3,cmin3;
3468  int wavendti[NDIM],wavendtj[NDIM],wavendtk[NDIM];
3469  int accdti,accdtj,accdtk;
3470  int gravitydti,gravitydtj,gravitydtk;
3471  FTYPE tempwavedt,tempaccdt,tempgravitydt;
3472  FTYPE dtij[NDIM]={BIG}, wavedt, accdt, gravitydt;
3473  FTYPE wavendt[NDIM];
3474  FTYPE wavedt_1,wavedt_2,wavedttemp;
3475  FTYPE ndtfinal;
3476  FTYPE dUgeom[NPR],dUcomp[NUMSOURCES][NPR];
3477  int enerregion;
3478  int *waveenerpos, *sourceenerpos;
3479  FTYPE X[NDIM],V[NDIM],Vp1[NDIM];
3480  FTYPE dUriemann[NPR];
3481  FTYPE Ugeomfree[NPR],U[NPR];
3482 
3483 
3484 
3485 
3486  wavedt_1=wavedt_2=wavedt=accdt=gravitydt=ndtfinal=BIG;
3487  wavendt[1]=wavendt[2]=wavendt[3]=BIG;
3488  wavendti[1]=wavendtj[1]=wavendtk[1]=-100;
3489  wavendti[2]=wavendtj[2]=wavendtk[2]=-100;
3490  wavendti[3]=wavendtj[3]=wavendtk[3]=-100;
3491  accdti=accdtj=accdtk=-100;
3492  gravitydti=gravitydtj=gravitydtk=-100;
3493 
3494  enerregion=OUTSIDEHORIZONENERREGION; // consistent with flux update (except when doing WHAM)
3495  sourceenerpos=enerposreg[enerregion];
3496 
3497  int didreturnpf=0; // used to have source() pass back better guess for Utoprimgen() than pb.
3498 
3499  // COMPFULLLOOP{ // want to use boundary cells as well to limit dt (otherwise boundary-induced changes not treated)
3500  LOOPWITHINACTIVESECTIONEXPAND1(i,j,k){ // only 1 grid cell within boundary. Don't need to use extrapolated cells deep inside boundary because those cells are not evolved. More consistent with how flux.c sets dt.
3501 
3502  // includes "ghost" zones in case boundary drives solution
3503  get_geometry(i, j, k, CENT, ptrgeom);
3504 
3505  // need full state for vchar()
3506  MYFUN(get_state(MAC(prim,i,j,k), ptrgeom, &state),"advance.c:set_dt()", "get_state()", 1);
3507 
3508 
3509 #if(N1>1)
3510  dir=1;
3511  MYFUN(vchar_all(MAC(prim,i,j,k), &state, dir, ptrgeom, &cmax1, &cmin1,&ignorecourant),"advance.c:set_dt()", "vchar_all() dir=1", 1);
3512  dtij[dir] = cour * dx[dir] / MAX(fabs(cmax1),fabs(cmin1));
3513  if(FORCESOLVEL){
3514  dtij[dir] = cour*dx[dir]*sqrt(ptrgeom->gcov[GIND(dir,dir)]);
3515  }
3516  if (dtij[dir] < wavendt[dir]){
3517  wavendt[dir] = dtij[dir];
3518  wavendti[dir] = i;
3519  wavendtj[dir] = j;
3520  wavendtk[dir] = k;
3521  }
3522 #endif
3523 
3524 #if(N2>1)
3525  dir=2;
3526  MYFUN(vchar_all(MAC(prim,i,j,k), &state, dir, ptrgeom, &cmax2, &cmin2,&ignorecourant),"advance.c:set_dt()", "vchar_all() dir=2", 1);
3527  dtij[dir] = cour * dx[dir] / MAX(fabs(cmax2),fabs(cmin2));
3528  if(FORCESOLVEL){
3529  dtij[dir] = cour*dx[dir]*sqrt(ptrgeom->gcov[GIND(dir,dir)]);
3530  }
3531  if (dtij[dir] < wavendt[dir]){
3532  wavendt[dir] = dtij[dir];
3533  wavendti[dir] = i;
3534  wavendtj[dir] = j;
3535  wavendtk[dir] = k;
3536  }
3537 #endif
3538 
3539 #if(N3>1)
3540  dir=3;
3541  MYFUN(vchar_all(MAC(prim,i,j,k), &state, dir, ptrgeom, &cmax3, &cmin3,&ignorecourant),"restart.c:set_dt()", "vchar_all() dir=3", 1);
3542  dtij[dir] = cour * dx[dir] / MAX(fabs(cmax3),fabs(cmin3));
3543  if(FORCESOLVEL){
3544  dtij[dir] = cour*dx[dir]*sqrt(ptrgeom->gcov[GIND(dir,dir)]);
3545  }
3546  if (dtij[dir] < wavendt[dir]){
3547  wavendt[dir] = dtij[dir];
3548  wavendti[dir] = i;
3549  wavendtj[dir] = j;
3550  wavendtk[dir] = k;
3551  }
3552 #endif
3553 
3554 
3555 
3556  // also get PERCELLDT==1 version
3557  wavedttemp = MINDTSET(dtij[1],dtij[2],dtij[3]);
3558  if(wavedttemp<wavedt_2) wavedt_2=wavedttemp;
3559 
3560 
3561 
3563  //
3564  // deal with source terms
3565  //
3567  if(WITHINENERREGION(sourceenerpos,i,j,k)){
3568 
3569 
3570 #if(LIMITDTWITHSOURCETERM)
3571 
3572  // conserved quantity without geometry
3573  MYFUN(primtoU(UEVOLVE, MAC(prim,i,j,k), &state, ptrgeom, U, NULL),"step_ch.c:advance()", "primtoU()", 1);
3574  PLOOP(pliter,pl) Ugeomfree[pl] = U[pl]*(ptrgeom->IEOMFUNCNOSINGMAC(pl));
3575 
3576  // get source term
3577  // GODMARK: here dUriemann=0, although in reality this setting of dt is related to the constraint trying to make
3578  PLOOP(pliter,pl) dUriemann[pl]=0.0;
3579  FTYPE CUf[NUMDTCUFS]={0.0}; // no update yet!
3580  int timeorder=0; // fake timeorder
3581  FTYPE *CUimp=&CUf[NUMPREDTCUFS+timeorder];
3582  // modifies prim() to be closer to final, which is ok here.
3583  // setup default eomtype
3584  int eomtype=EOMDEFAULT;
3585  MYFUN(source(MAC(prim,i,j,k), MAC(prim,i,j,k), MAC(prim,i,j,k), &didreturnpf, &eomtype, ptrgeom, &state, U, U, CUf, CUimp, 0.0, dUriemann, dUcomp, dUgeom),"advance.c:set_dt()", "source", 1);
3586 
3587  // get dt limit
3588  compute_dt_fromsource(ptrgeom,&state,MAC(prim,i,j,k), Ugeomfree, dUgeom, dUcomp[GEOMSOURCE], &tempaccdt, &tempgravitydt);
3589  if(accdt>tempaccdt){
3590  accdt=tempaccdt;
3591  accdti=i;
3592  accdtj=j;
3593  accdtk=k;
3594  }
3595  if(gravitydt>tempgravitydt){
3596  gravitydt=tempgravitydt;
3597  gravitydti=i;
3598  gravitydtj=j;
3599  gravitydtk=k;
3600  }
3601 
3602 #if(0)// DEBUG
3603  if(i==-1 || i==0){
3604  dualfprintf(fail_file,"BANG: i=%d\n",i);
3605  PLOOP(pliter,pl) dualfprintf(fail_file,"prim[%d]=%21.15g\n",pl,MACP0A1(prim,i,j,k,pl));
3606  PLOOP(pliter,pl) dualfprintf(fail_file,"dUgeom[%d]=%21.15g dUcompgeomsource=%21.15g\n",pl,dUgeom[pl],dUcomp[GEOMSOURCE][pl]);
3607  if(i==-1){
3608  // side-by-side
3609  coord(i,j,k,CENT,X);
3610  bl_coord(X,V);
3611  coord(ip1mac(i),j,k,CENT,X);
3612  bl_coord(X,Vp1);
3613  dualfprintf(fail_file,"r(i=-1)=%21.15g r(i=0)=%21.15g\n",V[1],Vp1[1]);
3614  dualfprintf(fail_file,"gdet(i=-1)=%21.15g gdet(i=0)=%21.15g\n",GLOBALMETMACP1A0(gdet,CENT,i,j,k),GLOBALMETMACP1A0(gdet,CENT,ip1mac(i),j,k));
3615  DLOOP(jj,kk) dualfprintf(fail_file,"%d %d gcov(i=-1)=%21.15g gcov(i=0)=%21.15g\n",jj,kk,GLOBALMETMACP1A2(gcov,CENT,i,j,k,jj,kk),GLOBALMETMACP1A2(gcov,CENT,ip1mac(i),j,k,jj,kk));
3616  DLOOP(jj,kk) dualfprintf(fail_file,"%d %d gcovlast(i=-1)=%21.15g gcovlast(i=0)=%21.15g\n",jj,kk,GLOBALMETMACP1A2(gcovlast,CENT,i,j,k,jj,kk),GLOBALMETMACP1A2(gcovlast,CENT,ip1mac(i),j,k,jj,kk));
3617  DLOOP(jj,kk) dualfprintf(fail_file,"%d %d gcon(i=-1)=%21.15g gcon(i=0)=%21.15g\n",jj,kk,GLOBALMETMACP1A2(gcon,CENT,i,j,k,jj,kk),GLOBALMETMACP1A2(gcon,CENT,ip1mac(i),j,k,jj,kk));
3618  DLOOP(jj,kk) DLOOPA(ll) dualfprintf(fail_file,"%d %d %d conn(i=-1)=%21.15g conn(i=0)=%21.15g\n",jj,kk,ll,GLOBALMETMACP0A3(conn,i,j,k,jj,kk,ll),GLOBALMETMACP0A3(conn,ip1mac(i),j,k,jj,kk,ll));
3619  }
3620  }
3621 #endif
3622 
3623 
3624 #endif
3625 
3626 
3627  } // end if within source enerregion
3628 
3629  } // end of loop
3630 
3631 
3632 
3633 
3634 
3635 
3636  // GODMARK: note that in normal advance, wavendt[i] is over each CPU region and wavedt computed for each CPU and then minimized over all CPUs -- so not perfectly consistent with MPI
3637  // here we preserve perfect MPI domain decomposition
3638  mpifmin(&wavendt[1]);
3639  mpifmin(&wavendt[2]);
3640  mpifmin(&wavendt[3]);
3641  // single all-CPU wavedt for PERCELLDT==0 version
3642  wavedt_1 = MINDTSET(wavendt[1],wavendt[2],wavendt[3]); // wavendt[i] is over entire region for each i
3643 
3644  // minimize per-cell dt over all CPUs for PERCELLDT==1 version
3645  mpifmin(&wavedt_2);
3646 
3647  // get actual version to use
3648  if(PERCELLDT==0) wavedt=wavedt_1;
3649  else wavedt=wavedt_2;
3650 
3651  // single all-CPU accdt and gravitydt
3652  mpifmin(&accdt);
3653  mpifmin(&gravitydt);
3654 
3655  wavedtglobal=wavedt;
3656  sourcedtglobal=accdt;
3657  gravitydtglobal=gravitydt;
3658 
3659 
3660  // find global minimum value of wavendt over all cpus
3661  ndtfinal=MIN(wavedt,MIN(accdt,gravitydt));
3662 
3663 #if(1)
3664  // below single line only right if 1-CPU
3665  SLOOPA(jj) dualfprintf(log_file,"dtij[%d]=%21.15g wavendti=%d wavendtj=%d wavendtk=%d\n",jj,wavendt[jj],wavendti[jj],wavendtj[jj],wavendtk[jj]);
3666  dualfprintf(log_file,"wavedt_1=%21.15g wavedt_2=%21.15g\n",wavedt_1,wavedt_2); // report this so can compare PERCELLDT==0 vs. 1 at least when starting or restarting runs
3667  dualfprintf(log_file,"ndtfinal=%21.15g wavedt=%21.15g accdt=%21.15g gravitydt=%21.15g\n",ndtfinal,wavedt,accdt,gravitydt);
3668  dualfprintf(log_file,"accdti=%d accdtj=%d accdtk=%d :: gravitydti=%d gravitydtj=%d gravitydtk=%d\n",accdti,accdtj,accdtk,gravitydti,gravitydtj,gravitydtk);
3669 #endif
3670 
3671  *dt = ndtfinal;
3672 
3673 
3674  // don't step beyond end of run
3675  if (t + *dt > tf) *dt = tf - t;
3676 
3677  return(0);
3678 }
3679 
3680 
3681 // 0.5 not good enough for pressureless collapse
3682 // normal cour=0.8/4 works for presureless collapse for longsteps, so use 0.1 to be safe since rarely gravity conquers timestep
3683 // but cour=0.8 and GRAVITYCOUR = 0.1 doesn't even work for longsteps!
3684 #define GRAVITYCOUR (0.1)
3685 
3687 static int compute_dt_fromsource(struct of_geom *ptrgeom, struct of_state *state, FTYPE *pr, FTYPE *U, FTYPE *dUevolvedt, FTYPE *dUgeomevolvedt, FTYPE *dtij, FTYPE *gravitydt)
3688 {
3689  FTYPE dUevolve[NDIM],dUgeomevolve[NDIM];
3690  FTYPE dUd[NDIM],dUu[NDIM];
3691  int jj,kk;
3692  FTYPE rhoprime[NDIM];
3693  FTYPE ag[NDIM],dtsource[NDIM];
3694  FTYPE rho,u,P,bsq,w,eta;
3695  FTYPE mydU[NDIM];
3696  FTYPE mydUdtgravity, rhoprimegravity, aggravity;
3697  FTYPE frac;
3698  int i,j,k,loc;
3699  extern void compute_dr(int i, int j, int k, FTYPE *dr);
3700  FTYPE dr,dphidt,phi,tempdt;
3701  FTYPE veleff;
3702  FTYPE v1max,v1min;
3703  FTYPE mydx[NDIM];
3704 
3705 
3706  i=ptrgeom->i;
3707  j=ptrgeom->j;
3708  k=ptrgeom->k;
3709  loc=ptrgeom->p;
3710 
3711  // default is no limit on dt due to flux differential or source terms
3712  *dtij=BIG;
3713  // default is no limit due to time-dependence of gravity
3714  *gravitydt=BIG;
3715 
3716 
3717  // convert from dU/dt to dU
3718  DLOOPA(jj){
3719  dUevolve[UU+jj] = dUevolvedt[UU+jj]*dt;
3720  dUgeomevolve[UU+jj] = dUgeomevolvedt[UU+jj]*dt;
3721  }
3722 
3723 
3724  DLOOPA(jj){
3725  dUd[jj]=dUevolve[UU+jj]*(ptrgeom->IEOMFUNCNOSINGMAC(UU+jj)); // remove geometry
3726  }
3727  raise_vec(dUd,ptrgeom,dUu);
3728 
3729  // comparing time update with time value, so keep lower as conserved quantity
3730  mydU[TT]=dUd[TT];
3731  mydUdtgravity = dUgeomevolvedt[UU]*(ptrgeom->IEOMFUNCNOSINGMAC(UU)); // pure gravity piece
3732 
3733  mydx[TT]=dt; // so in the end dt_time <=C*dt/(dU/rhoprime)
3734  SLOOPA(jj){
3735  // treating momentum update as giving dv^i, so for getting Courant condition of moving across grid, need upper
3736  mydU[jj] = dUu[jj];
3737  mydx[jj] = dx[jj];
3738  }
3739 
3740 
3741  bsq = dot(state->bcon, state->bcov);
3742  rho=pr[RHO];
3743  u=pr[UU];
3744  P=pressure_rho0_u_simple(i,j,k,loc,rho,u);
3745  w = rho+u+P;
3746  eta = w+bsq;
3747 
3748 
3749 
3750 
3751 
3753  //
3754  // New method for dealing with source terms
3755  //
3757 
3758  DLOOPA(jj){
3759  // U[UU] is like eta but with \gamma^2 factors that are present in the momentum terms
3760  // account for geometry prefactor of conserved quantities and put in geometry consistent with source term
3761  // U[UU] \sim eta \gamma^2 when neglecting stress terms
3762  // GODMARK: Might want to be more careful like in utoprim_jon.c in how normalize errors
3763  // GODMARK: Consider REMOVERESTMASSFROMUU==2 effects
3764  rhoprime[jj]=MAX(fabs(eta),fabs(U[UU]));
3765 
3766  // update to 3-velocity v^i is approximately due to this acceleration
3767  // ag^j \sim (\rho\gamma^2 v^i)/(\rho\gamma^2) \sim dv^i/dt
3768  // below is really = acceleration * dt
3769  ag[jj]=SMALL+fabs(mydU[jj]/rhoprime[jj]); // acceleration. SMALL is so doesn't identically vanish and we get nan below
3770 
3771  // for time, idea is to keep d\rho/\rho\lesssim cour, so dtnew = dtold *\rho/d\rho = dtold/ag[TT]
3772  if(jj==TT) dtsource[jj]=cour*(mydx[jj]/ag[jj]);
3773  // dt = dx/ag since ag is really = dv^i = dx^i/dt
3774  else dtsource[jj]=cour*(mydx[jj]/ag[jj]); // characteristic time-step for increasing velocity so mass would cross a grid
3775 
3776  }
3777 
3778 
3779 
3780 
3782  //
3783  // Self-gravity
3784  //
3786 
3787 #if(DOSELFGRAVVSR)
3788  // make sure metric is not varying too fast
3789  // just look at perturbed part of g_{tt} -- an invariant in stationary metrics, so good indicator of gauge-invariant time-dependence of metric
3790  // only look at loc=CENT since others should be similar to order unity -- also CENT won't diverge at r=0
3791  // frac = (METMACP1A1(gcovpertlast,CENT,i,j,k,TT) - METMACP1A1(gcovpert,CENT,i,j,k,TT))/(fabs(METMACP1A1(gcovpertlast,CENT,i,j,k,TT)) + fabs(METMACP1A1(gcovpert,CENT,i,j,k,TT)));
3792  // above frac has no dt, so no measure of what dt should be
3793 
3794  // \Gamma^t_{tt} measures dg_{tt}/dt
3795  // \Gamma^t_{tt} \approx g_{tt},t g^{tt} so that g_{tt},t = \Gamma^t_{tt}/g^{tt}
3796  // now form same construct as with (dU/dt)/U as above
3797  // g^{tt} can't go to 0 unless in bad coordinate system (BL-coords on horizon)
3798  // frac is approximately g_{tt},t/g^{tt} \aprox 1/dt
3799  // GODMARK: below might be problem in non-relativistic case
3800 
3801 
3802 
3803  // get \Gamma_{ttt} = dphi/dt ~ 1/2 g_{tt,t}
3804  dphidt=0.0;
3805  DLOOPA(jj) dphidt += GLOBALMETMACP0A3(conn,i,j,k,jj,TT,TT)*(ptrgeom->gcov[GIND(jj,TT)]);
3806  dphidt = fabs(dphidt); // don't care about sign, just magnitude
3807 
3808  // get \phi ~ -(g_{tt} +1)/2
3809  // phi by itself has no meaning, but as a reference for changes in phi in time it does
3810  phi = -(1.0+ptrgeom->gcov[GIND(TT,TT)])*0.5;
3811  phi = fabs(phi); // sign not important
3812 
3813 #if(0)
3814 
3815  // treat dt ~ \phi / (d\phi/dt)
3816  // frac = fabs(GLOBALMETMACP0A3(conn,i,j,k,TT,TT,TT)/((1+GLOBALMETMACP1A2(gcon,CENT,i,j,k,TT,TT))*(1+GLOBALMETMACP1A2(gcon,CENT,i,j,k,TT,TT))));
3817  frac = fabs(dphidt/phi);
3818  *gravitydt = cour*(GRAVITYCOUR/frac);
3819  // this dt keeps frac~cour
3820  // *gravitydt = cour*(GRAVITYCOUR/frac); // GRAVITYCOUR is additional courant factor on gravitational term
3821 
3822 
3823  // treat d\phi/dt as v^2/dt
3824  compute_dr( i, j, k, &dr);
3825  //dgttdt = fabs(GLOBALMETMACP0A3(conn,i,j,k,TT,TT,TT)/(GLOBALMETMACP1A2(gcon,CENT,i,j,k,TT,TT)));
3826  //tempdt = GRAVITYCOUR*pow(cour*cour*dr*dr/dgttdt,1.0/3.0); // GRAVITYCOUR in front is effective additional courant factor on gravitational term
3827  tempdt = GRAVITYCOUR*pow(cour*cour*dr*dr/dphidt,1.0/3.0); // GRAVITYCOUR in front is effective additional courant factor on gravitational term
3828 
3829  if(tempdt<*gravitydt) *gravitydt=tempdt;
3830 #elif(0)
3831 
3832  frac = fabs(ptrgeom->gcon[GIND(TT,TT)]*dphidt);
3833  *gravitydt = cour*(GRAVITYCOUR/frac);
3834 
3835 
3836 
3837 
3838 #elif(1)
3839 
3841  //
3842  // 3 methods to limit dt
3843  //
3845 
3846  // LOCAL DPHI/DT LIMIT
3847  // treat dt ~ \phi / (d\phi/dt)
3848  // frac = fabs(GLOBALMETMACP0A3(conn,i,j,k,TT,TT,TT)/((1+GLOBALMETMACP1A2(gcon,CENT,i,j,k,TT,TT))*(1+GLOBALMETMACP1A2(gcon,CENT,i,j,k,TT,TT))));
3849  frac = fabs(dphidt/phi);
3850  *gravitydt = cour*(GRAVITYCOUR/frac);
3851  // this dt keeps frac~cour
3852  // *gravitydt = cour*(GRAVITYCOUR/frac); // GRAVITYCOUR is additional courant factor on gravitational term
3853 
3854 
3855 
3856  compute_dr( i, j, k, &dr);
3857 
3858 
3859  // LOCAL DU/DT LIMIT BUT TREAT AS VELOCITY LIMITED BY SOL
3860 
3861 #if(REMOVERESTMASSFROMUU==2)
3862  rhoprimegravity=fabs(U[UU]); // gravity affects only \rho \phi -like terms order \rho v^2, not \rho
3863 #else
3864  // remove rest-mass
3865  rhoprimegravity=fabs(U[UU]+U[RHO]); // gravity affects only \rho \phi -like terms order \rho v^2, not \rho
3866 #endif
3867  aggravity=SMALL+fabs(mydUdtgravity/rhoprimegravity);
3868  veleff = aggravity*mydx[1];
3869 
3870  // get speed of light in 1-direction (dx^1/dt)
3871  sol(pr,state,1,ptrgeom,&v1max,&v1min);
3872  // limit "velocity" to speed of light
3873  if(veleff>fabs(v1min)) veleff=fabs(v1min);
3874  if(veleff>fabs(v1max)) veleff=fabs(v1max);
3875 
3876  tempdt=GRAVITYCOUR*cour*mydx[1]/veleff;
3877  if(tempdt<*gravitydt) *gravitydt=tempdt;
3878 
3879 
3880  // LOCAL LIMIT ON DPHI/DT WHERE PHI~V^2
3881  //dgttdt = fabs(GLOBALMETMACP0A3(conn,i,j,k,TT,TT,TT)/(GLOBALMETMACP1A2(gcon,CENT,i,j,k,TT,TT)));
3882  //tempdt = GRAVITYCOUR*pow(cour*cour*dr*dr/dgttdt,1.0/3.0); // GRAVITYCOUR in front is effective additional courant factor on gravitational term
3883  tempdt = GRAVITYCOUR*pow(cour*cour*dr*dr/dphidt,1.0/3.0); // GRAVITYCOUR in front is effective additional courant factor on gravitational term
3884  if(tempdt<*gravitydt) *gravitydt=tempdt;
3885 
3886 
3887 #endif
3888 
3889 
3890 
3891 
3892 #endif // end if DOSELFGRAVVSR==1
3893 
3894 
3895 
3896 
3897 
3898 
3899 
3900 
3901 
3902 
3904  //
3905  // Finally store source term's version of limited dt to be used later
3906  //
3908 
3909  // if(ptrgeom->i==30 && ptrgeom->j==31){
3910  // DLOOPA(jj) dualfprintf(fail_file,"dtsource[%d]=%21.15g : %21.15g : %21.15g %21.15g : %21.15g\n",jj,dtsource[jj],cour,mydx[jj],ag[jj],dUevolve[UU+jj]);
3911  //}
3912 
3913  // dualfprintf(fail_file,"i=%d mydUdtgravity=%21.15g rhoprimegravity=%21.15g rhoprime[TT]=%21.15g mydU[TT]=%21.15g\n",ptrgeom->i,mydUdtgravity,rhoprimegravity,rhoprime[TT],mydU[TT]);
3914 
3915  // always do time-component
3916  // accounts for thermal changes if cooling function or geometry changes if metric changing
3917  if (dtsource[TT] < *dtij) *dtij = dtsource[TT];
3918 
3919 #if(N1>1)
3920  if (dtsource[RR] < *dtij) *dtij = dtsource[RR];
3921 #endif
3922 #if(N2>1)
3923  if (dtsource[TH] < *dtij) *dtij = dtsource[TH];
3924 #endif
3925 #if(N3>1)
3926  if (dtsource[PH] < *dtij) *dtij = dtsource[PH];
3927 #endif
3928 
3929 
3930  return(0);
3931 
3932 }
3933 
3934 
3935 
3937 static int dUtodt(struct of_geom *ptrgeom, struct of_state *qaddr, FTYPE *pr, FTYPE *dUgeom, FTYPE *dUriemann, FTYPE *dUgeomgravity, FTYPE *accdt, FTYPE *gravitydt)
3938 {
3939  int pl,pliter;
3940  FTYPE dUtotal[NPR];
3941  FTYPE Ugeomfree[NPR],U[NPR];
3942 
3943 
3944 
3945  PLOOP(pliter,pl) {
3946  // while each piece may be "large", when summed if small then final change to conserved quantity is small, so that's all that's relevant
3947  dUtotal[pl]=dUriemann[pl]+dUgeom[pl];
3948  // GODMARK:
3949  // dUtotal[pl]=fabs(dUriemann[pl])+fabs(dUgeom[pl]);
3950  }
3951 
3952  // conserved quantity without geometry
3953  MYFUN(primtoU(UEVOLVE, pr, qaddr, ptrgeom, U, NULL),"step_ch.c:advance()", "primtoU()", 1);
3954  PLOOP(pliter,pl) Ugeomfree[pl] = U[pl]*(ptrgeom->IEOMFUNCNOSINGMAC(pl));
3955 
3956 
3957  compute_dt_fromsource(ptrgeom, qaddr, pr, Ugeomfree, dUtotal, dUgeomgravity, accdt, gravitydt);
3958 
3959 
3960 
3961  return(0);
3962 
3963 }
3964