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); }
/* 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; }
complex& complex::operator-=(const double& a) { _complex = gsl_complex_sub_real(_complex,a); return *this; }
complex complex::operator-(const double& a) const { gsl_complex rl = gsl_complex_sub_real(_complex,a); return complex(rl); }
/****************************************************************************** * 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); }