/* In: tau (lattice parameter) Out: g2 -> g[0] g3 -> g[1] */ void compute_invariants(gsl_complex tau, gsl_complex *g) { gsl_complex q, q14; gsl_complex t2,t3,t24,t34; gsl_complex g3_term1, g3_term2; gsl_complex g2, g3; q = gsl_complex_exp(gsl_complex_mul_imag(tau,M_PI)); q14 = gsl_complex_exp(gsl_complex_mul_imag(tau,M_PI_4)); t2=theta20(q,q14); t3=theta30(q); t24 = pow4(t2); t34 = pow4(t3); g2 = gsl_complex_mul_real(gsl_complex_sub(gsl_complex_add(gsl_complex_mul(t24,t24),gsl_complex_mul(t34,t34)),gsl_complex_mul(t24,t34)),_CONST_43PI4); g3_term1 = gsl_complex_add(gsl_complex_mul(t24,gsl_complex_mul(t24,t24)),gsl_complex_mul(t34,gsl_complex_mul(t34,t34))); g3_term2 = gsl_complex_mul(gsl_complex_add(t24,t34),gsl_complex_mul(t24,t34)); g3 = gsl_complex_sub( gsl_complex_mul_real(g3_term1, _CONST_827PI6), gsl_complex_mul_real(g3_term2, _CONST_49PI6) ); g[0] = g2; g[1] = g3; }
/* ------------------------------------------------------ */ gsl_complex gsl_complex_arctan2 (gsl_complex a, gsl_complex b) { gsl_complex z, p; if(GSL_REAL(b) != 0.0) { z = gsl_complex_arctan(gsl_complex_div(a, b)); if(GSL_REAL(b) < 0.0){ GSL_SET_COMPLEX (&p, M_PI, 0); if(GSL_REAL(a) >= 0.0) z = gsl_complex_add(z, p); else z = gsl_complex_sub(z, p); } } else { if(GSL_REAL(a) >= 0.0) { GSL_SET_COMPLEX (&z, M_PI/2.0, 0.0); } else { GSL_SET_COMPLEX (&z, -M_PI/2.0, 0.0); } } return z; }
/* NOTE: Assumes z is in fundamental parallelogram */ void wP_and_prime(gsl_complex z, gsl_complex tau, const gsl_complex *g, gsl_complex *p, gsl_complex *pp) { int N = 6; /* Enough iterations for good P, not so good P' */ int i; gsl_complex z0; gsl_complex z02; gsl_complex pout, ppout; gsl_complex ppsolve; z = near_origin(z,tau); z0 = gsl_complex_div_real(z,(double)(1 << N)); z02 = gsl_complex_mul(z0,z0); /* Laurent expansion: P \approx 1/z^2 + (g2/20)z^2 + (g3/28) z^4 */ pout = gsl_complex_add(gsl_complex_inverse(z02), gsl_complex_add(gsl_complex_mul(z02,gsl_complex_mul_real(g[0],0.05)), gsl_complex_mul(gsl_complex_mul(z02,z02),gsl_complex_mul_real(g[1],_CONST_1_28)))); /* Laurent expansion: P' \approx -2/z^3 + g2/10z + g3/7 z^3 */ ppout = gsl_complex_add(gsl_complex_mul_real(gsl_complex_inverse(gsl_complex_mul(z0,z02)),-2.0), gsl_complex_add(gsl_complex_mul(z0,gsl_complex_mul_real(g[0],0.1)), gsl_complex_mul(gsl_complex_mul(z0,z02),gsl_complex_mul_real(g[1],_CONST_1_7)))); for (i=0;i<N;i++) { P_and_Pprime_doubler(&pout, &ppout, g); } /* At this point ppout is a decent but not great approximation of P'(z) */ /* Instead of using it directly, we use it as a guide for which square root of */ /* (4P^3 - g2 P - g3) should be selected. */ ppsolve = gsl_complex_sqrt( gsl_complex_sub( gsl_complex_mul_real(gsl_complex_mul(pout,gsl_complex_mul(pout,pout)),4.0), gsl_complex_add(gsl_complex_mul(g[0],pout),g[1]) ) ); *p = pout; if (gsl_complex_abs(gsl_complex_sub(ppsolve,ppout)) < gsl_complex_abs(gsl_complex_add(ppsolve,ppout))) *pp = ppsolve; else *pp = gsl_complex_negative(ppsolve); }
/* Assuming z is in the (1,tau) parallelogram, return the point closest to the origin among all translates of z by the lattice. */ gsl_complex near_origin(gsl_complex z, gsl_complex tau) { gsl_complex znew; znew = gsl_complex_sub_real(z,1.0); if (gsl_complex_abs(z) > gsl_complex_abs(znew)) z = znew; znew = gsl_complex_sub(z,tau); if (gsl_complex_abs(z) > gsl_complex_abs(znew)) z = znew; znew = gsl_complex_sub(z,gsl_complex_add_real(tau,1.0)); if (gsl_complex_abs(z) > gsl_complex_abs(znew)) z = znew; return z; }
/* The extended Lattes map (rational function doubling on the elliptic curve) */ void P_and_Pprime_doubler(gsl_complex *p, gsl_complex *pp, const gsl_complex *g) { gsl_complex pp3; gsl_complex ppp, ppp3; /* p'' */ ppp = gsl_complex_sub(gsl_complex_mul_real(gsl_complex_mul(*p,*p),6.0), gsl_complex_mul_real(g[0],0.5)); ppp3 = gsl_complex_mul(ppp,gsl_complex_mul(ppp,ppp)); pp3 = gsl_complex_mul(*pp,gsl_complex_mul(*pp,*pp)); *pp = gsl_complex_sub(gsl_complex_add(gsl_complex_mul_real(gsl_complex_div(gsl_complex_mul(*p,ppp),*pp),3.0), gsl_complex_mul_real(gsl_complex_div(ppp3,pp3),-0.25)), *pp); *p = P_doubler(*p,g); }
/* psi(z) for complex z in the right half-plane */ static int psi_complex_rhp( gsl_complex z, gsl_sf_result * result_re, gsl_sf_result * result_im ) { int n_recurse = 0; int i; gsl_complex a; if(GSL_REAL(z) == 0.0 && GSL_IMAG(z) == 0.0) { result_re->val = 0.0; result_im->val = 0.0; result_re->err = 0.0; result_im->err = 0.0; return GSL_EDOM; } /* compute the number of recurrences to apply */ if(GSL_REAL(z) < 20.0 && fabs(GSL_IMAG(z)) < 20.0) { const double sp = sqrt(20.0 + GSL_IMAG(z)); const double sn = sqrt(20.0 - GSL_IMAG(z)); const double rhs = sp*sn - GSL_REAL(z); if(rhs > 0.0) n_recurse = ceil(rhs); } /* compute asymptotic at the large value z + n_recurse */ a = psi_complex_asymp(gsl_complex_add_real(z, n_recurse)); result_re->err = 2.0 * GSL_DBL_EPSILON * fabs(GSL_REAL(a)); result_im->err = 2.0 * GSL_DBL_EPSILON * fabs(GSL_IMAG(a)); /* descend recursively, if necessary */ for(i = n_recurse; i >= 1; --i) { gsl_complex zn = gsl_complex_add_real(z, i - 1.0); gsl_complex zn_inverse = gsl_complex_inverse(zn); a = gsl_complex_sub(a, zn_inverse); /* accumulate the error, to catch cancellations */ result_re->err += 2.0 * GSL_DBL_EPSILON * fabs(GSL_REAL(zn_inverse)); result_im->err += 2.0 * GSL_DBL_EPSILON * fabs(GSL_IMAG(zn_inverse)); } result_re->val = GSL_REAL(a); result_im->val = GSL_IMAG(a); result_re->err += 2.0 * GSL_DBL_EPSILON * fabs(result_re->val); result_im->err += 2.0 * GSL_DBL_EPSILON * fabs(result_im->val); return GSL_SUCCESS; }
double rpp(gsl_matrix_complex * M) { gsl_complex t11, t43, t41, t13, t33, t31, mul1, mul2, mul3, mul4, sub1, sub2, div1; t11 = gsl_matrix_complex_get(M,0,0); t43 = gsl_matrix_complex_get(M,3,2); t41 = gsl_matrix_complex_get(M,3,0); t13 = gsl_matrix_complex_get(M,0,2); t33 = gsl_matrix_complex_get(M,2,2); t31 = gsl_matrix_complex_get(M,2,0); mul1 = gsl_complex_mul(t11,t43); mul2 = gsl_complex_mul(t41,t13); mul3 = gsl_complex_mul(t11,t33); mul4 = gsl_complex_mul(t13,t31); sub1 = gsl_complex_sub(mul1,mul2); sub2 = gsl_complex_sub(mul3,mul4); div1 = gsl_complex_div(sub1,sub2); return gsl_complex_abs2(div1); }
void gtmiso(gsl_matrix_complex * Tiso, gsl_complex eiso, double k0, double eta, double diso) { double eta2 = pow(eta,2); gsl_complex rb = gsl_complex_rect(eta2,0); gsl_complex za = gsl_complex_sub_real(eiso,eta2); gsl_complex qiso = gsl_complex_sqrt(za); gsl_complex zb = gsl_complex_mul_real(qiso,k0); gsl_complex zc = gsl_complex_mul_real(zb,diso); gsl_complex zd = gsl_complex_div(rb,eiso); gsl_complex carg = gsl_complex_cos(zc); gsl_complex sarg = gsl_complex_sin(zc); gsl_complex i = gsl_complex_rect(0,1); gsl_complex one = gsl_complex_rect(1,0); gsl_matrix_complex_set_zero(Tiso); gsl_matrix_complex_set(Tiso,0,0,carg); gsl_matrix_complex_set(Tiso,1,1,carg); gsl_matrix_complex_set(Tiso,2,2,carg); gsl_matrix_complex_set(Tiso,3,3,carg); gsl_complex zd1 = gsl_complex_sub(one,zd); gsl_complex zd2 = eiso; gsl_complex zd3 = one; gsl_complex zd4 = gsl_complex_sub_real(eiso,eta2); gsl_complex zmult1 = gsl_complex_mul(zd1,i); gsl_complex zmult2 = gsl_complex_mul(zd2,i); gsl_complex zmult3 = gsl_complex_mul(zd3,i); gsl_complex zmult4 = gsl_complex_mul(zd4,i); gsl_complex zdiv1 = gsl_complex_div(zmult1,qiso); gsl_complex zdiv2 = gsl_complex_div(zmult2,qiso); gsl_complex zdiv3 = gsl_complex_div(zmult3,qiso); gsl_complex zdiv4 = gsl_complex_div(zmult4,qiso); gsl_complex zmult5 = gsl_complex_mul(zdiv1,sarg); gsl_complex zmult6 = gsl_complex_mul(zdiv2,sarg); gsl_complex zmult7 = gsl_complex_mul(zdiv3,sarg); gsl_complex zmult8 = gsl_complex_mul(zdiv4,sarg); gsl_matrix_complex_set(Tiso,0,1,zmult5); gsl_matrix_complex_set(Tiso,1,0,zmult6); gsl_matrix_complex_set(Tiso,2,3,zmult7); gsl_matrix_complex_set(Tiso,3,2,zmult8); }
int main(int argc, char** argv) { gsl_complex a,b; GSL_SET_COMPLEX(&a,3,4);//a=3+4i GSL_SET_COMPLEX(&b,6,8);//b=6+8i gsl_complex c = gsl_complex_add(a,b); printf("a+b\treal : %f image : %f\n",c.dat[0],c.dat[1]); c = gsl_complex_sub(a,b); printf("a-b\treal : %f image : %f\n",c.dat[0],c.dat[1]); c = gsl_complex_mul(a,b); printf("a*b\treal : %f image : %f\n",c.dat[0],c.dat[1]); c = gsl_complex_div(a,b); printf("a/b\treal : %f image : %f\n",c.dat[0],c.dat[1]); // system("PAUSE"); return 0; }
/* The Lattes map */ gsl_complex P_doubler(gsl_complex p, const gsl_complex *g) { gsl_complex p2, p3; gsl_complex num; gsl_complex denom; gsl_complex term; p2 = gsl_complex_mul(p,p); p3 = gsl_complex_mul(p2,p); /* denom = 4p^3 - g2p - g3 */ denom = gsl_complex_sub(gsl_complex_mul_real(p3,4.0), gsl_complex_add(gsl_complex_mul(p,g[0]),g[1])); /* num = (p^2 + g2/4)^2 + 2g3p */ term = gsl_complex_add(p2,gsl_complex_mul_real(g[0],0.25)); num = gsl_complex_add(gsl_complex_mul(p,gsl_complex_mul_real(g[1],2.0)), gsl_complex_mul(term,term)); return gsl_complex_div(num,denom); }
void tabulate(FILE *os, ComplexFunction fun, void *params, gsl_complex z0, gsl_complex z1, int n) { gsl_complex k = gsl_complex_sub(z1, z0); for (int i = 0; i < n; ++i) { double t = (double)i / (n - 1); gsl_complex z = gsl_complex_add(z0, gsl_complex_mul_real(k, t)); gsl_complex f = fun(z, params); double abs = gsl_complex_abs(f); fprintf(os, "%g %g %g %g %g %g %g\n", t, GSL_REAL(z), GSL_IMAG(z), GSL_REAL(f), GSL_IMAG(f), abs, -abs); } }
/****************************************************************************** * calc_X() * This function calcs the X's and g's for a given theta. * * Parameters * --------- * * Returns * ------- * * Notes * ----- * This function computes * X[j] = Ar[j]/Ai[j] * where Ar[j] and Ai[j] are the field amplitdues within layer j at * the j/j-1 interface. For the base layer X[0] = 0, * ie there is no reflected field in the substrate. While * X[nlayers-1] is the field intensity at the top of the multilayer, * therefore |X[nlayers-1]|^2 = R * * The X's are calculated using the optical recursion formlua, starting at the bottom * where X[0] = 0 and calc X[1], and proceding to calc of X[nlayer-1]: * * X[j] = ( r[j] + X[j-1]*phase) / (1 + r[j]*X[j-1]*phase) * * The r[j] values are the reflection coefficients for the j/j-1 interface, * and calculated from: * * r[j] = (g[j]-g[j-1])/(g[j]+g[j-1]) * * This function also includes an interfacial roughness term mult into * the reflection coefficient for the j/j-1 interface: * * r[j] = r[j]*exp(-1.0(q*sig[j])^2) * * The phase term accounts for the phase shift and attentuation of the field * traversing the j-1 layer (ie from the j-1/j-2 interface to the j/j-1 interface) * * phase = exp( -i* 2*k*d[j-1] * g[j-1]) * * Note if j == 1 then the phase for layer j-1 is 0.0, * ie infinitley thick base layer * * Note: g[j] = sqrt( n[j]^2 - cos(theta)^2 ) * where n[j] is the layers index of refraction: n[j] = 1-del[j]-i*bet[j] * Hence, each layer has a unique g value. We assume here * that the del[j] and bet[j] have already been calculated * (see calc_del_bet(), this should be called before this function). * * * Note: double check how doing the phase calc below, is that the best way?? * e.g. could we use: * phase = gsl_complex_exp( gsl_complex_mul_real(g1,-1.0*k*d[j])); * instead of * phase = gsl_complex_exp( gsl_complex_mul(phase,g1)); * * Note we should move the g and r calc to a new function, possibly calc the * t values as well and store these so we dont have to recalc in calc_A() (???) * ******************************************************************************/ int calc_X(double theta, ref_model *ref, angle_calc *ang_c, layer_calc *lay_c){ int i, j; double cos_sqr_thet, k, q, dw; double *d, *sig; gsl_complex g1, g2, num, den, r, X2, X1, n1, n2, phase; // convenience vars cos_sqr_thet = square(cos(theta*M_PI/180.)); k = ref->k; q = 2.0*k*sin((theta*M_PI/180.)); d = ref->d; sig = ref->sigma; // start at bottom // ie interface 0 ang_c->Re_X[0] = GSL_REAL(X1) = 0.0; ang_c->Im_X[0] = GSL_IMAG(X1) = 0.0; // calc g for base layer (g[0]) // n = 1 - del -i*bet // g = sqrt( n^2 - cos(theta)^2 ) GSL_REAL(n1) = 1.0 - lay_c->del[0]; GSL_IMAG(n1) = -1.0*lay_c->bet[0]; g1 = gsl_complex_sqrt( gsl_complex_sub_real(gsl_complex_mul(n1, n1), cos_sqr_thet) ); // store g for base layer ang_c->Re_g[0] = GSL_REAL(g1); ang_c->Im_g[0] = GSL_IMAG(g1); // loop over all layers // note j is upper layer and i is the interface number // the loop starts considering the first interface (i=0) // which is the interface between the base layer (j=0) // and the first layer (j=1) ie the 1/0 interface // note there are nlayer-1 interfaces... i = 0; for ( j = 1; j < ref->nlayer; j++){ // calc g for upper layer // n = 1 - del -i*bet // g2 = sqrt( n^2 - cos(theta)^2 ) GSL_REAL(n2) = 1.0 - lay_c->del[j]; GSL_IMAG(n2) = -1.0 * lay_c->bet[j]; g2 = gsl_complex_sqrt( gsl_complex_sub_real(gsl_complex_mul(n2, n2), cos_sqr_thet) ); // store g for layer j ang_c->Re_g[j] = GSL_REAL(g2); ang_c->Im_g[j] = GSL_IMAG(g2); // calculate r for the j/j-1 interface // r_j = (g2-g1)/(g2+g1) //GSL_SET_COMPLEX(&num,0.0,0.0); //GSL_SET_COMPLEX(&den,0.0,0.0); //GSL_SET_COMPLEX(&r,0.0,0.0); num = gsl_complex_sub(g2,g1); den = gsl_complex_add(g2,g1); r = gsl_complex_div(num,den); // calc r including roughness // simple dw roughness model // r = r*exp(-1.0(q*sig)^2) // sigma[i] if (ref->sigma[j] > 0.0){ //dw = exp(-1.0*square(q*ref->sigma[j])); dw = exp(-1.0*square(q*ref->sigma[i])); r = gsl_complex_mul_real(r,dw); } //calc phase shift and attentuation for //field traversing the j-1 layer //phase = exp( -i* 2*k*d[j-1] * g1) // if j == 1 then the phase for layer j-1 // is 0.0, ie infinitley thick base layer if (j == 1){ GSL_REAL(phase) = 0.0; GSL_IMAG(phase) = 0.0; } else { // check here GSL_REAL(phase) = 0.0; GSL_IMAG(phase) = -2.0*k*d[j-1]; phase = gsl_complex_exp( gsl_complex_mul(phase,g1)); } // calc Xj // X2 = ( r + X1*phase) / (1 + r*X1*phase) //GSL_SET_COMPLEX(&num,0.0,0.0); //GSL_SET_COMPLEX(&den,0.0,0.0); num = gsl_complex_add(r,gsl_complex_mul(X1,phase)); den = gsl_complex_add_real(gsl_complex_mul(r,gsl_complex_mul(X1,phase)), 1.0); X2 = gsl_complex_div(num,den); if (fabs(GSL_REAL(X2)) < 1e-10){ GSL_REAL(X2) = 0.0; } if (fabs(GSL_IMAG(X2)) < 1e-10){ GSL_IMAG(X2) = 0.0; } // store values of Xj ang_c->Re_X[j] = GSL_REAL(X2); ang_c->Im_X[j] = GSL_IMAG(X2); // use top layer as bottom for next time through GSL_REAL(X1) = GSL_REAL(X2); GSL_IMAG(X1) = GSL_IMAG(X2); // do the same for g's GSL_REAL(g1) = GSL_REAL(g2); GSL_IMAG(g1) = GSL_IMAG(g2); //increment the interface number i++; } return (SUCCESS); }
int gsl_linalg_complex_LU_decomp (gsl_matrix_complex * A, gsl_permutation * p, int *signum) { if (A->size1 != A->size2) { GSL_ERROR ("LU decomposition requires square matrix", GSL_ENOTSQR); } else if (p->size != A->size1) { GSL_ERROR ("permutation length must match matrix size", GSL_EBADLEN); } else { const size_t N = A->size1; size_t i, j, k; *signum = 1; gsl_permutation_init (p); for (j = 0; j < N - 1; j++) { /* Find maximum in the j-th column */ gsl_complex ajj = gsl_matrix_complex_get (A, j, j); double max = gsl_complex_abs (ajj); size_t i_pivot = j; for (i = j + 1; i < N; i++) { gsl_complex aij = gsl_matrix_complex_get (A, i, j); double ai = gsl_complex_abs (aij); if (ai > max) { max = ai; i_pivot = i; } } if (i_pivot != j) { gsl_matrix_complex_swap_rows (A, j, i_pivot); gsl_permutation_swap (p, j, i_pivot); *signum = -(*signum); } ajj = gsl_matrix_complex_get (A, j, j); if (!(GSL_REAL(ajj) == 0.0 && GSL_IMAG(ajj) == 0.0)) { for (i = j + 1; i < N; i++) { gsl_complex aij_orig = gsl_matrix_complex_get (A, i, j); gsl_complex aij = gsl_complex_div (aij_orig, ajj); gsl_matrix_complex_set (A, i, j, aij); for (k = j + 1; k < N; k++) { gsl_complex aik = gsl_matrix_complex_get (A, i, k); gsl_complex ajk = gsl_matrix_complex_get (A, j, k); /* aik = aik - aij * ajk */ gsl_complex aijajk = gsl_complex_mul (aij, ajk); gsl_complex aik_new = gsl_complex_sub (aik, aijajk); gsl_matrix_complex_set (A, i, k, aik_new); } } } } return GSL_SUCCESS; } }
void SoftDemapper::Run() { unsigned int nbits,nsymbs,count; /// fetch data objects gsl_vector_complex_class input = vin1.GetDataObj(); // number of input symbs nsymbs = input.vec->size; // cout << "received " << nsymbs << " elements in vector." << endl; // number of output symbols nbits = nsymbs * Nb(); gsl_vector *llr=gsl_vector_alloc(nbits); double *den = (double *)calloc( Nb(), sizeof(double) ); double *num = (double *)calloc( Nb(), sizeof(double) ); // determine symb_likelyhood for (int i=0;i<nsymbs;i++) { // cycle through received symbols for (int k=0;k<Nb();k++) { num[k] = GSL_NEGINF; den[k] = GSL_NEGINF; } // the received symbol gsl_complex recsym = gsl_vector_complex_get(input.vec,i); // cout << "received symbol = (" // << GSL_REAL(recsym) // << "," // << GSL_IMAG(recsym) // << ") " << endl; for (int j=0;j<Ns;j++) { // cycle through postulated symbol // gray encoded symbol id unsigned int symbol_id = gsl_vector_uint_get(gray_encoding,j); // complex symbol gsl_complex refsym = gsl_complex_polar(1.0,symbol_arg * symbol_id ); // likelyhood metric double metric = gsl_complex_abs( gsl_complex_sub(refsym,recsym) ); metric = -EsNo()*metric*metric; //gsl_matrix_complex_set(symb_likelihoods,j,i); // // HERE is available a metric for symb i and refsymb j // int mask = 1 << Nb() - 1; for (int k=0;k<Nb();k++) { /* loop over bits */ if (mask&j) { /* this bit is a one */ num[k] = ( *max_star[LMAP()] )( num[k], metric ); } else { /* this bit is a zero */ den[k] = ( *max_star[LMAP()] )( den[k], metric ); } mask = mask >> 1; } //bits } // alphabet for (int k=0;k<Nb();k++) { gsl_vector_set(llr,Nb()*i+k,num[k] - den[k]); } } // symbols gsl_vector_class outv(llr); // outv.show(); // output bitwise LLR vout1.DeliverDataObj(outv); gsl_vector_free(llr); // free dynamic structures free(num); free(den); }
complex& complex::operator-=(const complex& z1) { _complex = gsl_complex_sub(_complex, z1._complex); return *this; }
complex complex::operator-(const complex& z1) const { gsl_complex rl = gsl_complex_sub(_complex, z1._complex); return complex(rl); }
/****************************************************************************** * calc_A() * This function calcs the A's for a given theta. * * Parameters * --------- * * Returns * ------- * * Notes * ----- * This function assumes that the X[j] and g[j] values have already * been calculated (see calc_X()) * * Note: X[j] = Ar[j]/Ai[j] * And we can derive: * * Ai[j] = phase*Ai[j+1]*t[j+1] / ( 1 + phase^2 * X[j] * r[j+1]) * Ar[j] = Ai[j]*X[j] * * where Ar[j] and Ai[j] are the field amplitudes within layer j at * the j/j-1 interface. * * For the top layer Ai[nlayer-1] = 1. ie everything is referenced to * unit intensity (Io=|Ai|^2) within the top layer. Therefore Ar[0] = X[0]. * * Given the known values for the top layer we can procede to calculate each Ai and Ar * value starting at the top. * * For the base layer X[0] = 0, ie Ar[0] = 0 * * The values of r[j+1] and t[j+1] are the reflection and transmission coefficients * for the j+1/j interface, respectively, and calculated from: * * r[j+1] = (g[j+1]-g[j])/(g[j+1]+g[j]) * t[j+1] = 2*g[j+1]/(g[j+1] + g[j]) = 1 + r[j+1] * * This function also includes an interfacial roughness term mult into * the reflection coefficient for the j+1/j interface: * * r[j+1] = r[j+1]*exp(-1.0(q*sig[j+1])^2) * * Note we include roughness in the t calc using the below: * t[j+1] = 1 + r[j+1]*exp(-1.0(q*sig[j+1])^2) * * Therefore as r-> 0, t-> 1. This is only done if calc_params[10] > 0. * Otherwise t is calc explicitley from the g's * * The phase term accounts for the phase shift and attentuation of the field * traversing the j layer (ie from the j+1/j interface to the j/j-1 interface), * ie the Ai[j] and Ar[j] are the field amplitudes at the j/j-1 interface: * * phase = exp( -i*k*d[j] * g[j]) * * Note if j == 0 then the phase for layer j is 0.0, and X[0] = 0 * ie in the infinitley thick base layer we assumer the is no reflected * field (Ar[0] = 0.0) and we are calculating the the field amplitude at the * top of layer 0 rather than the bottom of layer 0. * * * Note: double check how doing the phase calc below, is that the best way?? * e.g. could we use: * phase = gsl_complex_exp( gsl_complex_mul_real(g1,-1.0*k*d[j])); * instead of * phase = gsl_complex_exp( gsl_complex_mul(phase,g1)); * * ******************************************************************************/ int calc_A(double theta, ref_model *ref, angle_calc *ang_c, layer_calc *lay_c){ int i, j, idx; double cos_sqr_thet, k, q, dw; double *d, *sig; gsl_complex g1, g2, num, den, r, t, Ai_2, Ar_2, Ai_1, Ar_1, X1, phase, phase_sqr; //gsl_complex n1, n2; // convenience vars cos_sqr_thet = square(cos(theta*M_PI/180.)); k = ref->k; q = 2.0*k*sin((theta*M_PI/180.)); d = ref->d; sig = ref->sigma; // start at top idx = ref->nlayer - 1; // get g for upper layer, ie air/vaccum slab // ie del ~ bet ~ 0. // n = 1 - del -i*bet ~ 1 // g2 = sqrt( n^2 - cos(theta)^2 ) //GSL_REAL(n2) = 1.0 - lay_c->del[idx]; //GSL_IMAG(n2) = -1.0*lay_c->bet[idx]; //g2 = gsl_complex_sqrt( gsl_complex_sub_real(gsl_complex_mul(n2, n2), cos_sqr_thet) ); GSL_SET_COMPLEX(&g2,ang_c->Re_g[idx],ang_c->Im_g[idx]); // for the top (j=nlayer-1) layer, Ai =1.0 // therefore Ar = Ai*X = X // store these in A arrays ang_c->Re_Ai[idx] = GSL_REAL(Ai_2) = 1.0; ang_c->Im_Ai[idx] = GSL_IMAG(Ai_2) = 0.0; ang_c->Re_Ar[idx] = GSL_REAL(Ar_2) = ang_c->Re_X[idx]; ang_c->Im_Ar[idx] = GSL_IMAG(Ar_2) = ang_c->Im_X[idx]; // loop over all layers, start at top - 1 // ie loop from j = nlayer-2 --> j = 0 // note j is lower layer in the r and t calcs // therefore we are considering the j+1/j interface // i is the interface number, ie which interface // are the r's and t's calc for i = idx - 1; for ( j = idx - 1; j > -1 ; j--){ // calc g and phase for lower layer // n = 1 - del -i*bet // g1 = sqrt( n^2 - cos(theta)^2 ) //GSL_REAL(n1) = 1.0 - xpar->del[j]; //GSL_IMAG(n1) = -1.0 * xpar->bet[j]; //g1 = gsl_complex_sqrt( gsl_complex_sub_real(gsl_complex_mul(n1, n1), cos_sqr_thet) ); GSL_SET_COMPLEX(&g1,ang_c->Re_g[j],ang_c->Im_g[j]); //calc phase and attenuation // phase = exp( -i*k*d[j] * g1) // phase_sqr = (phase)^2 if (j == 0){ GSL_REAL(phase) = 1.0; GSL_IMAG(phase) = 0.0; GSL_REAL(phase_sqr) = 1.0; GSL_IMAG(phase_sqr) = 0.0; } else { GSL_REAL(phase) = 0.0; GSL_IMAG(phase) = -1.0*k*d[j]; phase = gsl_complex_exp( gsl_complex_mul(phase,g1)); GSL_REAL(phase_sqr) = 0.0; GSL_IMAG(phase_sqr) = -2.0*k*d[j]; phase_sqr = gsl_complex_exp( gsl_complex_mul(phase_sqr,g1)); } // calc r for upper layer // r = (g2-g1)/(g2+g1) GSL_SET_COMPLEX(&num,0.0,0.0); GSL_SET_COMPLEX(&den,0.0,0.0); num = gsl_complex_sub(g2,g1); den = gsl_complex_add(g2,g1); r = gsl_complex_div(num,den); // include simple dw type roughness // r = r*exp(-1.0(q*sig)^2) if (ref->sigma[j+1] > 0.0){ //dw = exp(-1.0*square(q*ref->sigma[j+1])); dw = exp(-1.0*square(q*ref->sigma[i])); r = gsl_complex_mul_real(r,dw); } // calc t for upper layer // t = 2*g2/(g2 + g1) if (ref->calc_params[10] == 0.0){ GSL_SET_COMPLEX(&num,0.0,0.0); num = gsl_complex_mul_real(g2, 2.0); t = gsl_complex_div(num,den); } else { // note as as r->0, t->1 // ie t = 1+r, so we could just calc t from r? t = gsl_complex_add_real(r,1.0); } // calc Ai_1 and Ar_1 // these are field mag in the lower slab (layer j) // at the bottom of the slab, relative to Ai in the top layer (j=nlayer-1) // Ai_1 = phase*Ai_2*t / ( 1 + phase^2 * X1 * r) // Ar_1 = Ai_1*X1 GSL_REAL(X1) = ang_c->Re_X[j]; GSL_IMAG(X1) = ang_c->Im_X[j]; GSL_SET_COMPLEX(&num,0.0,0.0); GSL_SET_COMPLEX(&den,0.0,0.0); num = gsl_complex_mul(t,gsl_complex_mul(Ai_2,phase)); den = gsl_complex_add_real(gsl_complex_mul(phase_sqr,gsl_complex_mul(X1,r)),1.0); Ai_1 = gsl_complex_div(num,den); if (fabs(GSL_REAL(Ai_1)) < 1.0e-12){ GSL_REAL(Ai_1) = 0.0; } if (fabs(GSL_IMAG(Ai_1)) < 1.0e-12){ GSL_IMAG(Ai_1) = 0.0; } Ar_1 = gsl_complex_mul(Ai_1,X1); //store results ang_c->Re_Ai[j] = GSL_REAL(Ai_1); ang_c->Im_Ai[j] = GSL_IMAG(Ai_1); ang_c->Re_Ar[j] = GSL_REAL(Ar_1); ang_c->Im_Ar[j] = GSL_IMAG(Ar_1); // this is the field intensity at the bottom of layer j // except for layer j = 0, this is the intensity at the top // of the base layer (bc of how phase is calc above) // use bottom layer as top for next time through GSL_REAL(Ai_2) = GSL_REAL(Ai_1); GSL_IMAG(Ai_2) = GSL_IMAG(Ai_1); GSL_REAL(Ar_2) = GSL_REAL(Ar_1); GSL_IMAG(Ar_2) = GSL_IMAG(Ar_1); // do the same for g's GSL_REAL(g2) = GSL_REAL(g1); GSL_IMAG(g2) = GSL_IMAG(g1); // increment interface number i--; } return (SUCCESS); }
gsl_complex integrate_line_segment(Params *params, gsl_complex p0, gsl_complex p1) { gsl_complex k = gsl_complex_sub(p1, p0); const double r = params->r; const double a = 0.0; // parameter interval start const double b = 1.0; // parameter interval end const double L = b - a; // length of parameter interval const size_t table_size = 1000; // calculate frequency of oscillatory part double omega = GSL_REAL(k) * r; gsl_integration_workspace *ws = gsl_integration_workspace_alloc(table_size); // prepare sine/cosine tables for integration gsl_integration_qawo_table *table_cos = gsl_integration_qawo_table_alloc(omega, L, GSL_INTEG_COSINE, table_size); gsl_integration_qawo_table *table_sin = gsl_integration_qawo_table_alloc(omega, L, GSL_INTEG_SINE, table_size); LineSegmentParams lsp; lsp.p0 = p0; lsp.k = k; lsp.damping = params->r * GSL_IMAG(k); lsp.params = params; //fprintf(stderr, "p0 = %g %g, p1 = %g %g, k = %g %g, r = %g, omega = %g, damping = %g\n", // GSL_REAL(p0), GSL_IMAG(p0), GSL_REAL(p1), GSL_IMAG(p1), // GSL_REAL(k), GSL_IMAG(k), r, omega, lsp.damping); gsl_function F; F.function = &line_segment_integrand_wrapper; F.params = &lsp; double result_real_cos, abserr_real_cos; double result_real_sin, abserr_real_sin; double result_imag_cos, abserr_imag_cos; double result_imag_sin, abserr_imag_sin; double epsabs = 1e-9; double epsrel = 1e-9; lsp.part = REAL; gsl_integration_qawo(&F, a, epsabs, epsrel, table_size, ws, table_cos, &result_real_cos, &abserr_real_cos); gsl_integration_qawo(&F, a, epsabs, epsrel, table_size, ws, table_sin, &result_real_sin, &abserr_real_sin); lsp.part = IMAG; gsl_integration_qawo(&F, a, epsabs, epsrel, table_size, ws, table_cos, &result_imag_cos, &abserr_imag_cos); gsl_integration_qawo(&F, a, epsabs, epsrel, table_size, ws, table_sin, &result_imag_sin, &abserr_imag_sin); //fprintf(stderr, " cos: %g (+- %g) %g (+- %g) sin: %g (+- %g) %g (+- %g)\n", // result_real_cos, abserr_real_cos, result_imag_cos, abserr_imag_cos, // result_real_sin, abserr_real_sin, result_imag_sin, abserr_imag_sin); gsl_complex cos_part = gsl_complex_rect(result_real_cos, result_imag_cos); gsl_complex sin_part = gsl_complex_rect(-result_imag_sin, result_real_sin); gsl_complex sum = gsl_complex_add(cos_part, sin_part); gsl_complex result = gsl_complex_mul( k, gsl_complex_mul(sum, gsl_complex_exp(gsl_complex_mul_imag(p0, params->r)))); gsl_integration_qawo_table_free(table_sin); gsl_integration_qawo_table_free(table_cos); gsl_integration_workspace_free(ws); return result; }