HARM
harm and utilities
 All Data Structures Files Functions Variables Typedefs Macros Pages
tetrad.c
Go to the documentation of this file.
1 
6 #include "decs.h"
7 
9 
10 // declarations
11 static int compute_tetrcon_frommetric_mathematica(FTYPE (*generalmatrix)[NDIM], FTYPE (*tetrcon)[NDIM], FTYPE eigenvalues[]);
12 static int compute_tetrcon_frommetric(FTYPE (*generalmatrix)[NDIM], FTYPE (*tetrcon)[NDIM], FTYPE eigenvalues[]);
13 
14 static int tetlapack_func_prec(FTYPE (*metr)[NDIM], FTYPE (*tetr)[NDIM], FTYPE eigenvalues[]);
15 
18 int tetr_func_frommetric(int primcoord, FTYPE (*dxdxp)[NDIM], FTYPE *gcov, FTYPE (*tetrcov)[NDIM],FTYPE (*tetrcon)[NDIM], FTYPE eigenvalues[])
19 {
20  int jj,kk;
21  int ll,pp;
22  FTYPE idxdxp[NDIM][NDIM];
24  int info;
25 
26  if(primcoord){
27  // get MCOORD metric from PRIMECOORD metric
28  idxdxprim(dxdxp, idxdxp);
29 
30  DLOOP(jj,kk){
31  newgcov[GIND(jj,kk)]=0.0;
32  DLOOP(ll,pp) {
33  newgcov[GIND(jj,kk)] += GINDASSIGNFACTOR(jj,kk)*gcov[GIND(ll,pp)]*idxdxp[ll][jj]*idxdxp[pp][kk];
34  }
35  }
36  }
37  else{
38  // then just copy
39  DLOOP(jj,kk) newgcov[GIND(jj,kk)]=gcov[GIND(jj,kk)];
40  }
41 
42 
43  // DEBUG
44  // if(tiglobal[1]==200 && tiglobal[2]==10 && tiglobal[3]==0){
45  // DLOOP(jj,kk) dualfprintf(fail_file,"jj=%d kk=%d newgcov=%21.15g\n",jj,kk,newgcov[GIND(jj,kk)]);
46  // }
47 
48  // get tetrad (feed newgcov rather than gcov since with metric assume best comparison of vectors when have non-twisted metric and likely untwisted when using dxdxp)
49  info=tetr_func(METRICTETRAD, newgcov, tetrcov, tetrcon, eigenvalues);
50 
51  return(info);
52 
53 }
54 
56 static int tetlapack_func_prec(FTYPE (*metr)[NDIM], FTYPE (*tetr)[NDIM], FTYPE eigenvalues[])
57 {
58  int info;
59 
60  extern int tetlapack_func(double (*metrin)[NDIM], double (*tetrout)[NDIM], double eigenvaluesout[]);
61 
62 #if(SUPERLONGDOUBLE==0)
63  info=tetlapack_func(metr,tetr,eigenvalues);
64 #else
65  // external call to function in tetlapack_func_doubleonly.c
66  double metrin[NDIM][NDIM],tetrout[NDIM][NDIM],eigenvaluesout[NDIM];
67  int jj,kk;
68  DLOOP(jj,kk) metrin[jj][kk] = (double)metr[jj][kk];
69  info=tetlapack_func(metrin,tetrout,eigenvaluesout);
70  DLOOP(jj,kk) tetr[jj][kk] = (FTYPE)tetrout[jj][kk];
71  DLOOPA(jj) eigenvalues[jj] = (FTYPE)eigenvaluesout[jj];
72 #endif
73 
74  return(info);
75 }
76 
77 
80 int tetr_func(int inputtype, FTYPE *gcov, FTYPE (*tetr_cov)[NDIM],FTYPE (*tetr_con)[NDIM], FTYPE eigenvalues[])
81 {
82  FTYPE generalmatrixlower[NDIM][NDIM];
83  FTYPE tmpgeneralmatrix[NDIM][NDIM] ;
84  FTYPE tmpgeneralvec[NDIM] ;
85  int j,k,l ;
86  int info;
87  int jj,kk;
88 
89  // copy to 2D space
90  DLOOP(jj,kk) generalmatrixlower[jj][kk] = gcov[GIND(jj,kk)];
91 
92 
93  if(inputtype==METRICTETRAD){
94  info=compute_tetrcon_frommetric(generalmatrixlower,tetr_con,eigenvalues);
95  }
96  else{
97  info=tetlapack_func_prec(generalmatrixlower,tetr_con,eigenvalues);
98  }
99 
100  // force tetr_con to have correct signature so when applied it gives back vector as if nothing done (i.e. Kronecker Delta) (e.g. Minkowski to Minkowski)
101  // Tcon_j^l = Tconorig^{al} \eta_{ja}
102  // So first index is orthonormal and second index is old coordinate basis
103  DLOOP(j,k) tmpgeneralmatrix[j][k] = tetr_con[j][k];
104  DLOOP(j,k) tetr_con[j][k] = 0. ;
105  DLOOP(j,k) for(l=0;l<NDIM;l++) tetr_con[j][k] += mink(j,l)*tmpgeneralmatrix[l][k] ;
106 
107  // also fix eigenvalues to be consistent
108  DLOOPA(j) tmpgeneralvec[j] = eigenvalues[j];
109  DLOOPA(j) eigenvalues[j]=0;
110  DLOOPA(j) for(l=0;l<NDIM;l++) eigenvalues[j] += mink(j,l)*tmpgeneralvec[l] ;
111 
112 
113  // construct tetr_cov
114  // Tcov^a_b = Tcon_j^l g_{lb} \eta^{aj}
115  // So first index is orthonormal and second index is old coordinate basis.
116  // So Tcon and Tcov are inverses but not transposes of each other as would occur if matrix_inverse() operated.
117  DLOOP(j,k) tmpgeneralmatrix[j][k] = 0. ;
118  DLOOP(j,k) for(l=0;l<NDIM;l++) tmpgeneralmatrix[j][k] += tetr_con[j][l]*gcov[GIND(l,k)] ;
119  DLOOP(j,k) tetr_cov[j][k] = 0. ;
120  DLOOP(j,k) for(l=0;l<NDIM;l++) tetr_cov[j][k] += mink(j,l)*tmpgeneralmatrix[l][k] ;
121 
122 #if 0
123  /* tetr_ cov & con are inverse transposes of each other */
124  DLOOP(j,k) tmpgeneralmatrix[j+1][k+1] = tetr_cov[j][k] ;
125  gaussj(tmpgeneralmatrix,NDIM,NULL,0) ;
126  DLOOP(j,k) tetr_con[j][k] = tmpgeneralmatrix[k+1][j+1] ;
127 #endif
128 
129 
130 
131 
132  return(info);
133 }
134 
135 
136 
137 
138 
139 
140 
147 #define DEBUGLAPACK 1
148 
149 static int compute_tetrcon_frommetric(FTYPE (*generalmatrix)[NDIM], FTYPE (*tetrcon)[NDIM], FTYPE eigenvalues[])
150 {
151  FTYPE tetrconother[NDIM][NDIM];
152  int jj,kk;
153  int ll,pp;
154  int info;
155  FTYPE eigenvaluesother[NDIM],tempeigenvalues[NDIM];
156  FTYPE errorold,errornew,temptetrcon[NDIM][NDIM];
157  FTYPE errorlist[NDIM][NDIM];
158  FTYPE error1,error2;
159  int newlist[NDIM];
160  FTYPE signlistmat[NDIM][NDIM];
161  FTYPE signlist[NDIM];
162 
163 
164 
165 
166 
167 #if(DEBUGLAPACK && (USINGLAPACK))
168 
169  // in case feed in BL coord metric inside horizon, just fix so no minimum error reached
170  if(generalmatrix[1][1]<=0.0) generalmatrix[1][1]=NUMEPSILON+fabs(generalmatrix[1][1]);
171 
172  // get general tetrad and eigenvalues
173  info=tetlapack_func_prec(generalmatrix,tetrcon,eigenvalues);
174 
175  // get tetrad and eigenvalues for not-so-general metric
176  // (ignore this other info)
177  compute_tetrcon_frommetric_mathematica(generalmatrix, tetrconother, eigenvaluesother);
178 
179  // try to reorder spatial parts, assuming time part is always negative eigenvalue that will come as first eigenvector always
180  // tetrconother[jj][jj] is correct t,r,\theta,\phi order for diagonal part
181  // tetrcon[jj][kk] is not correct order in general, with jj (rows) being out of order
182 
183 
184  // error for every row compared to every row
185  DLOOP(jj,kk){// double over rows
186  errorlist[jj][kk]=0.0;
187  error1=0.0;
188  error2=0.0;
189  DLOOPA(ll){ // over columns
190  error1+=fabs(tetrcon[jj][ll]-tetrconother[kk][ll]);
191  }
192  // compensate for potential sign flip for eigenvector
193  DLOOPA(ll){ // over columns
194  error2+=fabs(tetrcon[jj][ll]+tetrconother[kk][ll]);
195  }
196  if(error1>error2){
197  errorlist[jj][kk]=error2;
198  // use sign to indicate need to flip sign
199  signlistmat[jj][kk]=-1.0;
200  }
201  else{
202  errorlist[jj][kk]=error1; // same sign
203  signlistmat[jj][kk]=1.0;
204  }
205  }
206  // now have error matrix.
207 
208 
209  // start with minimum error pair and increase in error until obtain all unique matches
210  DLOOPA(kk) newlist[kk]=-1;
211  int notfoundall=1;
212  FTYPE signerror=0;
213  while(notfoundall){
214  int minkk=-1;
215  int minjj=-1;
216  FTYPE minerror=BIG;
217  DLOOP(jj,kk){
218  int uniquecheck=0; DLOOPA(pp) if(pp!=kk) uniquecheck += (newlist[pp]==jj);
219  if(fabs(errorlist[jj][kk])<minerror && newlist[kk]==-1 && uniquecheck==0){ // only use minimum if minimum AND not already on list (forces result to be unique)
220  minerror=fabs(errorlist[jj][kk]);
221  minjj=jj;
222  minkk=kk;
223  // if(globalii==0 && globaljj==N2/2) dualfprintf(fail_file,"minkk=%d",minkk);
224  signerror=sign(signlistmat[jj][kk]);
225  }
226  }
227  if(minjj==-1 || minkk==-1){
228  dualfprintf(fail_file,"Problem in finding minimum error between eigenvectors\n");
229  myexit(34643634);
230  }
231  else{
232  newlist[minkk]=minjj; // point {t,x,y,z}=minkk to lapack (minjj)
233  signlist[minkk]=signerror; // set sign to flip for this given {t,x,y,z}=minkk
234  int uniquecheck=0; DLOOPA(kk) if(kk!=minkk) uniquecheck += (newlist[kk]==minjj);
235  if(uniquecheck==1){
236  dualfprintf(fail_file,"Tried to double set: %d %d %d\n",minkk,minjj);
237  DLOOPA(jj) dualfprintf(fail_file,"jj=%d newlist=%d\n",jj,newlist[jj]);
238  }
239  }
240  notfoundall=0; // end?
241  DLOOPA(kk) if(newlist[kk]==-1) notfoundall=1; // nope, not end
242  }
243 
244  // store original result
245  DLOOP(jj,kk) temptetrcon[jj][kk]=tetrcon[jj][kk];
246  DLOOPA(jj) tempeigenvalues[jj]=eigenvalues[jj];
247 
249  //
250  // reorder
251  //
253  DLOOPA(jj){// over rows
254  eigenvalues[jj]=tempeigenvalues[newlist[jj]];
255  }
256  DLOOPA(jj){// over rows
257  DLOOPA(kk){
258  tetrcon[jj][kk]=temptetrcon[newlist[jj]][kk]*signlist[jj]; // signlist[jj] since jj is t,x,y,z in order
259  }
260  }
261 
262 #if(DEBUGLAPACK==2)
263  // real debug
264  if(globalii==0 && globaljj==N2/2){
265  // if(tiglobal[1]==200 && tiglobal[2]==10 && tiglobal[3]==0){
266  dualfprintf(fail_file,"\ninfo=%d\n",info);
267  DLOOPA(jj) dualfprintf(fail_file,"jj=%d newlist=%d\n",jj,newlist[jj]);
268  DLOOPA(jj){
269  dualfprintf(fail_file,"jj=%d eigenorig=%21.15g eigen=%21.15g old=%21.15g\n",jj,tempeigenvalues[jj],eigenvalues[jj],eigenvaluesother[jj]);
270  }
271  DLOOP(jj,kk){
272  dualfprintf(fail_file,"jj=%d kk=%d lapack=%21.15g old=%21.15g\n",jj,kk,tetrcon[jj][kk],tetrconother[jj][kk]);
273  }
274  dualfprintf(fail_file,"\n");
275 
276  fflush(fail_file);
277  myexit(0);
278  }
279 #endif
280 
281 
282 #else // else if not debugging
283 
284 
285 
286 
287 
288 #if(USINGLAPACK)
289  // input general metric
290  // don't need to convert using idxdxp since result is tetrad used to convert from whatever input metric one started with
291  info=tetlapack_func_prec(generalmatrix,tetrcon,eigenvalues);
292 #else
293 
294  // generate orthonormal basis and dxdxp transformation (user-based function that doesn't take general metric)
295  info=compute_tetrcon_frommetric_mathematica(generalmatrix, tetrcon, eigenvalues);
296 #endif
297 
298 
299 
300 
301 #endif // end over debug/not debug
302 
303 
304  return(info);
305 
306 }
307 
315 static int compute_tetrcon_frommetric_mathematica(FTYPE (*generalmatrix)[NDIM], FTYPE (*tetrcon)[NDIM], FTYPE eigenvalues[])
316 {
317  FTYPE gtt,grr,grt,ghh,gpp;
318  FTYPE blob1,blob1sq;
319 
320  // now assume no mixing in r-\theta
321  // Right now, only works for a=0 KS or BL
322  // But, even for a\neq 0, the order is found correctly since spherical polar and KS gtr terms dominate
323 
324  if(THETAROT!=0.0){
325  // dualfprintf(fail_file,"compute_tetrcon_frommetric_mathematica() needs to have rotation added (see jon_interp stuff) so can handle tilts that mix theta and phi. Then can trust picking up dominate terms: THETAROT=%g\n",THETAROT);
326  //myexit(546292153); // GODMARK
327  }
328 
329  gtt=generalmatrix[0][0];
330  grr=generalmatrix[1][1];
331  grt=generalmatrix[1][0];
332  ghh=generalmatrix[2][2];
333  gpp=generalmatrix[3][3];
334 
335  blob1=grr - sqrt(4.0*((grt)*(grt)) + ((grr - gtt)*(grr - gtt))) + gtt;
336  blob1sq=blob1*blob1;
337 
338  //regexp: pow(\([a-zA-Z0-9-+*/ ]+\),2) -> ((\1)*(\1))
339 
340  // get orthonormal basis transformation
341  tetrcon[0][0]=-(sqrt(grr + sqrt(4.0*((grt)*(grt)) + ((grr - gtt)*(grr - gtt))) - gtt)/
342  pow((4.0*((grt)*(grt)) + ((grr - gtt)*(grr - gtt)))*blob1sq,0.25));
343 
344  tetrcon[0][1] = (2.0*grt)/(sqrt(4.0*((grt)*(grt)) + (grr - gtt)*(grr + sqrt(4.0*((grt)*(grt)) + ((grr - gtt)*(grr - gtt))) - gtt))*
345  sqrt(fabs(grr - sqrt(4.0*((grt)*(grt)) + ((grr - gtt)*(grr - gtt))) + gtt)));
346 
347  tetrcon[0][2] = 0.0;
348  tetrcon[0][3] = 0.0;
349 
350  tetrcon[1][0] = (2.0*grt)/sqrt((4.0*((grt)*(grt)) + (grr - gtt)*(grr + sqrt(4.0*((grt)*(grt)) + ((grr - gtt)*(grr - gtt))) - gtt))*
351  (grr + sqrt(4.0*((grt)*(grt)) + ((grr - gtt)*(grr - gtt))) + gtt));
352 
353  tetrcon[1][1] = sqrt((grr + sqrt(4.0*((grt)*(grt)) + ((grr - gtt)*(grr - gtt))) - gtt)/
354  (sqrt(4.0*((grt)*(grt)) + ((grr - gtt)*(grr - gtt)))*(grr + sqrt(4.0*((grt)*(grt)) + ((grr - gtt)*(grr - gtt))) + gtt)));
355 
356  tetrcon[1][2] = 0.0;
357  tetrcon[1][3] = 0.0;
358 
359  tetrcon[2][0] = 0.0;
360  tetrcon[2][1] = 0.0;
361  tetrcon[2][2] = 1.0/fabs(sqrt(ghh));
362  tetrcon[2][3] = 0.0;
363 
364  tetrcon[3][0] = 0.0;
365  tetrcon[3][1] = 0.0;
366  tetrcon[3][2] = 0.0;
367  tetrcon[3][3] = 1.0/fabs(sqrt(gpp));
368 
369  eigenvalues[0]=0.5*(grr - 1.*sqrt(4.*pow(grt,2) + pow(grr - 1.*gtt,2)) + gtt);
370  eigenvalues[1]=0.5*(grr + sqrt(4.*pow(grt,2) + pow(grr - 1.*gtt,2)) + gtt);
371  eigenvalues[2]=ghh;
372  eigenvalues[3]=gpp;
373 
374  return(0);
375 }
376 
377 
378 
390 int calc_ORTHOes(int primcoord, struct of_geom *ptrgeom, FTYPE tmuup[][NDIM], FTYPE tmudn[][NDIM])
391 {
392  FTYPE dxdxp[NDIM][NDIM];
393  FTYPE idxdxp[NDIM][NDIM];
394  FTYPE tetrcovV[NDIM][NDIM];
395  FTYPE tetrconV[NDIM][NDIM];
396  FTYPE eigenvaluesV[NDIM];
397  FTYPE tetrcovX[NDIM][NDIM];
398  FTYPE tetrconX[NDIM][NDIM];
399  int jj,kk,ll;
400 
401  globalii=ptrgeom->i;
402  globaljj=ptrgeom->j;
403  globalkk=ptrgeom->k;
404 
405  if(primcoord){
406  // get dxdxp
407  dxdxprim_ijk(ptrgeom->i,ptrgeom->j,ptrgeom->k,ptrgeom->p,dxdxp);
408  idxdxprim(dxdxp, idxdxp);
409  }
410  else{
411  // then won't use dxdxp, so can just leave unset, but set it to diag(1,1,1,1) for santiy in case used.
412  DLOOP(jj,kk) dxdxp[jj][kk]=idxdxp[jj][kk]=0.0;
413  DLOOPA(jj) dxdxp[jj][jj]=idxdxp[jj][jj]=1.0;
414  }
415 
416  // get tetrad (uses dxdxp so that tetrcon and tetrcon and eigenvalues are using V metric not X metric
417  tetr_func_frommetric(primcoord, dxdxp, ptrgeom->gcov, tetrcovV, tetrconV, eigenvaluesV); // doesn't account for ordering issue.
418  // tetr_func(METRICTETRAD,ptrgeom->gcov, tetrcovV, tetrconV, eigenvaluesV);
419 
420 
421  if(primcoord){
422  // now convert back to X metric for general internal code use
423 
424  // TBup_\mu[ff ortho]^\nu[lab coordbasis] = ilambda^aa[lab ortho]_\mu[ff ortho] Tetrcon_aa[lab ortho]^\nu[lab coordbasis]
425  // TBlo^\mu[ff ortho]_\nu[lab coordbasis] = lambda^\mu[ff ortho]_aa[lab ortho] Tetrcov^aa[lab ortho]_\nu[lab coordbasis]
426 
427 
428  // \LambdaXcov^jj[ortho]_kk[labX] = \LambdaVcov^jj[ortho]_ll[labV] dxdxp^ll[labV]_kk[labX]
429  DLOOP(jj,kk){
430  tetrcovX[jj][kk]=0.0;
431  DLOOPA(ll) {
432  tetrcovX[jj][kk] += tetrcovV[jj][ll]*dxdxp[ll][kk];
433  }
434  }
435 
436  // \LambdaXcon_jj[ortho]^kk[labX] = \LambdaVcon_jj[ortho]^ll[labV] idxdxp^kk[labX]_ll[labV]
437  DLOOP(jj,kk){
438  tetrconX[jj][kk]=0.0;
439  DLOOPA(ll) {
440  tetrconX[jj][kk] += tetrconV[jj][ll]*idxdxp[kk][ll];
441  }
442  }
443 
444  // map to tmuup and tmudn
445  DLOOP(jj,kk) tmuup[jj][kk]=tetrcovX[jj][kk]; // \Lambda^jj[ortho]_kk[labX] = tmuup = "LAB2ORTHO" = tetrcovX
446  DLOOP(jj,kk) tmudn[jj][kk]=tetrconX[jj][kk]; // \Lambda_jj[ortho]^kk[labX] = tmudn = "ORTHO2LAB" = tetrconX
447 
448  }
449  else{
450  // map to tmuup and tmudn
451  DLOOP(jj,kk) tmuup[jj][kk]=tetrcovV[jj][kk]; // \Lambda^jj[ortho]_kk[labV] = tmuup = "LAB2ORTHO" = tetrcovV
452  DLOOP(jj,kk) tmudn[jj][kk]=tetrconV[jj][kk]; // \Lambda_jj[ortho]^kk[labV] = tmudn = "ORTHO2LAB" = tetrconV
453  }
454 
455 
456  return(0);
457 }
458 
459 
462 int get_tetrcovcon(int primcoord, struct of_geom *ptrgeom, FTYPE (**tetrcov)[NDIM],FTYPE (**tetrcon)[NDIM])
463 {
464 
466  // for tetrads
468  int ii,jj,kk,pp;
469  ii=ptrgeom->i;
470  jj=ptrgeom->j;
471  kk=ptrgeom->k;
472  pp=ptrgeom->p;
473 
474  // get tetrads
475  // tmuup ~ tlab2ortho[LAB2ORTHO] ~ tetrcon [which operates on covariant things when in form: ufl_\nu = Tetrcon_\nu^\mu ucovlab_\mu]
476  // tmudn ~ tlab2ortho[ORTHO2LAB] ~ tetrcov [which operates on contravariant things when in form: ufl^\nu = Tetrcov^\nu_\mu uconlab^\mu
477  // i.e. first and second index each always refer to the same basis without transposition. So always contract with second index to get thing into form of first index.
478 
479  // note that ORTHO2LAB is stored as tetrcon=tmudn
480  // note that LAB2ORTHO is stored as tetrcov=tmuup
481  if(STORETLAB2ORTHO==1){ // global parameter
482  // then just get stored version instead of computing on fly
483  *tetrcov=GLOBALMETMACP2A0(tlab2ortho,pp,LAB2ORTHO,ii,jj,kk);
484  *tetrcon=GLOBALMETMACP2A0(tlab2ortho,pp,ORTHO2LAB,ii,jj,kk);
485  }
486  else{// compute on fly here
487 
488  // compute (expensive in general!)
489  // NOTE ORDER!
490  calc_ORTHOes(primcoord, ptrgeom, *tetrcov, *tetrcon);
491  }
492 
493  return(0);
494 
495 }
496 
497 
498 
499 
508 int calc_ZAMOes_old(struct of_geom *ptrgeom, FTYPE emuup[][NDIM], FTYPE emudn[][NDIM])
509 {
510  FTYPE e2nu,e2psi,e2mu1,e2mu2,omega;
511  FTYPE gtt,gtph,gphph,grr,gthth;
512  int i,j;
513  // recast as [NDIM][NDIM] matrix
514  // FTYPE emuup[][NDIM]=(FTYPE (*)[NDIM])(&ptremuup[0]);
515  //FTYPE emudn[][NDIM]=(FTYPE (*)[NDIM])(&ptremudn[0]);
516 
517 
518  gtt=ptrgeom->gcov[GIND(0,0)];
519  gtph=ptrgeom->gcov[GIND(0,3)];
520  gphph=ptrgeom->gcov[GIND(3,3)];
521  grr=ptrgeom->gcov[GIND(1,1)];
522  gthth=ptrgeom->gcov[GIND(2,2)];
523 
524  //Bardeen's 72 coefficients:
525  e2nu=-gtt+gtph*gtph/gphph;
526  e2psi=gphph;
527  e2mu1=grr;
528  e2mu2=gthth;
529  omega=-gtph/gphph;
530 
531  for(i=0;i<4;i++)
532  for(j=0;j<4;j++)
533  {
534  emuup[i][j]=0.;
535  emudn[i][j]=0.;
536  }
537 
538  emuup[0][0]=sqrt(e2nu);
539  emuup[1][1]=sqrt(e2mu1);
540  emuup[2][2]=sqrt(e2mu2);
541  emuup[0][3]=-omega*sqrt(e2psi);
542  emuup[3][3]=sqrt(e2psi);
543 
544  emudn[3][0]=omega*1./sqrt(e2nu);
545  emudn[0][0]=1./sqrt(e2nu);
546  emudn[1][1]=1./sqrt(e2mu1);
547  emudn[2][2]=1./sqrt(e2mu2);
548  emudn[3][3]=1./sqrt(e2psi);
549 
550  // need to return Kerr-Schild prime transformations
551 
552  return 0;
553 }
554 
555 
565 int calc_generalized_boost_uu(struct of_geom *ptrgeom, FTYPE *wcon, FTYPE *ucon, FTYPE (*lambda)[NDIM])
566 {
567  int mu,nu;
568  FTYPE wcov[NDIM],ucov[NDIM];
569 
570  // wcov
571  DLOOPA(mu) wcov[mu] = 0.0;
572  DLOOP(mu,nu) wcov[nu] += wcon[mu]*(ptrgeom->gcov[GIND(mu,nu)]);
573 
574  // ucov
575  DLOOPA(mu) ucov[mu] = 0.0;
576  DLOOP(mu,nu) ucov[nu] += ucon[mu]*(ptrgeom->gcov[GIND(mu,nu)]);
577 
578  // gamma
579  FTYPE gamma=0.0;
580  DLOOPA(mu) gamma += -wcon[mu]*ucov[mu];
581 
582  // lambda^\mu_\nu
583  DLOOP(mu,nu) lambda[mu][nu]=
584  + delta(mu,nu)
585  + (1.0/(1.0+gamma)) * (wcon[mu]*wcov[nu] + ucon[mu]*ucov[nu] - gamma *(ucon[mu]*wcov[nu] + wcon[mu]*ucov[nu]))
586  + (ucon[mu]*wcov[nu] - wcon[mu]*ucov[nu]);
587 
588  return(0);
589 }
590 
591 
594 int calc_ortho_boost_uu(FTYPE *wcon, FTYPE *ucon, FTYPE (*lambda)[NDIM])
595 {
596  int mu,nu;
597  FTYPE wcov[NDIM],ucov[NDIM];
598 
599  // wcov
600  DLOOPA(mu) wcov[mu] = wcon[mu];
601  wcov[TT]*=-1.0;
602 
603  // ucov
604  DLOOPA(mu) ucov[mu] = ucon[mu];
605  ucov[TT]*=-1.0;
606 
607  // gamma
608  FTYPE gamma=0.0;
609  DLOOPA(mu) gamma += -wcon[mu]*ucov[mu];
610 
611  // dualfprintf(fail_file,"gamma=%g\n",gamma);
612 
613  // lambda
614  DLOOP(mu,nu) lambda[mu][nu]=
615  + delta(mu,nu)
616  + (1.0/(1.0+gamma)) * (wcon[mu]*wcov[nu] + ucon[mu]*ucov[nu] - gamma *(ucon[mu]*wcov[nu] + wcon[mu]*ucov[nu]))
617  + (ucon[mu]*wcov[nu] - wcon[mu]*ucov[nu]);
618 
619  return(0);
620 }
621 
622 
623 
626 int transboost_lab2fluid(int lab2orthofluid, int primcoord, struct of_geom *ptrgeom, FTYPE *uconlab, FTYPE (*transboostup)[NDIM], FTYPE (*transboostlo)[NDIM])
627 {
628  int mu,nu;
629 
630 
632  // get tetrcov and tetrcon
634  FTYPE tetrconmem[NDIM][NDIM],tetrcovmem[NDIM][NDIM];
635  FTYPE (*tetrcon)[NDIM]=tetrconmem;
636  FTYPE (*tetrcov)[NDIM]=tetrcovmem;
637  get_tetrcovcon(primcoord, ptrgeom, &tetrcov,&tetrcon); // pass address of pointer since want to give new pointer address if stored
638 
639 
640  // DLOOP(mu,nu) dualfprintf(fail_file,"mu=%d nu=%d tetrcov=%g tetrcon=%g\n",mu,nu,tetrcov[mu][nu],tetrcon[mu][nu]);
641 
642 
643  // get ucovlab
644  FTYPE ucovlab[NDIM];
645  lower_vec(uconlab,ptrgeom,ucovlab);
646 
647  // set wconlab to LAB frame, which happens to be ZAMO for the equations HARM solves
648  FTYPE wcovlab[NDIM];
649  FTYPE wconlab[NDIM];
650  DLOOPA(mu) wconlab[mu] = 0.0;
651 
652  if(lab2orthofluid==LAB2FF || lab2orthofluid==FF2LAB){
653 #if(0) // STAY AS ZERO
654  // ZAMO frame: \eta_\mu = (-\alpha,0,0,0)
655  wcovlab[TT]=-ptrgeom->alphalapse;
656  SLOOPA(mu) wcovlab[mu]=0.0;
657  // raise to get wconlab = \eta^\mu
658  DLOOPA(mu) wconlab[mu] = 0.0;
659  DLOOP(mu,nu) wconlab[nu] += wcovlab[mu]*(ptrgeom->gcon[GIND(mu,nu)]);
660 #else
661  // actually construct implied frame of coordinates directly
662  FTYPE wconff[NDIM]={1,0,0,0};
663  // i.e. ucon^\nu[lab coordbasis] = ucon^\mu[ff ortho] TBup_\mu[ff ortho]^\nu[lab coordbasis]
664  DLOOP(mu,nu) wconlab[nu] += wconff[mu]*tetrcon[mu][nu];
665  // get w_\nu
666  DLOOPA(mu) wcovlab[mu] = 0.0;
667  DLOOP(mu,nu) wcovlab[nu] += wconlab[mu]*(ptrgeom->gcov[GIND(mu,nu)]);
668 
669 #endif
670  }
671  else{
672  // HARM fake frame: \eta_\mu = (1,0,0,0)
673  wcovlab[TT]=1.0;
674  SLOOPA(mu) wcovlab[mu]=0.0;
675  // raise to get wconlab = \eta^\mu
676  DLOOPA(mu) wconlab[mu] = 0.0;
677  DLOOP(mu,nu) wconlab[nu] += wcovlab[mu]*(ptrgeom->gcon[GIND(mu,nu)]);
678  }
679 
680 
681  // DLOOPA(mu) dualfprintf(fail_file,"mu=%d ucovlab=%g wcovlab=%g wconlab=%g\n",mu,ucovlab[mu],wcovlab[mu],wconlab[mu]);
682 
683 
684  // get orthonormal boost to fluid frame
685  // Convert ucon^i[lab] to orthonormal basis, so then just use simple Lorentz boost from special relativity to operate on the tetrad to have something that converts lastly to the fluid frame.
686  FTYPE wconlabortho[NDIM],uconlabortho[NDIM];
687  DLOOPA(mu) wconlabortho[mu]=uconlabortho[mu]=0.0;
688  // Tetrcov^mu[lab ortho]_\nu[lab coordbasis] uconlab^\nu[lab coordbasis]
689  DLOOP(mu,nu) wconlabortho[mu] += tetrcov[mu][nu]*wconlab[nu];
690  DLOOP(mu,nu) uconlabortho[mu] += tetrcov[mu][nu]*uconlab[nu];
691 
692  // DLOOPA(mu) dualfprintf(fail_file,"mu=%d uconlabortho=%g wconlabortho=%g\n",mu,uconlabortho[mu],wconlabortho[mu]);
693 
694 
695  FTYPE lambda[NDIM][NDIM];
696  calc_ortho_boost_uu(wconlabortho, uconlabortho, lambda);
697  // get inverse lambda
698  FTYPE ilambda[NDIM][NDIM];
699  // comments for matrix_inverse() say takes lambda^j_k and pops out (ilambda)^k_j such that (lambda)^j_k (ilambda)^k_l = \delta^j_l
700  // So need to apply ilambda correctly assuming does transpose
701  matrix_inverse(PRIMECOORDS,lambda,ilambda);
702 
703 
704  // DLOOP(mu,nu) dualfprintf(fail_file,"mu=%d nu=%d lambda=%g ilambda=%g\n",mu,nu,lambda[mu][nu],ilambda[mu][nu]);
705 
706 
707  // From earlier in other functions:
708  //
709  // Tetrcon_k^j [first index ortho, second index lab]
710  // Tetrcov^k_j [first index ortho, second index lab (i.e. not transposed!)]
711  //
712  // Lambda^\mu[w]_\nu[u] u^\nu = w^\mu [Corresponding to boost *into* fluid frame]
713  // Lambda^\mu[w]_\nu[u] w_\mu = u_\nu [Corresponding to boost *from* fluid frame]
714  // (iLambda)^\mu[u]_\nu[w] u_\mu = w_\nu [Corresponding to boost *into* fluid frame]
715  // (iLambda)^\mu[u]_\nu[w] w^\nu = u^\mu [Corresponding to boost *from* fluid frame]
716  // So if going from w->u (i.e. FF2LAB) frame for vecff^\mu , then apply (iLambda)^\mu_\nu vecff^nu = veclab^\mu
717  // So if going from u->w (i.e. LAB2FF) frame for veclab^\mu , then apply Lambda ^\mu_\nu veclab^nu = vecff^\mu
718 
719 
720 
721  // form transboost
722  int aa;
723  // apply Lorentz boost on transformation from lab-frame to orthonormal basis
724 
725  // TBup_\mu[ff ortho]^\nu[lab coordbasis] = ilambda^aa[lab ortho]_\mu[ff ortho] Tetrcon_aa[lab ortho]^\nu[lab coordbasis]
726  DLOOP(mu,nu) transboostup[mu][nu]=0.0;
727  DLOOP(mu,nu) DLOOPA(aa) transboostup[mu][nu] += ilambda[aa][mu]*tetrcon[aa][nu]; // as if operated boost on u_aa
728 
729  // TBlo^\mu[ff ortho]_\nu[lab coordbasis] = lambda^\mu[ff ortho]_aa[lab ortho] Tetrcov^aa[lab ortho]_\nu[lab coordbasis]
730  DLOOP(mu,nu) transboostlo[mu][nu]=0.0;
731  DLOOP(mu,nu) DLOOPA(aa) transboostlo[mu][nu] += lambda[mu][aa]*tetrcov[aa][nu]; // as if operated boost on u^aa
732 
733  // for starting in lab frame coordinate basis, use as follows:
734  // i.e. ucon^\mu[ff ortho] = TBlo^\mu[ff ortho]_\nu[lab coordbasis] ucon^\nu[lab coordbasis]
735  // i.e. ucov_\mu[ff ortho] = TBup_\mu[ff ortho]^\nu[lab coordbasis] ucov_\nu[lab coordbasis]
736 
737  // if starting with fluid frame orthonormal basis, then use same things but indices are contracted reversely.
738  // i.e. ucon^\nu[lab coordbasis] = ucon^\mu[ff ortho] TBup_\mu[ff ortho]^\nu[lab coordbasis]
739  // i.e. ucov_\nu[lab coordbasis] = ucov_\mu[ff ortho] TBlo^\mu[ff ortho]_\nu[lab coordbasis]
740 
741  // that is, as constructed, the TBlo and TBhi have indices always in the same consistent order as far as the meaning of the first and second index with respect to the frame and coordinates. Unlike those things that use matrix_inverse like idxdxp and ilambda
742 
743 
744  return(0);
745 }
746 
747 
748 
749 
764 int vector_harm2orthofluidorback(int whichvector, int harm2orthofluid, struct of_geom *ptrgeom, int uconcovtype, FTYPE *uconcov, FTYPE v4concovtype, FTYPE *vector4in, FTYPE *vector4out)
765 {
766  int vector_lab2orthofluidorback(int primcoord, int lab2orthofluid, struct of_geom *ptrgeom, int uconcovtype, FTYPE *uconcov, FTYPE v4concovtype, FTYPE *vector4in, FTYPE *vector4out);
767  int jj;
768  FTYPE vector4incopy[NPR];
769 
770 
771  // KORALTODO SUPERGODMARK: Need to know what coordinates ptrgeom is. Currently assume always PRIMECOORDS for either LAB2FF or FF2LAB.
772 
773 
774 
775  // preserve vector4in
776  DLOOPA(jj) vector4incopy[jj]=vector4in[jj];
777 
778  // harmlab to ortho fluid
779  if(harm2orthofluid==LAB2FF){
780  // correct "t" component
781  if(whichvector==TYPEUCOV){ // u_\mu type
782  DLOOPA(jj) vector4incopy[jj] *= 1.0; // (ptrgeom->alphalapse); // gets E_\nu from T^t_\nu or T^{t\nu} from E^\nu
783  }
784  else if(whichvector==TYPEUCON){ // u^\nu type
785  DLOOPA(jj) vector4incopy[jj] *= 1.0; //(ptrgeom->alphalapse); // gets B^\nu from B^i or B_i from B_\nu
786  }
787 
788  // transform+boost
789  int primcoord=1; // assume input is harm's PRIMECOORDS so can use dxdxp to optimize tetrad computation
790  vector_lab2orthofluidorback(primcoord, harm2orthofluid, ptrgeom, uconcovtype, uconcov, v4concovtype, vector4incopy, vector4out);
791  // vector4out is now orthonormalized and boosted into fluid frame
792  }
793 
794 
795  // ortho fluid to harmlab
796  if(harm2orthofluid==FF2LAB){
797 
798  // transform+boost
799  int primcoord=1; // assume inputting fluid frame, but want back harm PRIMECOORDS
800  vector_lab2orthofluidorback(primcoord, harm2orthofluid, ptrgeom, uconcovtype, uconcov, v4concovtype, vector4incopy, vector4out);
801  // vector4out is now orthonormalized and boosted into fluid frame
802 
803 
804  // correct "t" component
805  if(whichvector==TYPEUCOV){ // u_\mu type
806  DLOOPA(jj) vector4out[jj] /= 1.0; //(ptrgeom->alphalapse); // gets T^t_\nu from E_\nu or T^{t\nu} from E^\nu
807  }
808  else if(whichvector==TYPEUCON){ // u^\nu type
809  DLOOPA(jj) vector4out[jj] /= 1.0; //(ptrgeom->alphalapse); // gets B^i from B^\nu or B_i from B_\nu
810  }
811 
812  }
813 
814 
815  return(0);
816 
817 }
818 
819 
820 
821 
840 int vector_lab2orthofluidorback(int primcoord, int lab2orthofluid, struct of_geom *ptrgeom, int uconcovtype, FTYPE *uconcov, FTYPE v4concovtype, FTYPE *vector4in, FTYPE *vector4out)
841 {
842  int mu,nu;
843  FTYPE transboostup[NDIM][NDIM],transboostlo[NDIM][NDIM];
844  FTYPE ucon[NDIM]; // needed for transboost
845 
846  if(uconcovtype==TYPEUCON){ // then uconcov is contravariant u^\mu of fluid frame
847  // ucon
848  DLOOPA(mu) ucon[mu] = uconcov[mu];
849  }
850  else if(uconcovtype==TYPEUCOV){ // then uconcov is covariant u_\mu of fluid frame
851  // ucon
852  DLOOPA(mu) ucon[mu] = 0.0; DLOOP(mu,nu) ucon[nu] += uconcov[mu]*(ptrgeom->gcon[GIND(mu,nu)]);
853  }
854  else{
855  dualfprintf(fail_file,"No such uconcovtype=%d\n",uconcovtype);
856  myexit(934627520);
857  }
858 
859 
860  // get trans boosts (uses ucon always, hence above getting of ucon)
861  transboost_lab2fluid(lab2orthofluid, primcoord, ptrgeom, ucon, transboostup, transboostlo);
862 
863 
864  // apply trans boost to 4-vector
865  DLOOPA(mu) vector4out[mu]=0.0;
866  if(v4concovtype==TYPEUCON){ // then vector4in^\mu is contravariant
867  if(lab2orthofluid==LAB2FF){
868  // vector4ff^\nu = TBlo^\nu_\mu vector4labcoordbasis^\mu
869  DLOOP(mu,nu) vector4out[nu] += transboostlo[nu][mu]*vector4in[mu]; // application on vector4in^\mu
870  }
871  else{ // i.e. orthoff 2 lab
872  // vector4labcoordbasis^\mu = vector4ff^\nu TBup_\nu^\mu
873  DLOOP(mu,nu) vector4out[mu] += vector4in[nu]*transboostup[nu][mu]; // application on vector4in^\nu
874  }
875  }
876  else if(v4concovtype==TYPEUCOV){ // then vector4in_\mu is covariant
877  if(lab2orthofluid==LAB2FF){
878  //vector4ff_\nu = TBup_\nu^\mu vector4labcoordbasis_\mu
879  DLOOP(mu,nu) vector4out[nu] += transboostup[nu][mu]*vector4in[mu]; // application on vector4in_\mu
880  }
881  else{ // i.e. orthoff 2 lab
882  // vector4labcoordbasis_\mu = vector4ff_\nu TBlo^\nu_\mu
883  DLOOP(mu,nu) vector4out[mu] += vector4in[nu]*transboostlo[nu][mu]; // application on vector4in_\nu
884  }
885  }
886  else{
887  dualfprintf(fail_file,"No such v4concovtype=%d\n",v4concovtype);
888  myexit(934627520);
889  }
890 
891  return(0);
892 
893 }
894 
895 
896 
907 int tensor_lab2orthofluidorback(int primcoord, int lab2orthofluid, struct of_geom *ptrgeom, int uconcovtype, FTYPE *uconcov, int tconcovtypeA, int tconcovtypeB, FTYPE (*tensor4in)[NDIM], FTYPE (*tensor4out)[NDIM])
908 {
909  int mu,nu,aa,bb;
910  FTYPE ucon[NDIM];
911  FTYPE transboostup[NDIM][NDIM],transboostlo[NDIM][NDIM];
912 
913 
914  if(uconcovtype==TYPEUCON){ // then uconcov is contravariant u^\mu of fluid frame
915  // ucon
916  DLOOPA(mu) ucon[mu] = uconcov[mu];
917  }
918  else if(uconcovtype==TYPEUCOV){ // then uconcov is covariant u_\mu of fluid frame
919  // ucon
920  raise_vec(uconcov,ptrgeom,ucon);
921  }
922  else{
923  dualfprintf(fail_file,"No such uconcovtype=%d\n",uconcovtype);
924  myexit(934627525);
925  }
926 
927  // get trans boosts (uses ucon always, hence above getting of ucon)
928  transboost_lab2fluid(lab2orthofluid, primcoord, ptrgeom, ucon, transboostup, transboostlo);
929 
930 
931  // DLOOP(mu,nu) dualfprintf(fail_file,"mu=%d nu=%d transboostup=%g transboostlo=%g\n",mu,nu,transboostup[mu][nu],transboostlo[mu][nu]);
932 
933 
934  // apply trans boost to 4-tensor
935  DLOOP(mu,nu) tensor4out[mu][nu]=0.0;
936  if(tconcovtypeA==TYPEUCON && tconcovtypeB==TYPEUCON){
937  if(lab2orthofluid==LAB2FF || lab2orthofluid==HARM2FF){
938  // tfl^{\nu bb} = TBlo^\nu[ffortho]_\mu[labcoord] TBlo^bb[ffortho]_aa[labcoord] t^{\mu aa}
939  DLOOP(mu,nu) DLOOP(aa,bb) tensor4out[nu][bb] += transboostlo[nu][mu]*transboostlo[bb][aa]*tensor4in[mu][aa]; // application on con con
940  }
941  else{
942  // t^{\mu aa} = tfl^{\nu bb} TBup_\nu^\mu TBup_bb^aa
943  //DLOOP(mu,aa){
944  // DLOOP(nu,bb){
945  DLOOP(mu,nu){
946  DLOOP(aa,bb){
947  tensor4out[mu][aa] += tensor4in[nu][bb]*transboostup[nu][mu]*transboostup[bb][aa]; // application on con con
948  // dualfprintf(fail_file,"mu=%d aa=%d nu=%d bb=%d adding=%g from %g*%g*%g\n",mu,aa,nu,bb,tensor4in[nu][bb]*transboostup[nu][mu]*transboostup[bb][aa],tensor4in[nu][bb],transboostup[nu][mu],transboostup[bb][aa]);
949  }
950  }
951  // dualfprintf(fail_file,"final00=%26.20g final10=%26.20g final01=%26.20g\n",tensor4out[0][0],tensor4out[0][1],tensor4out[1][0]);
952  }
953  }
954  else if(tconcovtypeA==TYPEUCON && tconcovtypeB==TYPEUCOV){
955  if(lab2orthofluid==LAB2FF || lab2orthofluid==HARM2FF){
956  // tfl^\nu_bb = TBlo^\nu_\mu TBup_bb^aa t^\mu_aa
957  DLOOP(mu,nu) DLOOP(aa,bb) tensor4out[nu][bb] += transboostlo[nu][mu]*transboostup[bb][aa]*tensor4in[mu][aa]; // application on con cov
958  }
959  else{
960  // t^\mu_aa = t^\nu_bb TBup_\nu^\mu TBlo^bb_aa
961  DLOOP(mu,nu) DLOOP(aa,bb) tensor4out[mu][aa] += tensor4in[nu][bb]*transboostup[nu][mu]*transboostlo[bb][aa]; // application on con cov
962  }
963  }
964  else if(tconcovtypeA==TYPEUCOV && tconcovtypeB==TYPEUCON){
965  if(lab2orthofluid==LAB2FF || lab2orthofluid==HARM2FF){
966  // tfl_\nu^bb = TBup_\nu^\mu TBlo^bb_aa t_\mu^aa
967  DLOOP(mu,nu) DLOOP(aa,bb) tensor4out[nu][bb] += transboostup[nu][mu]*transboostlo[bb][aa]*tensor4in[mu][aa]; // application on cov con
968  }
969  else{
970  // t_\mu^aa = t_\nu^bb TBlo^\nu_\mu TBup_bb^aa
971  DLOOP(mu,nu) DLOOP(aa,bb) tensor4out[mu][aa] += tensor4in[nu][bb]*transboostlo[nu][mu]*transboostup[bb][aa]; // application on cov con
972  }
973  }
974  else if(tconcovtypeA==TYPEUCOV && tconcovtypeB==TYPEUCOV){
975  if(lab2orthofluid==LAB2FF || lab2orthofluid==HARM2FF){
976  // tfl_{\nu bb} = TBup_\nu^\mu TBup_bb^aa t_{\mu aa}
977  DLOOP(mu,nu) DLOOP(aa,bb) tensor4out[nu][bb] += transboostup[nu][mu]*transboostup[bb][aa]*tensor4in[mu][aa]; // application on cov cov
978  }
979  else{
980  // t_{\mu aa} = t_{\nu bb} TBlo^\nu_\mu TBlo^bb_aa
981  DLOOP(mu,nu) DLOOP(aa,bb) tensor4out[mu][aa] += tensor4in[nu][bb]*transboostlo[nu][mu]*transboostlo[bb][aa]; // application on cov cov
982  }
983  }
984  else{
985  dualfprintf(fail_file,"No such tconcovtypeA=%d tconcovtypeB=%d\n",tconcovtypeA,tconcovtypeB);
986  myexit(934627526);
987  }
988 
989  return(0);
990 
991 }
992 
993 
994 
995 
1003 void vecX2vecVortho(int concovtype, struct of_geom *ptrgeom, FTYPE *veclab, FTYPE *vecortho)
1004 {
1005  int primcoord=1; // input is X and going to V means used dxdxp when making metric, so can use dxdxp to simplify metric before getting tetrad
1006 
1008  // get tetrcov and tetrcon
1010  FTYPE tetrconmem[NDIM][NDIM],tetrcovmem[NDIM][NDIM];
1011  FTYPE (*tetrcon)[NDIM]=tetrconmem;
1012  FTYPE (*tetrcov)[NDIM]=tetrcovmem;
1013  get_tetrcovcon(primcoord, ptrgeom, &tetrcov,&tetrcon); // pass address of pointer since want to give new pointer address if stored
1014 
1015 
1017  // Now setup transformation
1019 
1020  FTYPE tempcomp[NDIM];
1021  FTYPE finalvec[NDIM];
1022 
1023  // vector here is in original X coordinates
1024  int jj;
1025  DLOOPA(jj) finalvec[jj]=veclab[jj];
1026 
1027 
1028  DLOOPA(jj) tempcomp[jj]=0.0;
1029  int kk;
1030  // NOTEMARK: here (unlike in jon_interp_computepreprocess.c) tetrcon and tetrcov convert directly from X coords to V-based orthonormal basis
1031  if(concovtype==TYPEUCON){
1032  // transform to orthonormal basis for contravariant vector in X coordinates
1033  // u^kk[ortho] = tetrcov^kk[ortho]_jj[lab] u^jj[lab]
1034  DLOOP(jj,kk) tempcomp[kk] += tetrcov[kk][jj]*finalvec[jj];
1035  }
1036  else if(concovtype==TYPEUCOV){
1037  // transform to orthonormal basis for covariant vector in X coordinates
1038  // u_kk[ortho] = tetrcon_kk[ortho]^jj[lab] u_jj[lab]
1039  DLOOP(jj,kk) tempcomp[kk] += tetrcon[kk][jj]*finalvec[jj];
1040  }
1041  else{
1042  dualfprintf(fail_file,"No such concovtype=%d\n",concovtype);
1043  myexit(1);
1044  }
1045  DLOOPA(jj) finalvec[jj]=tempcomp[jj];
1046 
1047 
1048  // Could now apply lambda that transforms from (e.g.) SPC to Cart using normal orthonormal type transformation for both coordinates to get that transformation
1049 
1050  // final answer:
1051  DLOOPA(jj) vecortho[jj]=finalvec[jj];
1052 
1053 
1054 }
1055 
1059 FTYPE Root(FTYPE a, FTYPE b, FTYPE c, FTYPE d, FTYPE *roots, int *numroots)
1060 {
1061  FTYPE x0=BIG,x1=BIG,x2=BIG;
1062 #if(USINGGSL)
1063  int failreturn = gsl_poly_solve_cubic(b/a,c/a,d/a,&x0,&x1,&x2);
1064 #else
1065  dualfprintf(fail_file,"Shouldn't be here with no GSL\n");
1066  myexit(562525);
1067 #endif
1068  if(x1==BIG){ // then only 1 root
1069  *numroots=1;
1070  }
1071  else{ // then 3 roots
1072  *numroots=3;
1073  }
1074  roots[0]=x0;
1075  roots[1]=x1;
1076  roots[2]=x2;
1077 
1078  return(roots[0]); // assume first root always chosen
1079 }
1080 
1081 
1084 int cubicroots(FTYPE a, FTYPE b, FTYPE c, FTYPE d, FTYPE *roots)
1085 {
1086  FTYPE Delta = 18.0*a*b*c*d - 4.0*b*b*b*d + b*b*c*c - 4.0*a*c*c*c - 27.0*a*a*d*d;
1087 
1088  //The following cases need to be considered: [17]
1089  // If Δ > 0, then the equation has three distinct real roots.
1090  // If Δ = 0, then the equation has a multiple root and all its roots are real.
1091  // If Δ < 0, then the equation has one real root and two nonreal complex conjugate roots.
1092 
1093  FTYPE u1=1.0;
1094  FTYPE u2=0.0;// complex
1095  FTYPE u3=0.0;// complex
1096 
1097  FTYPE Delta0 = b*b - 3.0*a*c;
1098  FTYPE Delta1 = 2.0*b*b*b - 9.0*a*b*c + 27.0*a*a*d;
1099  FTYPE Delta2sq = -27.0*a*a*Delta + 4.0*Delta0*Delta0*Delta0;
1100  FTYPE Delta2=sqrt(Delta2sq);
1101 
1102  FTYPE C = pow( (Delta1 + sqrt(Delta1*Delta1 - 4.0*Delta0*Delta0*Delta0))*0.5 ,1.0/3.0);
1103 
1104  FTYPE r1 = -1.0/(3.0*a) * (b + u1*C + Delta0/(u1*C));
1105  FTYPE r2 = -1.0/(3.0*a) * (b + u2*C + Delta0/(u2*C));
1106  FTYPE r3 = -1.0/(3.0*a) * (b + u3*C + Delta0/(u3*C));
1107 
1108  return(0);
1109 }
1110 
1112 int genes(FTYPE *gcov[4], FTYPE *evec[4], FTYPE *eval)
1113 {
1114  FTYPE Root(FTYPE a, FTYPE b, FTYPE c, FTYPE d, FTYPE *roots, int *numroots);
1115 
1116  //#include "genes.txt"
1117 
1118  return(0);
1119 }
1120 
1122 int genortho(FTYPE *vec1, FTYPE *vec2, FTYPE *vec3, FTYPE *vec4, FTYPE *ovec1, FTYPE *ovec2, FTYPE *ovec3, FTYPE *ovec4)
1123 {
1124  FTYPE vec1a=vec1[0];
1125  FTYPE vec1b=vec1[1];
1126  FTYPE vec1c=vec1[2];
1127  FTYPE vec1d=vec1[3];
1128 
1129  FTYPE vec2a=vec2[0];
1130  FTYPE vec2b=vec2[1];
1131  FTYPE vec2c=vec2[2];
1132  FTYPE vec2d=vec2[3];
1133 
1134  FTYPE vec3a=vec3[0];
1135  FTYPE vec3b=vec3[1];
1136  FTYPE vec3c=vec3[2];
1137  FTYPE vec3d=vec3[3];
1138 
1139  FTYPE vec4a=vec4[0];
1140  FTYPE vec4b=vec4[1];
1141  FTYPE vec4c=vec4[2];
1142  FTYPE vec4d=vec4[3];
1143 
1144  // #include "genortho.c"
1145 
1146  return(0);
1147 }