//****************************************************************************** //** SCATMECH: Polarized Light Scattering C++ Class Library //** //** File: rcw.cpp //** //** Thomas A. Germer //** Optical Technology Division, National Institute of Standards and Technology //** 100 Bureau Dr. Stop 8443; Gaithersburg, MD 20899-8443 //** Phone: (301) 975-2876; FAX: (301) 975-6991 //** Email: thomas.germer@nist.gov //** //** Version: 6.00 (February 2008) //** //****************************************************************************** #include "rcw.h" #include "matrixmath.h" using namespace std; // // Equation numbers refer to Moharam et al. J. Opt. Soc. Am. A 12, 1068 (1995) or // Moharam et al. J. Opt. Soc. Am. A 12, 1077 (1995) // namespace SCATMECH { using namespace CMLIB; namespace { template const T& min(const T& a,const T& b) {return (a const T& max(const T& a,const T& b) {return (a>b) ? a : b;} static const COMPLEX cI(0,1); } int RCW_Model::get_recalc() { if (lambda!=grating->get_lambda()) grating->set_lambda(lambda); return grating->get_recalc() || Model::get_recalc(); } CVector RCW_Model::GetEField(const JonesVector& inpol, const Vector& pos, bool incident) { SETUP(); CVector result(0.,0.,0.); if (type==0 && pos.z<0) return result; if (type==1 && pos.z>-totalthickness) return result; if (type==0 && incident) { Vector kin(nI*k0*sin(thetai*deg),0.,-nI*k0*cos(thetai*deg)); Vector s(0.,1.,0.); Vector p = cross(kin,s)/(k0*nI); COMPLEX phase = exp(cI*COMPLEX(kin*pos)); result = (inpol.S()*CVector(s)+inpol.P()*CVector(p))*phase; } for (int i=0;i-totalthickness) return result; if (type==0 && incident) { Vector kin(nI*k0*sin(thetai*deg),0.,-nI*k0*cos(thetai*deg)); Vector p(0.,-1,0.); Vector s = cross(p,kin)/(k0*nI); COMPLEX phase = nI*exp(cI*COMPLEX(kin*pos)); result = (inpol.S()*CVector(s)+inpol.P()*CVector(p))*phase; } for (int i=0;iSETUP(); // Forces grating to recalc if needed period = grating->get_period(); totalthickness=0; for (i=0;iget_levels();++i) { totalthickness+=grating->get_thickness(i); } dielectric_function medium_i = grating->get_medium_i(); dielectric_function medium_t = grating->get_medium_t(); k0 = 2*pi/lambda; n = order; nmat = 2*n+1; if (medium_i.k(lambda)!=0.) error("medium_i must be non-absorbing"); nI = medium_i.n(lambda); eI = sqr(nI); // Note: Moharam, et al., use n-ik convention... nII = conj((COMPLEX)medium_t.index(lambda)); eII = sqr(nII); kxi.resize(nmat); Kx.resize(nmat); kIzi.resize(nmat); kIIzi.resize(nmat); YI.resize(nmat); YII.resize(nmat); ZI.resize(nmat); ZII.resize(nmat); V.resize(nmat); kvector.resize(nmat); r.resize(nmat); R.resize(nmat); // Incident wavevector, with coordinates aligned along grating. // Note that SCATMECH generally assumes the z axis points out // of the grating. rotation represents a counterclockwise rotation // of the grating, looking down at the surface. inckx = k0*nI*sin(thetai*deg)*cos(rotation*deg); incky = -k0*nI*sin(thetai*deg)*sin(rotation*deg); inckz = -k0*nI*cos(thetai*deg); // This program has a problem if kx of incident light is zero... if (fabs(inckx/k0/nI)<1E-7) { inckx = k0*nI*1E-7; inckz = -k0*sqrt(eI - sqr(inckx/k0) - sqr(incky/k0)); } // Eq. (51) ... // Moharam et al. assume z axis points into grating, so y(Moharam) = -y(SCATMECH) ky = -incky; // Kvector (magnitude) associated with grating... double Kgrating = 2.*pi/period; for (i=0;i0) aa = conj(aa); kIzi[i] = aa; COMPLEX bb = k0*sqrt(eII - kk - sqr(ky/k0)); if (imag(bb)>0) bb = conj(bb); kIIzi[i] = bb; // Defined after Eq. (24)... YI[i] = kIzi[i]/k0; YII[i] = kIIzi[i]/k0; // Defined after Eq. (44)... ZI[i] = kIzi[i]/k0/sqr(nI); ZII[i] = kIIzi[i]/k0/sqr(nII); } // Min and max orders that propagate... min_order=order+1; max_order=-order-1; // Rotation matrix elements to rotate from sample coordinates to // incident wave coordinates... double cost = cos(rotation*deg); double sint = sin(rotation*deg); for (i=-order;i<=order;++i) { int j=i+n; R[j] = JonesZero(); V[j] = Vector(0,0,0); double kx = inckx-i*Kgrating; double ky = incky; if (type==0) { COMPLEX eps = medium_i.epsilon(lambda); COMPLEX kz = sqrt(sqr(k0)*eps-sqr(kx)-sqr(ky)); // Diffracted wavevector in incident wave coordinates... kvector[j] = CVector(kx*cost-ky*sint,kx*sint+ky*cost,kz); // If it is propagating... if (imag(kz)==0.) { V[j] = Vector(real(kvector[j].x),real(kvector[j].y),real(kvector[j].z))/(k0*nI); if (imax_order) max_order=i; } } else { COMPLEX eps = medium_t.epsilon(lambda); COMPLEX kz = -sqrt(sqr(k0)*eps-sqr(kx)-sqr(ky)); // Diffracted wavevector in incident wave coordinates... kvector[j] = CVector(kx*cost-ky*sint,kx*sint+ky*cost,kz); // If it is propagating... if (imag(kz)==0) { V[j] = Vector(real(kvector[j].x),real(kvector[j].y),-real(kvector[j].z))/(k0*real(nII)); if (min_orderi) max_order=i; } } } if (rotation==0) { if (type==0) { InPlaneReflection(); } else { InPlaneTransmission(); } } else { if (type==0) { ConicalReflection(); } else { ConicalTransmission(); } } kxi.resize(0); Kx.resize(0); kIzi.resize(0); YI.resize(0); YII.resize(0); ZI.resize(0); ZII.resize(0); } //*********************************************************************** //** ** //** In-Plane Reflection ** //** ** //*********************************************************************** void RCW_Model::InPlaneReflection() { int i,j,k; int nnmat = 2*nmat; vector EEE(2*nmat+1),EEEE(2*nmat+1); vector E(sqr(nmat)); vector Einv(sqr(nmat)); vector EE(sqr(nmat)); vector EEinv(sqr(nmat)); vector A(sqr(nmat)); vector B(sqr(nmat)); vector EB(sqr(nmat)); vector Ws(sqr(nmat)),Qs(nmat),Xs(nmat),Vs(sqr(nmat)); vector Wp(sqr(nmat)),Qp(nmat),Xp(nmat),Vp(sqr(nmat)); vector Fs(sqr(nnmat)),Fp(sqr(nnmat)); vector indexs(nnmat),indexp(nnmat); vector WXVXs(nnmat); vector WXVXp(nnmat); vector as(2*nmat*nmat),ap(2*nmat*nmat); vector fs(nmat*nmat),gs(nmat*nmat); vector fp(nmat*nmat),gp(nmat*nmat); for (i=0;iget_levels()-1;layer>=0;--layer) { string layerstr = format("(layer = %d)",layer); // // Get the Fourier components for this layer... // message(layerstr + "Creating E matrix"); for (i=-nmat;i<=nmat;++i) { EEE[i+nmat]=conj(grating->fourier(i,layer,0)); EEEE[i+nmat]=conj(grating->fourier(i,layer,1)); } for (i=0;iget_thickness(layer)); } for (i=0;iget_thickness(layer)); } for (i=0;i Gs(nnmat*nnmat),Gp(nnmat*nnmat); for (i=0;i RRs(nnmat,0.); vector RRp(nnmat,0.); RRs[n] = -1.; //RRs[n+nmat] = COMPLEX(0.,-cos(thetai*deg)*nI); RRs[n+nmat] = COMPLEX(0.,inckz/k0); RRp[n] = -1.; RRp[n+nmat] = COMPLEX(0.,inckz/k0/sqr(nI)); message("Solving for reflected fields"); { vector indexs(nnmat),indexp(nnmat); message("LU decomposition of Gs"); LUdecompose(Gs,nnmat,indexs); message("LU decomposition of Gs"); LUbacksubstitute(Gs,nnmat,indexs,RRs); message("LU decomposition of Gp"); LUdecompose(Gp,nnmat,indexp); message("LU decomposition of Gp"); LUbacksubstitute(Gp,nnmat,indexp,RRp); } message("Finishing"); for (i=-order;i<=order;++i) { j= n+i; r[j].PS() = 0.; r[j].PP() = conj(RRp[j]); r[j].SP() = 0.; r[j].SS() = conj(RRs[j]); R[j]=MuellerMatrix(r[j])*fabs(real(kIzi[j])/inckz);; } } //*********************************************************************** //** ** //** In-Plane Transmission ** //** ** //*********************************************************************** void RCW_Model::InPlaneTransmission() { int i,j,k; int nnmat = 2*nmat; vector EEE(2*nmat+1),EEEE(2*nmat+1); vector E(sqr(nmat)); vector Einv(sqr(nmat)); vector EE(sqr(nmat)); vector EEinv(sqr(nmat)); vector A(sqr(nmat)); vector B(sqr(nmat)); vector EB(sqr(nmat)); vector Ws(sqr(nmat)),Qs(nmat),Xs(nmat),Vs(sqr(nmat)); vector Wp(sqr(nmat)),Qp(nmat),Xp(nmat),Vp(sqr(nmat)); vector Fs(sqr(nnmat)),Fp(sqr(nnmat)); vector indexs(nnmat),indexp(nnmat); vector WXVXs(nnmat); vector WXVXp(nnmat); vector as(2*nmat*nmat),ap(2*nmat*nmat),as_(2*nmat*nmat),ap_(2*nmat*nmat); vector fs(nmat*nmat),gs(nmat*nmat),ss(nmat*nmat),ts(nmat*nmat); vector fp(nmat*nmat),gp(nmat*nmat),sp(nmat*nmat),tp(nmat*nmat); double costhetai = -inckz/k0/nI; for (i=0;iget_levels(); ++layer) { string layerstr = format("(layer = %d)",layer); // // Get the Fourier components for this layer... // message(layerstr + "Creating E matrix"); for (i=-nmat;i<=nmat;++i) { EEE[i+nmat]=conj(grating->fourier(i,layer,0)); EEEE[i+nmat]=conj(grating->fourier(i,layer,1)); } for (i=0;iget_thickness(layer)); } for (i=0;iget_thickness(layer)); } for (i=0;i Gs(nnmat*nnmat),Gp(nnmat*nnmat); for (i=0;i Ts(nnmat,0.); vector Tp(nnmat,0.); for (i=0;i indexs(nnmat),indexp(nnmat); LUdecompose(Gs,nnmat,indexs); LUbacksubstitute(Gs,nnmat,indexs,Ts); LUdecompose(Gp,nnmat,indexp); LUbacksubstitute(Gp,nnmat,indexp,Tp); } message("Finishing"); for (i=-order;i<=order;++i) { j= n+i; r[j].PS() = 0; r[j].PP() = conj(Tp[j+nmat]/nII*nI); r[j].SP() = 0.; r[j].SS() = conj(Ts[j+nmat]); R[j]=MuellerMatrix(r[j])*fabs(real(kIIzi[j])/inckz); } } //*********************************************************************** //** ** //** Conical Reflection ** //** ** //*********************************************************************** void RCW_Model::ConicalReflection() { int i,j,k; int nnmat = 4*nmat; int nmat2 = 2*nmat; int nmat4 = 4*nmat; vector EEE(2*nmat+1),EEEE(2*nmat+1); vector E(sqr(nmat)), Einv(sqr(nmat)); vector EE(sqr(nmat)), EEinv(sqr(nmat)); vector A(sqr(nmat)), Ainv(sqr(nmat)); vector B(sqr(nmat)), Binv(sqr(nmat)); vector Matrix1(sqr(nmat)),Matrix2(sqr(nmat)); vector W1(sqr(nmat)),Q1(nmat),X1(nmat); vector W2(sqr(nmat)),Q2(nmat),X2(nmat); vector V11(sqr(nmat)),V12(sqr(nmat)),V21(sqr(nmat)),V22(sqr(nmat)),v21(sqr(nmat)); vector Vsp(sqr(nmat)),Wsp(sqr(nmat)),Wpp(sqr(nmat)),Vpp(sqr(nmat)), Vss(sqr(nmat)),Wss(sqr(nmat)),Wps(sqr(nmat)),Vps(sqr(nmat)); vector BigMat(sqr(nnmat)),BigMatLU(sqr(nnmat)); vector index(nnmat); vector WXVXl(nnmat),WXVXr(nnmat),WXVXlx(nnmat),WXVXrx(nnmat); vector ab(nmat2*nmat4), fg(nmat2*nmat4); vector Fc(nmat),Fs(nmat); // // Set the initial values for the fg matrix... // for (i=0;iget_levels()-1;layer>=0;--layer) { string layerstr = format("(layer = %d)",layer); double d = grating->get_thickness(layer); // // Get the Fourier components for this layer... // for (i=-nmat;i<=nmat;++i) { EEE[i+nmat]=conj(grating->fourier(i,layer,0)); EEEE[i+nmat]=conj(grating->fourier(i,layer,1)); } for (i=0;i RRs(nnmat,0.); vector RRp(nnmat,0.); double costhetai = -inckz/k0/nI; RRs[ n ] = -1.; RRs[ n+nmat ] = -cI*nI*costhetai; RRp[n+2*nmat] = -cI*nI; RRp[n+3*nmat] = costhetai; message("Solving for fields"); LUbacksubstitute(BigMat,nnmat,index,RRs); LUbacksubstitute(BigMat,nnmat,index,RRp); message("Finishing"); for (i=-order;i<=order;++i) { j= n+i; // Conventions for incident polarizations are handled above. // Conventions for reflected polarizations need factor of -1 for S // and sqrt(-1) for P. Conjugates are needed for conversion to -iwt from iwt. r[j].PS() = conj( -RRp[j] ); r[j].PP() = conj( cI*RRp[j+nmat]/nI ); r[j].SP() = conj( cI*RRs[j+nmat]/nI ); r[j].SS() = conj( -RRs[j] ); R[j]=MuellerMatrix(r[j])*fabs(real(kIzi[j])/inckz); } } //*********************************************************************** //** ** //** Conical Transmission ** //** ** //*********************************************************************** void RCW_Model::ConicalTransmission() { int i,j,k; int nnmat = 4*nmat; int nmat2 = 2*nmat; int nmat4 = 4*nmat; vector EEE(2*nmat+1),EEEE(2*nmat+1); vector E(sqr(nmat)), Einv(sqr(nmat)); vector EE(sqr(nmat)), EEinv(sqr(nmat)); vector A(sqr(nmat)), Ainv(sqr(nmat)); vector B(sqr(nmat)), Binv(sqr(nmat)); vector Matrix1(sqr(nmat)),Matrix2(sqr(nmat)); vector W1(sqr(nmat)),Q1(nmat),X1(nmat); vector W2(sqr(nmat)),Q2(nmat),X2(nmat); vector V11(sqr(nmat)),V12(sqr(nmat)),V21(sqr(nmat)),V22(sqr(nmat)),v21(sqr(nmat)); vector Vsp(sqr(nmat)),Wsp(sqr(nmat)),Wpp(sqr(nmat)),Vpp(sqr(nmat)), Vss(sqr(nmat)),Wss(sqr(nmat)),Wps(sqr(nmat)),Vps(sqr(nmat)); vector BigMat(sqr(nnmat)),BigMat2(sqr(nnmat)); vector index(nnmat); vector WXVX(nnmat); vector ab(nmat4*nmat4), fg(nmat2*nmat4),st(nmat2*nmat4); vector Fc(nmat),Fs(nmat); // // Set the initial values for the fg matrix... // for (i=0;iget_levels();++layer) { string layerstr = format("(layer = %d)",layer); double d = grating->get_thickness(layer); // // Get the Fourier components for this layer... // for (i=-nmat;i<=nmat;++i) { EEE[i+nmat]=conj(grating->fourier(i,layer,0)); EEEE[i+nmat]=conj(grating->fourier(i,layer,1)); } for (i=0;i Ts(nnmat); vector Tp(nnmat); for (i=0;iget_recalc() || BRDF_Model::get_recalc(); } void RCW_BRDF_Model::setup() { BRDF_Model::setup(); RCW_Model RCW; RCW.set_order(order); RCW.set_type(type); RCW.set_oldmethod(oldmethod); RCW.set_lambda(lambda); RCW.set_grating(grating); RCW.set_thetai(thetai/deg); RCW.set_rotation(rotation/deg); if (order<0) error("order < 0"); V.resize(2*order+1); R.resize(2*order+1); for (int i=-order;i<=order;++i) { int j=i+order; V[j]=RCW.GetDirection(i); R[j]=RCW.GetIntensity(i); } last_thetai=thetai; last_rotation=rotation; cosalpha = cos(alpha); Omega = pi*sqr(alpha); //This line is here to force grating::recalc to be 0... grating->fourier(0,0,0); low = RCW.GetMinimumPropagatingOrder(); high = RCW.GetMaximumPropagatingOrder(); } MuellerMatrix RCW_BRDF_Model::mueller() { SETUP(); Vector v = polar(1.,thetas,phis); MuellerMatrix result = MuellerZero(); for (int i=low;i<=high;++i) { if (V[i+order]*v>=cosalpha) { result += R[i+order]/(Omega*v.z); } } return result; } DEFINE_MODEL(RCW_Model,Model,"RCW_Model","Rigorous coupled wave theory for a grating"); DEFINE_PARAMETER(RCW_Model,int,oldmethod,"Use old method for epsilon matrix","0"); DEFINE_PARAMETER(RCW_Model,int,order,"Order of calculation","25"); DEFINE_PARAMETER(RCW_Model,int,type,"Reflection (0) or Transmission (1)","0"); DEFINE_PARAMETER(RCW_Model,double,lambda,"Wavelength (vacuum)","0.532"); DEFINE_PARAMETER(RCW_Model,double,thetai,"Incident angle [deg]","0"); DEFINE_PARAMETER(RCW_Model,double,rotation,"Azimuthal rotation of sample [deg]","0"); DEFINE_PTRPARAMETER(RCW_Model,Grating_Ptr,grating,"Grating","Single_Line_Grating"); DEFINE_MODEL(RCW_BRDF_Model,BRDF_Model,"RCW_BRDF_Model","Rigorous coupled wave theory for a grating, form fitted into a BRDF_Model"); DEFINE_PARAMETER(RCW_BRDF_Model,int,oldmethod,"Use old method for epsilon matrix","0"); DEFINE_PARAMETER(RCW_BRDF_Model,double,alpha,"Half angle of diffraction cone [rad]","0.0175"); DEFINE_PARAMETER(RCW_BRDF_Model,int,order,"Maximum order","25"); DEFINE_PTRPARAMETER(RCW_BRDF_Model,Grating_Ptr,grating,"Grating","Single_Line_Grating"); }