PageRenderTime 58ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/src/zero_cfrac.c

https://github.com/certik/openmx
C | 320 lines | 191 code | 84 blank | 45 comment | 21 complexity | 0bee0954c34b15e41c0fe9c6944fc600 MD5 | raw file
  1. /******************************************************************
  2. zero_cfrac.c generates zero points and associated residues
  3. of a continued fraction expansion terminated at 2n+2 level
  4. of the Ferm-Dirac function, which is derived from Gauss's
  5. hypergeometric function.
  6. This code is distributed under the constitution of GNU-GPL.
  7. (C) Taisuke Ozaki (AIST-RICS)
  8. Log of zero_cfrac.c:
  9. 14/July/2005 Released by T.Ozaki
  10. ******************************************************************/
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <math.h>
  14. #include <search.h>
  15. #include <string.h>
  16. #include "openmx_common.h"
  17. #include "lapack_prototypes.h"
  18. #ifdef nompi
  19. #include "mimic_mpi.h"
  20. #else
  21. #include "mpi.h"
  22. #endif
  23. static void Eigen_DGGEVX( int n, double **a, double **s, double *eval,
  24. double *resr, double *resi );
  25. void zero_cfrac( int n, dcomplex *zp, dcomplex *Rp )
  26. {
  27. static int i,j,N;
  28. static double **a,**s,*eval,*resr,*resi;
  29. /* check input parameters */
  30. if (n<=0){
  31. printf("\ncould not find the number of zeros\n\n");
  32. MPI_Finalize();
  33. exit(0);
  34. }
  35. /* the total number of zeros including minus value */
  36. N = 2*n + 1;
  37. /* allocation of arrays */
  38. a = (double**)malloc(sizeof(double*)*(N+2));
  39. for (i=0; i<(N+2); i++){
  40. a[i] = (double*)malloc(sizeof(double)*(N+2));
  41. }
  42. s = (double**)malloc(sizeof(double*)*(N+2));
  43. for (i=0; i<(N+2); i++){
  44. s[i] = (double*)malloc(sizeof(double)*(N+2));
  45. }
  46. eval = (double*)malloc(sizeof(double)*(n+3));
  47. resr = (double*)malloc(sizeof(double)*(n+3));
  48. resi = (double*)malloc(sizeof(double)*(n+3));
  49. /* initialize arrays */
  50. for (i=0; i<(N+2); i++){
  51. for (j=0; j<(N+2); j++){
  52. a[i][j] = 0.0;
  53. s[i][j] = 0.0;
  54. }
  55. }
  56. /* set matrix elements */
  57. s[2][1] = 1.0;
  58. s[2][2] = -0.5;
  59. for (i=3; i<=N; i++){
  60. s[i][i-1] = -0.5;
  61. s[i-1][i] = 0.5;
  62. }
  63. a[1][1] = -2.0;
  64. a[1][2] = 1.0;
  65. a[2][2] = -1.0;
  66. for (i=3; i<=N; i++){
  67. a[i][i] = -(2.0*(double)i - 3.0);
  68. }
  69. /* diagonalization */
  70. Eigen_DGGEVX( N, a, s, eval, resr, resi );
  71. for (i=0; i<n; i++){
  72. zp[i].r = 0.0;
  73. zp[i].i = eval[i+1];
  74. Rp[i].r = resr[i+1];
  75. Rp[i].i = 0.0;
  76. }
  77. /* print result */
  78. /*
  79. for (i=1; i<=n; i++){
  80. printf("i=%4d eval=%18.14f resr=%18.15f resi=%18.15f\n",i,eval[i],resr[i],resi[i]);
  81. }
  82. */
  83. /* free of arrays */
  84. for (i=0; i<(N+2); i++){
  85. free(a[i]);
  86. }
  87. free(a);
  88. for (i=0; i<(N+2); i++){
  89. free(s[i]);
  90. }
  91. free(s);
  92. free(eval);
  93. free(resr);
  94. free(resi);
  95. }
  96. void Eigen_DGGEVX( int n, double **a, double **s, double *eval, double *resr, double *resi )
  97. {
  98. static int i,j,k,l,num;
  99. static char balanc = 'N';
  100. static char jobvl = 'V';
  101. static char jobvr = 'V';
  102. static char sense = 'B';
  103. static double *A;
  104. static double *b;
  105. static double *alphar;
  106. static double *alphai;
  107. static double *beta;
  108. static double *vl;
  109. static double *vr;
  110. static double *lscale;
  111. static double *rscale;
  112. static double abnrm;
  113. static double bbnrm;
  114. static double *rconde;
  115. static double *rcondv;
  116. static double *work;
  117. static double *tmpvecr,*tmpveci;
  118. static INTEGER *iwork;
  119. static INTEGER lda,ldb,ldvl,ldvr,ilo,ihi;
  120. static INTEGER lwork,info;
  121. static logical *bwork;
  122. static double sumr,sumi,tmpr,tmpi;
  123. static double *sortnum;
  124. lda = n;
  125. ldb = n;
  126. ldvl = n;
  127. ldvr = n;
  128. A = (double*)malloc(sizeof(double)*n*n);
  129. b = (double*)malloc(sizeof(double)*n*n);
  130. alphar = (double*)malloc(sizeof(double)*n);
  131. alphai = (double*)malloc(sizeof(double)*n);
  132. beta = (double*)malloc(sizeof(double)*n);
  133. vl = (double*)malloc(sizeof(double)*n*n);
  134. vr = (double*)malloc(sizeof(double)*n*n);
  135. lscale = (double*)malloc(sizeof(double)*n);
  136. rscale = (double*)malloc(sizeof(double)*n);
  137. rconde = (double*)malloc(sizeof(double)*n);
  138. rcondv = (double*)malloc(sizeof(double)*n);
  139. lwork = 2*n*n + 12*n + 16;
  140. work = (double*)malloc(sizeof(double)*lwork);
  141. iwork = (INTEGER*)malloc(sizeof(INTEGER)*(n+6));
  142. bwork = (logical*)malloc(sizeof(logical)*n);
  143. tmpvecr = (double*)malloc(sizeof(double)*(n+2));
  144. tmpveci = (double*)malloc(sizeof(double)*(n+2));
  145. sortnum = (double*)malloc(sizeof(double)*(n+2));
  146. /* convert two dimensional arrays to one-dimensional arrays */
  147. for (i=0; i<n; i++) {
  148. for (j=0; j<n; j++) {
  149. A[j*n+i]= a[i+1][j+1];
  150. b[j*n+i]= s[i+1][j+1];
  151. }
  152. }
  153. /* call dggevx_() */
  154. F77_NAME(dggevx,DGGEVX)(
  155. &balanc, &jobvl, & jobvr, &sense, &n, A, &lda, b, &ldb,
  156. alphar, alphai, beta, vl, &ldvl, vr, &ldvr, &ilo, &ihi,
  157. lscale, rscale, &abnrm, &bbnrm, rconde, rcondv, work,
  158. &lwork, iwork, bwork, &info );
  159. if (info!=0){
  160. printf("Errors in dggevx_() info=%2d\n",info);
  161. }
  162. /*
  163. for (i=0; i<n; i++){
  164. printf("i=%4d %18.13f %18.13f %18.13f\n",i,alphar[i],alphai[i],beta[i]);
  165. }
  166. printf("\n");
  167. */
  168. num = 0;
  169. for (i=0; i<n; i++){
  170. if ( 1.0e-13<fabs(beta[i]) && 0.0<alphai[i]/beta[i] ){
  171. /* normalize the eigenvector */
  172. for (j=0; j<n; j++) {
  173. sumr = 0.0;
  174. sumi = 0.0;
  175. for (k=0; k<n; k++) {
  176. sumr += s[j+1][k+1]*vr[i*n +k];
  177. sumi += s[j+1][k+1]*vr[(i+1)*n+k];
  178. }
  179. tmpvecr[j] = sumr;
  180. tmpveci[j] = sumi;
  181. }
  182. sumr = 0.0;
  183. sumi = 0.0;
  184. for (k=0; k<n; k++) {
  185. sumr += vl[i*n+k]*tmpvecr[k] + vl[(i+1)*n+k]*tmpveci[k];
  186. sumi += vl[i*n+k]*tmpveci[k] - vl[(i+1)*n+k]*tmpvecr[k];
  187. }
  188. /* calculate zero point and residue */
  189. eval[num+1] = alphai[i]/beta[i];
  190. tmpr = vr[i*n]*vl[i*n] + vr[(i+1)*n]*vl[(i+1)*n];
  191. tmpi = -vr[i*n]*vl[(i+1)*n] + vr[(i+1)*n]*vl[i*n];
  192. resr[num+1] = tmpi/sumi;
  193. resi[num+1] = -tmpr/sumi;
  194. num++;
  195. }
  196. else{
  197. /*
  198. printf("i=%4d %18.13f %18.13f %18.13f\n",i+1,alphar[i],alphai[i],beta[i]);
  199. */
  200. }
  201. }
  202. /* check round-off error */
  203. for (i=1; i<=num; i++){
  204. if (1.0e-8<fabs(resi[i])){
  205. printf("Could not calculate zero points and residues due to round-off error\n");
  206. MPI_Finalize();
  207. exit(0);
  208. }
  209. }
  210. /* sorting */
  211. qsort_double(num,eval,resr);
  212. /* free arraies */
  213. free(A);
  214. free(b);
  215. free(alphar);
  216. free(alphai);
  217. free(beta);
  218. free(vl);
  219. free(vr);
  220. free(lscale);
  221. free(rscale);
  222. free(rconde);
  223. free(rcondv);
  224. free(work);
  225. free(iwork);
  226. free(bwork);
  227. free(tmpvecr);
  228. free(tmpveci);
  229. free(sortnum);
  230. }