HARM
harm and utilities
 All Data Structures Files Functions Variables Typedefs Macros Pages
vchar.c
Go to the documentation of this file.
1 
9 #include "decs.h"
10 
11 
12 
13 #define BOUNDARYSMOOTHER 0
14 
15 
16 #define SMOOTHFACTOR 2.0
17 
18 #define IGNORECOURANT 0
19 
20 
21 
24 #define CHECKSOL 0
25 
29 #define USEGROUPVEL 0
30 
31 //#define GTOL 1.e-8
33 
34 int vchar(FTYPE *pr, struct of_state *q, int dir, struct of_geom *geom, FTYPE *vmax, FTYPE *vmin,int *ignorecourant)
35 {
36  FTYPE vgmax,vgmin,ctsq;
37  FTYPE bsq, WW, EF, va2, cs2, cms2, rho, u, P;
38  int simplefast(int whichcall, int dir, struct of_geom *geom,struct of_state *q, FTYPE cms2,FTYPE *vmin, FTYPE *vmax);
39  int realfast(int dir, struct of_geom *geom,struct of_state *q, FTYPE EF,FTYPE cs2,FTYPE cms2,FTYPE va2,FTYPE *ucon,FTYPE *bcon,FTYPE *gcon,FTYPE *vmin,FTYPE *vmax);
40  int boundary_smoother(struct of_geom *ptrgeom, FTYPE *vmax, FTYPE *vmin, int *ignorecourant);
41  extern int limitv3(FTYPE *pr, struct of_state *q, int dir, struct of_geom *geom, FTYPE *v);
42  void groupvel(FTYPE *pr, struct of_state *q, int dir, struct of_geom *geom, FTYPE *vmax, FTYPE *vmin, FTYPE ctsq, FTYPE *vgmax, FTYPE *vgmin);
43 
44  int pl,pliter;
45  int i,j,k,loc;
46 
47 
48  i=geom->i;
49  j=geom->j;
50  k=geom->k;
51  loc=geom->p;
52 
53 
54  /* for regions along poles */
55  /*
56  if (geom->gdet < GTOL) {
57  *vmax = 0.;
58  *vmin = 0.;
59  return (0);
60  }
61  */
62 
63  /* find fast magnetosonic speed */
64 
65  // OPTMARK: If compute bsq using primitives, then can avoid computing b^\mu and b_\mu using get_state in wavespeeds.c
66  // OPTMARK: Localently TRUEFAST==0 does not need b^\mu b_\mu inside
67  // OPTMARK: These kind of calculations suggest storing B^\mu/u^t and B_\mu/u^t at least.
68  bsq = q->bsq; // OPTMARK: already stored now
69  // Then TRUEFAST==1 (i.e. realfast() function) requires b^\mu b_\mu, so compute old way anyways
70  // bsq = dot(q->bcon, q->bcov);
71 
72 
73  rho = pr[RHO];
74  u = pr[UU];
75  if(u<0) u=0; // cold fix
76  if(rho<0) rho=SMALL; // neg. density fix (so that u/rho=0 but rho==SMALL). Required to avoid NaN when computing cs2 in case both u<=0 and rho<=0.
77  P = q->pressure;
78 
79 
80  WW = rho + u + P;
81  if(WW>0.0){
82  cs2 = cs2_compute_simple(i,j,k,loc,rho,u);
83  }
84  else WW=cs2=SMALL;
85 
86  // make sure sound speed is well-defined (needed in case fundamental variables are temporarily unphysical)
87 
88  if(cs2>=1.0) cs2=1.0-NUMEPSILON*10.0; // some upper limit resolvable by machine precision
89  else if(cs2<=0.0) cs2=SMALL; // lower limit
90 
91 
92  // dualfprintf(fail_file,"rho=%g u=%g p=%g WW=%g cs2=%g\n",rho,u,P,WW,cs2);
93 
94 
95  EF = SMALL + fabs(bsq + WW);
96  va2 = bsq / EF;
97  // GODMARK: Was
98  // EF = bsq + WW;
99  // if(EF>0.0) va2 = bsq / EF;
100  // else EF=va2=0.0;
101 
102  cms2 = cs2 + va2 - cs2 * va2; /* and there it is... */
103 
104  //atch SASMARK debug print
105  //if( nstep == 1 && steppart == 0 && 95 == geom->i && 0 == geom->j && 0 == geom-> k ) {
106  // PLOOP(pliter,pl) dualfprintf( fail_file, "%21.15g\n", pr[pl] );
107  //}
108 
110  //
111  // check on it!
112  //
114  if(cms2!=cms2){
115  // then nan
116  PLOOP(pliter,pl) dualfprintf( fail_file, "pr[%d]=%21.15g\n", pl, pr[pl] ); //print out offensive primitives
117  if (fail(i,j,k,loc,FAIL_COEFF_NEG) >= 1){
118  dualfprintf(fail_file,"cms2=NaN: dir=%d :\n bsq=%21.15g\n rho=%21.15g\n u=%21.15g\n WW=%21.15g\n EF=%21.15g\n va2=%21.15g\n cs2=%21.15g\n cms2=%21.15g\n",dir,bsq,rho,u,WW,EF,va2,cs2,cms2);
119  return (1);
120  }
121  }
122 
123  if(cms2<0.0){
124  if (cms2/(cs2+va2) > -NUMEPSILON*100.0) cms2=0.0;
125  else{
126  if (fail(i,j,k,loc,FAIL_COEFF_NEG) >= 1){
127  dualfprintf(fail_file,"cms2<0.0 : dir=%d :\n bsq=%21.15g\n rho=%21.15g\n u=%21.15g\n WW=%21.15g\n EF=%21.15g\n va2=%21.15g\n cs2=%21.15g\n cms2=%21.15g\n",dir,bsq,rho,u,WW,EF,va2,cs2,cms2);
128  return (1);
129  }
130  }
131  }
132 
133  if (cms2 > 1.) {
134  if (cms2 < 1.0+NUMEPSILON*100.0) cms2=1.0;
135  else if (rho<0.0) cms2=1.0;
136  else{
137  dualfprintf(fail_file,"cms2>1.0 : dir=%d :\n bsq=%21.15g\n rho=%21.15g\n u=%21.15g\n WW=%21.15g\n EF=%21.15g\n va2=%21.15g\n cs2=%21.15g\n cms2=%21.15g\n",dir,bsq,rho,u,WW,EF,va2,cs2,cms2);
138  if (fail(i,j,k,loc,FAIL_COEFF_SUP) >= 1) return (1);
139  }
140  }
141 
142 
143 
144  if(TRUEFAST==1){
145 #if(0)
146  // DEBUG
147  if((ilocal==32)&&(jlocal==40)&&(klocal==32)){
148  stderrfprintf("%d %21.15g %21.15g %21.15g %21.15g\n",dir,EF,cs2,cms2,va2);
149  for(i=0;i<NDIM;i++) stderrfprintf("%21.15g ",ucon[i]); stderrfprintf("\n");
150  for(i=0;i<NDIM;i++) stderrfprintf("%21.15g ",bcon[i]); stderrfprintf("\n");
151  for(i=0;i<NDIM;i++){ for(j=0;j<NDIM;j++) stderrfprintf("%21.15g ",gcon[GIND(i,j)]); stderrfprintf("\n");}
152  }
153 #endif
154 
155  if(realfast(dir,geom,q,EF,cs2,cms2,va2,q->ucon,q->bcon,geom->gcon,vmin,vmax)>=1){
156  dualfprintf(fail_file,"vchar.c: truefast() failed\n");
157  dualfprintf(fail_file,"truefast() failed : dir=%d :\n bsq=%21.15g\n rho=%21.15g\n u=%21.15g\n WW=%21.15g\n EF=%21.15g\n va2=%21.15g\n cs2=%21.15g\n cms2=%21.15g\n",dir,bsq,rho,u,WW,EF,va2,cs2,cms2);
158  return(1);
159  }
160  }
161  else if(TRUEFAST==0){
162  if(simplefast(0, dir,geom, q, cms2,vmin,vmax)>=1){
163  dualfprintf(fail_file,"vchar.c: simplefast() failed\n");
164  dualfprintf(fail_file,"simplefast() failed : dir=%d :\n bsq=%21.15g\n rho=%21.15g\n u=%21.15g\n WW=%21.15g\n EF=%21.15g\n va2=%21.15g\n cs2=%21.15g\n cms2=%21.15g\n",dir,bsq,rho,u,WW,EF,va2,cs2,cms2);
165  return(1);
166  }
167  }
168 
169 
170 
171 #if(0)
172  if(realfast(dir,geom,q,EF,cs2,cms2,va2,q->ucon,q->bcon,geom->gcon,vmin,vmax)>=1) return(1);
173  stderrfprintf("%d %d\n",geom->i,geom->j);
174  stderrfprintf("rf: vmax=%21.15g vmin=%21.15g\n",*vmax,*vmin);
175  if(simplefast(0, dir,geom, q, cms2,vmin,vmax)>=1) return(1);
176  stderrfprintf("sf: vmax=%21.15g vmin=%21.15g\n",*vmax,*vmin);
177 #endif
178 
179 
180 
181 
182 
183 
184 #if(BOUNDARYSMOOTHER)
185  boundary_smoother(geom,vmax,vmin,ignorecourant);
186 #else
187  *ignorecourant=0;
188 #endif
189 
190  // if(cms2==1.0){// isfinite
191  // dualfprintf(fail_file,"1 cms2=%21.15g vmin=%21.15g vmax=%21.15g\n",cms2,*vmin,*vmax);
192  // }
193  //if(!isfinite(*vmin)){
194  // dualfprintf(fail_file,"2 cms2=%21.15g vmin=%21.15g vmax=%21.15g\n",cms2,*vmin,*vmax);
195  // }
196  //if(!isfinite(*vmax)){
197  // dualfprintf(fail_file,"3 cms2=%21.15g vmin=%21.15g vmax=%21.15g\n",cms2,*vmin,*vmax);
198  // }
199 
200 
201 #if(USEGROUPVEL)
202  // ct^2 = (va^2 + cs^2(1-va^2) ) / ( 1 - (va^2+cs^2(1-va^2)))
203  // only really correct with simplified dispersion relation
204  ctsq=(va2+cs2*(1.0-va2))/(1.0-(va2+cs2*(1.0-va2)));
205  groupvel(pr,q,dir,geom,vmax,vmin,ctsq,&vgmax,&vgmin);
206  *vmax=vgmax;
207  *vmin=vgmin;
208 #endif
209 
210 
211  // check to make sure phase velocity is not greater than speed of light
212 #if(CHECKSOL)
213  limitv3(pr,q,dir,geom,vmax);
214  limitv3(pr,q,dir,geom,vmin);
215 #endif
216 
217 
218  return (0);
219 }
220 
221 
223 int boundary_smoother(struct of_geom *geom, FTYPE *vmax, FTYPE *vmin, int *ignorecourant)
224 {
225 
226 
227  if(
228  // x3-surfaces
229  // 1-zones
230  (((geom->p==CENT)||(geom->p==FACE1)||(geom->p==FACE2)||(geom->p==CORN3))&&((startpos[3]+geom->k<=0)||(startpos[3]+geom->k>=totalsize[3]-1))) ||
231  // 2-zones
232  (((geom->p==FACE3)||(geom->p==CORN1)||(geom->p==CORN2))&&((startpos[3]+geom->k<=1)||(startpos[3]+geom->k>=totalsize[3]-1))) ||
233 
234  // x2-surfaces
235  // 1-zones
236  (((geom->p==CENT)||(geom->p==FACE1)||(geom->p==FACE3)||(geom->p==CORN2))&&((startpos[2]+geom->j<=0)||(startpos[2]+geom->j>=totalsize[2]-1))) ||
237  // 2-zones, but for POLARAXIS, absolute face2 on boundary always leads to 0 flux, so only difference can be next zone value.
238  (((geom->p==FACE2)||(geom->p==CORN3)||(geom->p==CORN1))&&((startpos[2]+geom->j<=1)||(startpos[2]+geom->j>=totalsize[2]-1))) ||
239 
240  // x1-surfaces
241  // 1-zones
242  (((geom->p==CENT)||(geom->p==FACE2)||(geom->p==FACE3)||(geom->p==CORN1))&&((startpos[1]+geom->i<=0)||(startpos[1]+geom->i>=totalsize[1]-1))) ||
243  // 2-zones
244  (((geom->p==FACE1)||(geom->p==CORN3)||(geom->p==CORN2))&&((startpos[1]+geom->i<=1)||(startpos[1]+geom->i>=totalsize[1]-1)))
245  ){
246  *ignorecourant=IGNORECOURANT;
247  *vmax *=SMOOTHFACTOR;
248  *vmin *=SMOOTHFACTOR;
249  }
250  else{
251  // don't normally ignore vmin/vmax in Courant condition
252  *ignorecourant=0;
253  }
254 
255  return(0);
256 }
257 
258 
259 
260 
261 #define USESASHAREWRITE 1 // whether to use WHAM form that avoids catastrophic cancellation in non-rel and ultra-rel regimes.
262 
263 int simplefast(int whichcall, int dir,struct of_geom *geom, struct of_state *q, FTYPE cms2,FTYPE *vmin, FTYPE *vmax)
264 {
265  FTYPE discr;
266  FTYPE Acov[NDIM], Bcov[NDIM], Acon[NDIM], Bcon[NDIM];
267  FTYPE Asq, Bsq, Au, Bu, AB, Au2, Bu2, AuBu, A, B, C;
268  FTYPE vm,vp;
269  int j,k;
270  int ii,jj,kk,loc;
271 
272 
273  ii=geom->i;
274  jj=geom->j;
275  kk=geom->k;
276  loc=geom->p;
277 
278 
280  //
281  // Setup vectors for wave speed calculation
282  //
284 
285 
286  DLOOPA(j) Acov[j] = 0.;
287  Acov[dir] = 1.;
288  raise_vec(Acov, geom, Acon);
289 
290  DLOOPA(j) Bcov[j] = 0.;
291  Bcov[TT] = 1.;
292  raise_vec(Bcov, geom, Bcon);
293 
294 
295 
297  //
298  // now require that speed of wave measured by observer q->ucon is cms2
299  //
301  Asq = dot(Acon, Acov);
302  Bsq = dot(Bcon, Bcov);
303  Au = dot(Acov, q->ucon);
304  Bu = dot(Bcov, q->ucon);
305  AB = dot(Acon, Bcov);
306  Au2 = Au * Au;
307  Bu2 = Bu * Bu;
308  AuBu = Au * Bu;
309 
310 
311  // JCM: grouped cms2 with 1.0 so good in ultrarelativistic regime.
312  // was getting A=B=0 and giving vm=vp=inf, when really wasn't A=B=0! That is, code was failing when cms=1 and A=B=0
313  B = 2. * (AuBu * (1.0-cms2) - AB*cms2);
314  //B = 2. * (AuBu - (AB + AuBu) * cms2);
315  A = Bu2 * (1.0 - cms2) - Bsq * cms2;
316  // A = Bu2 - (Bsq + Bu2) * cms2;
317 
318 
319 #if(USESASHAREWRITE==0)
320  C = Au2*(1.0-cms2) - Asq * cms2;
321  // C = Au2 - (Asq + Au2) * cms2;
322 
323  // order unity normalized already
324  discr = B * B - 4.0 * A * C;
325 #else
326  //REWRITTEN without catastrophic cancellation for both non-rel and ultrarel regimes.
327  discr = 4.0 * cms2 *
328  (
329  (AB * AB - Asq * Bsq) * cms2
330  + (2.0 * AB * Au * Bu - Asq * Bu2 - Bsq * Au2) * (cms2 - 1.0)
331  );
332 #endif
333 
334 
335 
336 
337 
339  //
340  // Check if bad discr and report/fail if so
341  //
343 
344  if((discr<0.0)&&(discr> -1E-10)) discr=0.0; //atch: negative but not too much -- allow fractional error of 1e-10
345  else if(discr<0.0){ //if discriminant is too negative
346  dualfprintf(fail_file,"simplefast discr=%21.15g, nstep = %ld, steppart == %d, i = %d, j = %d, k = %d, p = %d\n",
347  discr, nstep, steppart, geom->i, geom->j, geom->k, geom->p );
348 
349  DLOOP(j,k){
350  dualfprintf(fail_file,"geom->gcov[%d][%d]=%21.15g\n",j,k,geom->gcov[GIND(j,k)]);
351  }
352 
353  DLOOP(j,k){
354  dualfprintf(fail_file,"geom->gcon[%d][%d]=%21.15g\n",j,k,geom->gcon[GIND(j,k)]);
355  }
356 
357 #if(USESASHAREWRITE==0)
358  dualfprintf(fail_file, "\n\t A=%21.15g B=%21.15g C=%21.15g discr=%21.15g cms2=%21.15g\n", A, B, C, discr, cms2);
359 #else
360  dualfprintf(fail_file, "\n\t A=%21.15g discr=%21.15g cms2=%21.15g\n", A, discr, cms2);
361 #endif
362  dualfprintf(fail_file, "\n\t q->ucon: %21.15g %21.15g %21.15g %21.15g\n", q->ucon[0],
363  q->ucon[1], q->ucon[2], q->ucon[3]);
364  dualfprintf(fail_file, "\n\t q->bcon: %21.15g %21.15g %21.15g %21.15g\n", q->bcon[0],
365  q->bcon[1], q->bcon[2], q->bcon[3]);
366  dualfprintf(fail_file, "\n\t Acon: %21.15g %21.15g %21.15g %21.15g\n", Acon[0], Acon[1],
367  Acon[2], Acon[3]);
368  dualfprintf(fail_file, "\n\t Bcon: %21.15g %21.15g %21.15g %21.15g\n", Bcon[0], Bcon[1],
369  Bcon[2], Bcon[3]);
370  if (fail(ii,jj,kk,loc,FAIL_VCHAR_DISCR) >= 1) return (1);
371  discr = 0.;
372  }
373 
374 
375 
377  //
378  // Compute actual discr
379  //
381 
382 
383  discr = sqrt(discr);
384 
385 
387  //
388  // Compute left- and right-going wavespeeds
389  //
390  // order not obvious
391  //
393  vm = -(-B + discr) / (2. * A);
394  vp = -(-B - discr) / (2. * A);
395 
396 
397 
399  //
400  // isfinite check -- non-debug check
401  //
403  if( (!isfinite(vm)) || (!isfinite(vp)) ){
404 #if(USESASHAREWRITE==0)
405  dualfprintf(fail_file,"vm=%21.15g vp=%21.15g discr=%21.15g A=%21.15g B=%21.15g C=%21.15g\n",vm,vp,discr,A,B,C);
406 #else
407  dualfprintf(fail_file,"vm=%21.15g vp=%21.15g discr=%21.15g A=%21.15g B=%21.15g\n",vm,vp,discr,A,B);
408 #endif
409  dualfprintf(fail_file,"i=%d j=%d k=%d p=%d nstep=%ld steppart=%d\n",geom->i,geom->j,geom->k,geom->p,nstep,steppart);
410  dualfprintf(fail_file,"cms2=%21.15g\n",cms2);
411  dualfprintf(fail_file,"dir=%d g=%21.15g uu0=%21.15g uu1=%21.15g uu2=%21.15g uu3=%21.15g\n",dir,geom->gdet,q->ucon[TT],q->ucon[RR],q->ucon[TH],q->ucon[PH]);
412  dualfprintf(fail_file,"vmin=%21.15g vmax=%21.15g\n",vm,vp);
413  // myexit(10001); // hard failure so look back and see what's wrong with code
414 
415  if(finite(cms2) && whichcall==0){
416  // best that can do is assume ZAMO relative 4-velocity with inputted cms2
417  FTYPE prbackup[NPR];
418  set_zamo_velocity(WHICHVEL,geom,prbackup);
419  struct of_state qbackup;
420  get_state(prbackup,geom,&qbackup);
421  simplefast(1, dir,geom, &qbackup, cms2,vmin, vmax); // simplefast(1)
422  if( (!isfinite(*vmin)) || (!isfinite(*vmax)) ){
423  dualfprintf(fail_file,"Backup vchar still failed\n");
424  }
425  else{
426  vm=*vmin;
427  vp=*vmax;
428  }
429  }
430  else{
431  // then really nothing can do
432  }
433 
434 
435  return(1); // yes, hard failure, but need trace information
436  }
437 
438 
439 
441  //
442  // re-order so left is really left and right really right
443  //
445 
446  if (vp < vm) {
447  *vmax = vm;
448  *vmin = vp;
449  }
450  else{
451  *vmax = vp;
452  *vmin = vm;
453  }
454 
455 
456  // done
457  return(0);
458 }
459 
460 
463 int realfast(int dir, struct of_geom *geom,struct of_state *q, FTYPE EF,FTYPE cs2,FTYPE cms2,FTYPE va2,FTYPE *ucon,FTYPE *bcon,FTYPE *gcon,FTYPE *vmin,FTYPE *vmax)
464 {
465  FTYPE va02,vax2,va0x2,uux;
466  FTYPE oEF;
467  FTYPE gn300,gn3xx,gn30x;
468  FTYPE uu0;
469  FTYPE AA,BB,CC,DD,EE;
470  FTYPE uuxsq,uux3,uux4,uu0sq,uu03,uu04;
471  FTYPE quarticsol(FTYPE sign1, FTYPE sign2,FTYPE AAA,FTYPE BBB,FTYPE CCC,FTYPE DDD,FTYPE EEE);
472  int i,j;
473 
474 
475  oEF=1.0/EF;
476  gn300=gcon[GIND(0,0)];
477  va02=bcon[0]*bcon[0]*oEF;
478  uu0=ucon[0];
479 
480  vax2=bcon[dir]*bcon[dir]*oEF;
481  va0x2=bcon[0]*bcon[dir]*oEF;
482  uux=ucon[dir];
483  gn3xx=gcon[GIND(dir,dir)];
484  gn30x=gcon[GIND(0,dir)];
485 
486  uuxsq=uux*uux;
487  uux3=uuxsq*uux;
488  uux4=uuxsq*uuxsq;
489  uu0sq=uu0*uu0;
490  uu03=uu0sq*uu0;
491  uu04=uu0sq*uu0sq;
492 
493  // quartic coefficients
494  EE=uux4 - cms2*uuxsq*(gn3xx + uuxsq) + cs2*gn3xx*vax2;
495  DD=2.*(-2.*uu0*uux3 + cms2*uux*(gn3xx*uu0 + uux*(gn30x + 2.*uu0*uux)) - cs2*gn3xx*va0x2 - cs2*gn30x*vax2);
496  CC=6.*uu0sq*uuxsq - cms2*(gn3xx*uu0sq + uux*(4.*gn30x*uu0 + gn300*uux + 6.*uu0sq*uux)) + cs2*(4.*gn30x*va0x2 + gn3xx*va02 + gn300*vax2);
497  BB=2.*(-2.*uu03*uux + cms2*uu0*(gn300*uux + uu0*(gn30x + 2.*uu0*uux)) - cs2*gn300*va0x2 - cs2*gn30x*va02);
498  AA=uu04 - cms2*uu0sq*(gn300 + uu0sq) + cs2*gn300*va02;
499 
500 
501 #if(0)
502  // test
503  AA=4.36134649461842;
504  BB=0.953704334932897;
505  CC=0.00501787191044863;
506  DD=-0.0036931214344023;
507  EE=3.97410207658954e-05;
508 #endif
509 
510  *vmax=quarticsol(1.0,1.0,AA,BB,CC,DD,EE);
511  *vmin=quarticsol(-1.0,-1.0,AA,BB,CC,DD,EE);
512 
513 
514  return(0);
515 
516 }
517 
519 FTYPE quarticsol(FTYPE sign1, FTYPE sign2,FTYPE AAA,FTYPE BBB,FTYPE CCC,FTYPE DDD,FTYPE EEE)
520 {
521  FTYPE unit1,unit2,unit3,newradius,newphi,unit4;
522  FTYPE part1,part2,part25,part3;
523  FTYPE AAAsq,AAAcu,BBBsq,BBBcu,CCCsq,CCCcu,DDDsq,unit1sq,unit2sq,unit2cu;
524  FTYPE disc;
525 
526  AAAsq=AAA*AAA;
527  AAAcu=AAAsq*AAA;
528  BBBsq=BBB*BBB;
529  BBBcu=BBBsq*BBB;
530  CCCsq=CCC*CCC;
531  CCCcu=CCCsq*CCC;
532  DDDsq=DDD*DDD;
533 
534  unit1=2.*CCCcu - 9.*BBB*CCC*DDD + 27.*AAA*DDDsq + 27.*BBBsq*EEE - 72.*AAA*CCC*EEE;
535  // unit2 is always positive or 0
536  unit2=CCCsq - 3.*BBB*DDD + 12.*AAA*EEE;
537 
538  unit2sq=unit2*unit2;
539  unit2cu=unit2sq*unit2;
540  unit1sq=unit1*unit1;
541 
542  // unit3 is always negative or 0, but may be positive due to machine precision error
543  unit3=-4.*unit2cu + unit1sq;
544  if((unit3>0.0)&&(unit3<1E-3)) unit3=0.0;
545  else if(unit3>1E-3){
546  dualfprintf(fail_file,"unit3=%21.15g\n",unit3);
547  exit(0);
548  }
549 
550  newradius=sqrt(unit1sq+fabs(-unit3));
551  // ATAN2(y,x) where tan(phi)=y/x
552  newphi=atan2(sqrt(-unit3),unit1);
553  // unit4 is always positive
554  unit4=(1./(3.*AAA))*pow(2.,(2./3.))*pow(newradius,(1./3.))*cos(newphi/3.);
555 
556  // part1 can be anything
557  part1 = -BBB/(4.*AAA);
558 
559  // part2 >0 always
560  disc=BBBsq/(4.*AAAsq) - 2./3.*CCC/AAA + unit4;
561 
562  // disc already normalized
563  if(disc<0.0){
564  if(disc>-NUMEPSILON*100.0){
565  part2=0.0;
566  part3=0.0;
567  }
568  else{
569  dualfprintf(fail_file,"part2 disc=%21.15g\n",disc);
570  myexit(1);
571  }
572  }
573  else{
574  part2 = sqrt(disc);
575 
576  // part25 can be anything
577  part25 = (-BBBcu/AAAcu + 4.*BBB*CCC/AAAsq - 8.*DDD/AAA)/(4.*part2);
578 
579  // part3>0 always
580  disc=BBBsq/(2.*AAAsq) - 4./3.*CCC/AAA - unit4 +sign1*part25;
581 
582  //disc already normalized
583  if(disc<0.0){
584  if(disc>-NUMEPSILON*100.0) disc=0.0;
585  else{
586  dualfprintf(fail_file,"part3 disc=%21.15g\n",disc);
587  myexit(1);
588  }
589  }
590  part3 = sqrt(disc);
591  }
592 
593 
594  return(part1 +sign1* 0.5*part2 +sign2* 0.5*part3);
595 }
596 
607 void groupvel(FTYPE *pr, struct of_state *q, int dir, struct of_geom *geom, FTYPE *vmax, FTYPE *vmin, FTYPE ctsq, FTYPE *vgmax, FTYPE *vgmin)
608 {
609  FTYPE uu[NDIM],vg[NDIM];
610  FTYPE kd[NDIM],ku[NDIM],omega;
611  FTYPE uu0,vu[NDIM];
612  FTYPE vp,vdiff;
613  FTYPE git,gtt,gii;
614  FTYPE ctrat;
615  int j;
616  FTYPE vgd[NDIM];
617  FTYPE isone1,isone2;
618 
619 
620 
621 #if(0)
622  uu0=q->ucon[TT];
623  SLOOPA(j) vu[j]=q->ucon[j]/uu0;
624 
625  ctrat=ctsq/(uu0*uu0);
626 
627  git=geom->gcon[GIND(dir,TT)];
628  gtt=geom->gcon[GIND(TT,TT)];
629  gii=geom->gcon[GIND(dir,dir)];
630 
631 
632  // omega=k.u
633  //#define numerator (vu[dir]*vdiff-ctrat*(git*uu0*vdiff+gii)) // vg^i/(u^t)^2
634  //#define denominator (vdiff-ctrat*(uu0*vdiff*gtt+git)) // vg^t/(u^t)^2
635 
636  // omega=-k.u
637  //#define numerator (vu[dir]*vdiff-ctrat*(git*uu0*vdiff-gii)) // vg^i/(u^t)^2
638  //#define denominator (vdiff-ctrat*(uu0*vdiff*gtt-git)) // vg^t/(u^t)^2
639 
640  // correct omega=-k.u and k=ke(-vp,e)
641  //#define numerator (vu[dir]*vdiff-ctrat*(git*vp-gii)) // vg^i/(u^t)^2
642  //#define denominator (vdiff-ctrat*(gtt*vp-git)) // vg^t/(u^t)^2
643 
644  vp=*vmax;
645  vdiff=(vu[dir]-vp);
646  *vgmax=numerator/denominator;
647 
648  vp=*vmin;
649  vdiff=(vu[dir]-vp);
650  *vgmin=numerator/denominator;
651 #endif
652 
653  DLOOPA(j) uu[j]=q->ucon[j];
654 
655  DLOOPA(j) kd[j]=0.0;
656  kd[TT]=-*vmax;
657  kd[dir]=1.0;
658  raise_vec(kd,geom,ku);
659  omega=0.0; DLOOPA(j) omega+=-kd[j]*uu[j];
660  DLOOPA(j) vg[j]=(-omega*uu[j]-ctsq*ku[j]);
661  *vgmax=vg[dir]/vg[TT];
662 
663 #if(0)
664  // check if really 4-velocity
665  lower_vec(vg,geom,vgd);
666  isone1=0.0;
667  DLOOPA(j) isone1+=vg[j]*vgd[j];
668  isone1/=(omega*omega*(1.0+ctsq));
669 
670  // check 3-velocity
671  dualfprintf(fail_file,"vmax: vfx=%21.15g vgx=%21.15g : vfy=%21.15g vgy=%21.15g : vfz=%21.15g vgz=%21.15g\n",q->ucon[1]/q->ucon[0],vg[1]/vg[0],q->ucon[2]/q->ucon[0],vg[2]/vg[0],q->ucon[3]/q->ucon[0],vg[3]/vg[0]);
672 #endif
673 
674  DLOOPA(j) kd[j]=0.0;
675  kd[TT]=-*vmin;
676  kd[dir]=1.0;
677  raise_vec(kd,geom,ku);
678  omega=0.0; DLOOPA(j) omega+=-kd[j]*uu[j];
679  DLOOPA(j) vg[j]=(-omega*uu[j]-ctsq*ku[j]);
680  *vgmin=vg[dir]/vg[TT];
681 
682 #if(0)
683  // check if really 4-velocity
684  lower_vec(vg,geom,vgd);
685  isone2=0.0;
686  DLOOPA(j) isone2+=vg[j]*vgd[j];
687  isone2/=(omega*omega*(1.0+ctsq));
688 
689  // check if really 4-velocity
690  dualfprintf(fail_file,"%d %d : isone: %21.15g %21.15g\n",geom->i,geom->j,isone1,isone2);
691  // checks out.
692 
693 
694  // check 3-velocity
695  dualfprintf(fail_file,"vmin: vfx=%21.15g vgx=%21.15g : vfy=%21.15g vgy=%21.15g : vfz=%21.15g vgz=%21.15g\n",q->ucon[1]/q->ucon[0],vg[1]/vg[0],q->ucon[2]/q->ucon[0],vg[2]/vg[0],q->ucon[3]/q->ucon[0],vg[3]/vg[0]);
696 
697 #endif
698 
699 }