[a42ea15] | 1 | /* |
---|
| 2 | * Yukawa.c |
---|
| 3 | * twoyukawa |
---|
| 4 | * |
---|
| 5 | * Created by Marcus Hennig on 5/12/10. |
---|
| 6 | * Copyright 2010 __MyCompanyName__. All rights reserved. |
---|
| 7 | * |
---|
| 8 | */ |
---|
| 9 | |
---|
| 10 | #include "2Y_OneYukawa.h" |
---|
| 11 | #include "2Y_cpoly.h" |
---|
| 12 | #include "2Y_utility.h" |
---|
| 13 | #include "2Y_PairCorrelation.h" |
---|
| 14 | #include <stdio.h> |
---|
| 15 | #include <math.h> |
---|
| 16 | #include <stdlib.h> |
---|
| 17 | |
---|
| 18 | /* |
---|
| 19 | ================================================================================================== |
---|
| 20 | |
---|
| 21 | Structure factor for the potential |
---|
| 22 | |
---|
| 23 | V(r) = -kB * T * K * exp[ -Z * (r - 1)] / r for r > 1 |
---|
| 24 | V(r) = inf for r <= 1 |
---|
| 25 | |
---|
| 26 | The structure factor is parametrized by (a, b, c, d) |
---|
| 27 | which depend on (Z, K, phi). |
---|
| 28 | |
---|
| 29 | ================================================================================================== |
---|
| 30 | */ |
---|
| 31 | |
---|
| 32 | double Y_sigma( double s, double Z, double a, double b, double c, double d ) |
---|
| 33 | { |
---|
| 34 | return -(a / 2. + b + c * exp( -Z )) / s + a * pow( s, -3 ) + b * pow( s, -2 ) + ( c + d ) * pow( s + Z, -1 ); |
---|
| 35 | } |
---|
| 36 | |
---|
| 37 | double Y_tau( double s, double Z, double a, double b, double c ) |
---|
| 38 | { |
---|
| 39 | return b * pow( s, -2 ) + a * ( pow( s, -3 ) + pow( s, -2 ) ) - pow( s, -1 ) * c * Z * exp( -Z ) * pow( s + Z, -1 ); |
---|
| 40 | } |
---|
| 41 | |
---|
| 42 | double Y_q( double s, double Z, double a, double b, double c, double d ) |
---|
| 43 | { |
---|
| 44 | return Y_sigma(s, Z, a, b, c, d ) - exp( -s ) * Y_tau( s, Z, a, b, c ); |
---|
| 45 | } |
---|
| 46 | |
---|
| 47 | double Y_g( double s, double phi, double Z, double a, double b, double c, double d ) |
---|
| 48 | { |
---|
| 49 | return s * Y_tau( s, Z, a, b, c ) * exp( -s ) / ( 1 - 12 * phi * Y_q( s, Z, a, b, c, d ) ); |
---|
| 50 | } |
---|
| 51 | |
---|
| 52 | double Y_hq( double q, double Z, double K, double v ) |
---|
| 53 | { |
---|
| 54 | double t1, t2, t3, t4; |
---|
| 55 | |
---|
| 56 | if ( q == 0) |
---|
| 57 | { |
---|
| 58 | return (exp(-2*Z)*(v + (v*(-1 + Z) - 2*K*Z)*exp(Z))*(-(v*(1 + Z)) + (v + 2*K*Z*(1 + Z))*exp(Z))*pow(K,-1)*pow(Z,-4))/4.; |
---|
| 59 | } |
---|
| 60 | else |
---|
| 61 | { |
---|
| 62 | |
---|
| 63 | t1 = ( 1 - v / ( 2 * K * Z * exp( Z ) ) ) * ( ( 1 - cos( q ) ) / ( q*q ) - 1 / ( Z*Z + q*q ) ); |
---|
| 64 | t2 = ( v*v * ( q * cos( q ) - Z * sin( q ) ) ) / ( 4 * K * Z*Z * q * ( Z*Z + q*q ) ); |
---|
| 65 | t3 = ( q * cos( q ) + Z * sin( q ) ) / ( q * ( Z*Z + q*q ) ); |
---|
| 66 | t4 = v / ( Z * exp( Z ) ) - v*v / ( 4 * K * Z*Z * exp( 2 * Z ) ) - K; |
---|
| 67 | |
---|
| 68 | return v / Z * t1 - t2 + t3 * t4; |
---|
| 69 | } |
---|
| 70 | } |
---|
| 71 | |
---|
| 72 | double Y_pc( double q, |
---|
| 73 | double Z, double K, double phi, |
---|
| 74 | double a, double b, double c, double d ) |
---|
| 75 | { |
---|
| 76 | double v = 24 * phi * K * exp( Z ) * Y_g( Z, phi, Z, a, b, c, d ); |
---|
| 77 | |
---|
| 78 | double a0 = a * a; |
---|
| 79 | double b0 = -12 * phi *( pow( a + b,2 ) / 2 + a * c * exp( -Z ) ); |
---|
| 80 | |
---|
| 81 | double t1, t2, t3, t4; |
---|
| 82 | |
---|
| 83 | if ( q == 0 ) |
---|
| 84 | { |
---|
| 85 | t1 = a0 / 3; |
---|
| 86 | t2 = b0 / 4; |
---|
| 87 | t3 = a0 * phi / 12; |
---|
| 88 | } |
---|
| 89 | else |
---|
| 90 | { |
---|
| 91 | t1 = a0 * ( sin( q ) - q * cos( q ) ) / pow( q, 3 ); |
---|
| 92 | t2 = b0 * ( 2 * q * sin( q ) - ( q * q - 2 ) * cos( q ) - 2 ) / pow( q, 4 ); |
---|
| 93 | t3 = a0 * phi * ( ( q*q - 6 ) * 4 * q * sin( q ) - ( pow( q, 4 ) - 12 * q*q + 24) * cos( q ) + 24 ) / ( 2 * pow( q, 6 ) ); |
---|
| 94 | } |
---|
| 95 | t4 = Y_hq( q, Z, K, v ); |
---|
| 96 | return -24 * phi * ( t1 + t2 + t3 + t4 ); |
---|
| 97 | } |
---|
| 98 | |
---|
| 99 | double SqOneYukawa( double q, |
---|
| 100 | double Z, double K, double phi, |
---|
| 101 | double a, double b, double c, double d ) |
---|
| 102 | { |
---|
| 103 | //structure factor one-yukawa potential |
---|
| 104 | return 1. / ( 1. - Y_pc( q, Z, K, phi, a, b, c, d ) ); |
---|
| 105 | } |
---|
| 106 | |
---|
| 107 | |
---|
| 108 | /* |
---|
| 109 | ================================================================================================== |
---|
| 110 | |
---|
| 111 | The structure factor S(q) for the one-Yukawa potential is parameterized by a,b,c,d which are |
---|
| 112 | the solution of a system of non-linear equations given Z,K, phi. There are at most 4 solutions |
---|
| 113 | from which the physical one is chosen |
---|
| 114 | |
---|
| 115 | ================================================================================================== |
---|
| 116 | */ |
---|
| 117 | |
---|
| 118 | double Y_LinearEquation_1( double Z, double K, double phi, double a, double b, double c, double d ) |
---|
| 119 | { |
---|
| 120 | return b - 12*phi*(-a/8. - b/6. + d*pow(Z,-2) + c*(pow(Z,-2) - exp(-Z)*(0.5 + (1 + Z)*pow(Z,-2)))); |
---|
| 121 | } |
---|
| 122 | |
---|
| 123 | double Y_LinearEquation_2( double Z, double K, double phi, double a, double b, double c, double d ) |
---|
| 124 | { |
---|
| 125 | return 1 - a - 12*phi*(-a/3. - b/2. + d*pow(Z,-1) + c*(pow(Z,-1) - (1 + Z)*exp(-Z)*pow(Z,-1))); |
---|
| 126 | } |
---|
| 127 | |
---|
| 128 | double Y_LinearEquation_3( double Z, double K, double phi, double a, double b, double c, double d ) |
---|
| 129 | { |
---|
| 130 | return K*exp(Z) - Z*d*(1-12*phi*Y_q(Z, Z, a, b, c, d)); |
---|
| 131 | } |
---|
| 132 | |
---|
| 133 | double Y_NonlinearEquation( double Z, double K, double phi, double a, double b, double c, double d ) |
---|
| 134 | { |
---|
| 135 | return c + d - 12*phi*((c + d)*Y_sigma(Z, Z, a, b, c, d) - c*exp(-Z)*Y_tau(Z, Z, a, b, c)); |
---|
| 136 | } |
---|
| 137 | |
---|
| 138 | // Check the computed solutions satisfy the system of equations |
---|
| 139 | int Y_CheckSolution( double Z, double K, double phi, |
---|
| 140 | double a, double b, double c, double d ) |
---|
| 141 | { |
---|
| 142 | double eq_1 = chop( Y_LinearEquation_1 ( Z, K, phi, a, b, c, d ) ); |
---|
| 143 | double eq_2 = chop( Y_LinearEquation_2 ( Z, K, phi, a, b, c, d ) ); |
---|
| 144 | double eq_3 = chop( Y_LinearEquation_3 ( Z, K, phi, a, b, c, d ) ); |
---|
| 145 | double eq_4 = chop( Y_NonlinearEquation( Z, K, phi, a, b, c, d ) ); |
---|
| 146 | |
---|
| 147 | // check if all equation are zero |
---|
| 148 | return eq_1 == 0 && eq_2 == 0 && eq_3 == 0 && eq_4 == 0; |
---|
| 149 | } |
---|
| 150 | |
---|
| 151 | int Y_SolveEquations( double Z, double K, double phi, double* a, double* b, double* c, double* d, int debug ) |
---|
| 152 | { |
---|
| 153 | char buf[256]; |
---|
| 154 | |
---|
| 155 | // at most there are 4 solutions for a,b,c,d |
---|
| 156 | double sol_a[4], sol_b[4], sol_c[4], sol_d[4]; |
---|
| 157 | |
---|
| 158 | double m11 = (3*phi)/2.; |
---|
| 159 | double m13 = 6*phi*exp(-Z)*(2 + Z*(2 + Z) - 2*exp(Z))*pow(Z,-2); |
---|
| 160 | double m23 = -12*phi*exp(-Z)*(-1 - Z + exp(Z))*pow(Z,-1); |
---|
| 161 | double m31 = -6*phi*exp(-Z)*pow(Z,-2)*(2*(1 + Z) + exp(Z)*(-2 + pow(Z,2))); |
---|
| 162 | double m32 = -12*phi*(-1 + Z + exp(-Z))*pow(Z,-1); |
---|
| 163 | double m33 = 6*phi*exp(-2*Z)*pow(-1 + exp(Z),2); |
---|
| 164 | |
---|
| 165 | double delta = m23*m31 - m13*m32 + m11*(-4*m13*m31 + (4*m23*m31)/3. + (8*m13*m32)/3. - m23*m32) + m33 + (4*(-3 + m11)*m11*m33)/9.; |
---|
| 166 | double a1 = -(K*(m23 + (4*m11*(-3*m13 + m23))/3.)*exp(Z)); |
---|
| 167 | double a2 = -(m13*(m32 + 4*m11*Z)) + ((3 + 4*m11)*(m33 + m23*Z))/3.; |
---|
| 168 | double a3 = -2*phi*pow(Z,-2)*(6*m23*m32 - 24*m11*m33 + 2*Z*((3 + 4*m11)*m33 - 3*m13*(m32 + 2*m11*Z)) + (3 + 4*m11)*m23*pow(Z,2)); |
---|
| 169 | |
---|
| 170 | double b1 = -(K*((-3 + 8*m11)*m13 - 3*m11*m23)*exp(Z))/3.; |
---|
| 171 | double b2 = m13*(m31 - Z + (8*m11*Z)/3.) - m11*(m33 + m23*Z); |
---|
| 172 | double b3 = 2*phi*pow(Z,-2)*(m13*Z*(-6*m31 + 3*Z - 8*m11*Z) + 2*m33*(3 - 8*m11 + 3*m11*Z) + 3*m23*(2*m31 + m11*pow(Z,2))); |
---|
| 173 | |
---|
| 174 | double c1 = -(K*exp(Z)*pow(3 - 2*m11,2))/9.; |
---|
| 175 | double c2 = -((3 + 4*m11)*m31)/3. + m11*m32 + Z + (4*(-3 + m11)*m11*Z)/9.; |
---|
| 176 | double c3 = (-2*phi*pow(Z,-2)*(6*(12*m11*m31 + 3*m32 - 8*m11*m32) - 6*((3 + 4*m11)*m31 - 3*m11*m32)*Z + pow(3 - 2*m11,2)*pow(Z,2)))/3.; |
---|
| 177 | |
---|
| 178 | // determine d, as roots of the polynomial, from that build a,b,c |
---|
| 179 | |
---|
| 180 | double real_coefficient[5]; |
---|
| 181 | double imag_coefficient[5]; |
---|
| 182 | |
---|
| 183 | double real_root[4]; |
---|
| 184 | double imag_root[4]; |
---|
| 185 | |
---|
| 186 | double zeta = 24*phi*pow(-6*phi*Z*cosh(Z/2.) + (12*phi + (-1 + phi)*pow(Z,2))*sinh(Z/2.),2); |
---|
| 187 | double A[5]; |
---|
| 188 | int degree,i,j,n_roots; |
---|
| 189 | double x,y; |
---|
| 190 | int n,selected_root; |
---|
| 191 | double qmax,q,dq,min,sum,dr; |
---|
| 192 | double *sq,*gr; |
---|
| 193 | |
---|
| 194 | |
---|
| 195 | A[0] = -(exp(3*Z)*pow(K,2)*pow(-1 + phi,2)*pow(Z,3) / zeta ); |
---|
| 196 | A[1] = K*Z*exp(Z)*(6*phi*(2 + 4*phi + (2 + phi)*Z) + exp(Z)* |
---|
| 197 | ((-24 + Z*(18 + (-6 + Z)*Z))*pow(phi,2) - 2*phi*(6 + (-3 + Z)*pow(Z,2)) + pow(Z,3))) / zeta; |
---|
| 198 | A[2] = -12*K*phi*exp(Z)*pow(-1 + phi,2)*pow(Z,3)/zeta; |
---|
| 199 | A[3] = 6*phi*Z*exp(-Z)*(-12*phi*(1 + 2*phi)*(-1 + exp(Z)) + 6*phi*Z*(3*phi + (2 + phi)*exp(Z)) + |
---|
| 200 | 6*(-1 + phi)*phi*pow(Z,2) + pow(-1 + phi,2)*pow(Z,3))/zeta; |
---|
| 201 | A[4] = -36*exp(-Z)*pow(-1 + phi,2)*pow(phi,2)*pow(Z,3)/zeta; |
---|
| 202 | /* |
---|
| 203 | if ( debug ) |
---|
| 204 | { |
---|
| 205 | sprintf (buf, "(Z,K,phi) = (%g, %g, %g)\r", K, Z, phi ); |
---|
| 206 | XOPNotice(buf); |
---|
| 207 | sprintf (buf, "A = (%g, %g, %g, %g, %g)\r", A[0], A[1], A[2], A[3], A[4] ); |
---|
| 208 | XOPNotice(buf); |
---|
| 209 | } |
---|
| 210 | */ |
---|
| 211 | //integer degree of polynomial |
---|
| 212 | degree = 4; |
---|
| 213 | |
---|
| 214 | // vector of real and imaginary coefficients in order of decreasing powers |
---|
| 215 | for ( i = 0; i <= degree; i++ ) |
---|
| 216 | { |
---|
| 217 | real_coefficient[i] = A[4-i]; |
---|
| 218 | imag_coefficient[i] = 0.; |
---|
| 219 | } |
---|
| 220 | |
---|
| 221 | // Jenkins-Traub method to approximate the roots of the polynomial |
---|
| 222 | cpoly( real_coefficient, imag_coefficient, degree, real_root, imag_root ); |
---|
| 223 | |
---|
| 224 | // show the result if in debug mode |
---|
| 225 | /* |
---|
| 226 | if ( debug ) |
---|
| 227 | { |
---|
| 228 | for ( i = 0; i < degree; i++ ) |
---|
| 229 | { |
---|
| 230 | x = real_root[i]; |
---|
| 231 | y = imag_root[i]; |
---|
| 232 | sprintf(buf, "root(%d) = %g + %g i\r", i+1, x, y ); |
---|
| 233 | XOPNotice(buf); |
---|
| 234 | } |
---|
| 235 | sprintf(buf, "\r" ); |
---|
| 236 | XOPNotice(buf); |
---|
| 237 | } |
---|
| 238 | */ |
---|
| 239 | // determine the set of solutions for a,b,c,d, |
---|
| 240 | j = 0; |
---|
| 241 | for ( i = 0; i < degree; i++ ) |
---|
| 242 | { |
---|
| 243 | x = real_root[i]; |
---|
| 244 | y = imag_root[i]; |
---|
| 245 | |
---|
| 246 | if ( chop( y ) == 0 ) |
---|
| 247 | { |
---|
| 248 | sol_a[j] = ( a1 + a2 * x + a3 * x * x ) / ( delta * x ); |
---|
| 249 | sol_b[j] = ( b1 + b2 * x + b3 * x * x ) / ( delta * x ); |
---|
| 250 | sol_c[j] = ( c1 + c2 * x + c3 * x * x ) / ( delta * x ); |
---|
| 251 | sol_d[j] = x; |
---|
| 252 | |
---|
| 253 | j++; |
---|
| 254 | } |
---|
| 255 | } |
---|
| 256 | |
---|
| 257 | // number remaining roots |
---|
| 258 | n_roots = j; |
---|
| 259 | |
---|
| 260 | // sprintf(buf, "inside Y_solveEquations OK, before malloc: n_roots = %d\r",n_roots); |
---|
| 261 | // XOPNotice(buf); |
---|
| 262 | |
---|
| 263 | // if there is still more than one root left, than choose the one with the minimum |
---|
| 264 | // average value inside the hardcore |
---|
| 265 | |
---|
| 266 | |
---|
| 267 | |
---|
| 268 | if ( n_roots > 1 ) |
---|
| 269 | { |
---|
| 270 | // the number of q values should be a power of 2 |
---|
| 271 | // in order to speed up the FFT |
---|
| 272 | n = 1 << 14; //= 16384 |
---|
| 273 | |
---|
| 274 | // the maximum q value should be large enough |
---|
| 275 | // to enable a reasoble approximation of g(r) |
---|
| 276 | qmax = 1000.; |
---|
| 277 | dq = qmax / ( n - 1 ); |
---|
| 278 | |
---|
| 279 | // step size for g(r) = dr |
---|
| 280 | |
---|
| 281 | // allocate memory for pair correlation function g(r) |
---|
| 282 | // and structure factor S(q) |
---|
| 283 | // (note that sq and gr are pointers) |
---|
| 284 | sq = malloc( sizeof( double ) * n ); |
---|
| 285 | gr = malloc( sizeof( double ) * n ); |
---|
| 286 | |
---|
| 287 | // loop over all remaining roots |
---|
| 288 | min = 1e99; |
---|
| 289 | selected_root=0; |
---|
| 290 | |
---|
| 291 | // sprintf(buf, "after malloc: n,dq = %d %g\r",n,dq); |
---|
| 292 | // XOPNotice(buf); |
---|
| 293 | |
---|
| 294 | for ( j = 0; j < n_roots; j++) |
---|
| 295 | { |
---|
| 296 | // calculate structure factor at different q values |
---|
| 297 | for ( i = 0; i < n ; i++) |
---|
| 298 | { |
---|
| 299 | q = dq * i; |
---|
| 300 | sq[i] = SqOneYukawa( q, Z, K, phi, sol_a[j], sol_b[j], sol_c[j], sol_d[j] ); |
---|
| 301 | /* |
---|
| 302 | if(i<20 && debug) { |
---|
| 303 | sprintf(buf, "after SqOneYukawa: s(q) = %g\r",sq[i] ); |
---|
| 304 | XOPNotice(buf); |
---|
| 305 | } |
---|
| 306 | */ |
---|
| 307 | } |
---|
| 308 | |
---|
| 309 | // calculate pair correlation function for given |
---|
| 310 | // structure factor, g(r) is computed at values |
---|
| 311 | // r(i) = i * dr |
---|
| 312 | PairCorrelation( phi, dq, sq, &dr, gr, n ); |
---|
| 313 | |
---|
| 314 | // sprintf(buf, "after PairCorrelation: \r"); |
---|
| 315 | // XOPNotice(buf); |
---|
| 316 | |
---|
| 317 | // determine sum inside the hardcore |
---|
| 318 | // 0 =< r < 1 of the pair-correlation function |
---|
| 319 | sum = 0; |
---|
| 320 | for (i = 0; i < floor( 1. / dr ); i++ ) |
---|
| 321 | { |
---|
| 322 | sum += fabs( gr[i] ); |
---|
| 323 | /* |
---|
| 324 | if(i<20 && debug) { |
---|
| 325 | sprintf(buf, "g(r) in core = %g\r",fabs(gr[i])); |
---|
| 326 | XOPNotice(buf); |
---|
| 327 | } |
---|
| 328 | */ |
---|
| 329 | } |
---|
| 330 | |
---|
| 331 | // sprintf(buf, "after hard core: sum, min = %g %g\r",sum,min); |
---|
| 332 | // XOPNotice(buf); |
---|
| 333 | |
---|
| 334 | if ( sum < min ) |
---|
| 335 | { |
---|
| 336 | min = sum; |
---|
| 337 | selected_root = j; |
---|
| 338 | } |
---|
| 339 | |
---|
| 340 | |
---|
| 341 | } |
---|
| 342 | free( gr ); |
---|
| 343 | free( sq ); |
---|
| 344 | |
---|
| 345 | // sprintf(buf, "after free: selected root = %d\r",selected_root); |
---|
| 346 | // XOPNotice(buf); |
---|
| 347 | |
---|
| 348 | // physical solution was found |
---|
| 349 | *a = sol_a[ selected_root ]; |
---|
| 350 | *b = sol_b[ selected_root ]; |
---|
| 351 | *c = sol_c[ selected_root ]; |
---|
| 352 | *d = sol_d[ selected_root ]; |
---|
| 353 | |
---|
| 354 | // sprintf(buf, "after solution found (ret 1): \r"); |
---|
| 355 | // XOPNotice(buf); |
---|
| 356 | |
---|
| 357 | return 1; |
---|
| 358 | } |
---|
| 359 | else if ( n_roots == 1 ) |
---|
| 360 | { |
---|
| 361 | *a = sol_a[0]; |
---|
| 362 | *b = sol_b[0]; |
---|
| 363 | *c = sol_c[0]; |
---|
| 364 | *d = sol_d[0]; |
---|
| 365 | |
---|
| 366 | return 1; |
---|
| 367 | } |
---|
| 368 | // no solution was found |
---|
| 369 | return 0; |
---|
| 370 | } |
---|