//****************************************************************************** //** SCATMECH: Polarized Light Scattering C++ Class Library //** //** File: bobvlieg1.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 #include #include #include #include "scatmech.h" #include "bobvlieg.h" #include "dielfunc.h" #include "askuser.h" using namespace std; namespace SCATMECH { using namespace BobVlieg_Supp; // The following code implements the theory described in // P.A. Bobbert and J. Vlieger, Physica 137A (1986) 209-242. // Some details of the theory can be found also in // P.A. Bobbert, J. Vlieger, and R. Grief, Physica 137A (1986) 243-257 // These articles will be referred to as B&V and BV&G, respectively. // // // Bmatrix() calculates the Mie scattering matrix found // in Eq. (4.2) of B&V. // COMPLEX Bobbert_Vlieger_BRDF_Model:: Bmatrix(int l_,int m_,int f_,int l,int m,int f) const { COMPLEX result; if (l_!=l || m_!=m || f_!=f) { result = 0.; } else if (d==0) { COMPLEX psi_lntildeq = psi_(l,N2*q); COMPLEX psilntildeq = psi(l,N2*q); COMPLEX psi_lq = psi_(l,q); COMPLEX psilq = psi(l,q); COMPLEX zetalq = zeta(l,q); COMPLEX zeta_lq = zeta_(l,q); if (f==efield) { result = -(N2 * psi_lq*psilntildeq -psilq*psi_lntildeq)/ (N2 * zeta_lq*psilntildeq-zetalq*psi_lntildeq); } else /* if (f==hfield) */ { result = -(N2 * psilq*psi_lntildeq -psi_lq*psilntildeq)/ (N2 * zetalq*psi_lntildeq-zeta_lq*psilntildeq); } } else { // This is from p. 183 of Bohren and Huffman... double x = k*(r-d); double y = k*r; int n = l; COMPLEX m2 = N3; COMPLEX m1 = N2; if (f==efield) { COMPLEX An = (m2*psi(n,m2*x)*psi_(n,m1*x)- m1*psi_(n,m2*x)*psi(n,m1*x))/ (m2*chi(n,m2*x)*psi_(n,m1*x)- m1*chi_(n,m2*x)*psi(n,m1*x)); COMPLEX an = (psi(n,y)*(psi_(n,m2*y)-An*chi_(n,m2*y)) - m2*psi_(n,y)*(psi(n,m2*y)-An*chi(n,m2*y)))/ (zeta(n,y)*(psi_(n,m2*y)-An*chi_(n,m2*y)) - m2*zeta_(n,y)*(psi(n,m2*y)-An*chi(n,m2*y))); result = -an; } else if (f==hfield) { COMPLEX Bn = (m2*psi(n,m1*x)*psi_(n,m2*x)- m1*psi(n,m2*x)*psi_(n,m1*x))/ (m2*chi_(n,m2*x)*psi(n,m1*x)- m1*psi_(n,m1*x)*chi(n,m2*x)); COMPLEX bn = (m2*psi(n,y)*(psi_(n,m2*y)-Bn*chi_(n,m2*y))- psi_(n,y)*(psi(n,m2*y)-Bn*chi(n,m2*y)))/ (m2*zeta(n,y)*(psi_(n,m2*y)-Bn*chi_(n,m2*y))- zeta_(n,y)*(psi(n,m2*y)-Bn*chi(n,m2*y))); result = -bn; } } return result; } // // The complex arccosine is not part of the standard C++ library (!)... // COMPLEX Bobbert_Vlieger_BRDF_Model:: arccosine(const COMPLEX& a) { double x=real(a); double y=imag(a); return pi/2. - arg(sqrt(1. - sqr(x + cI*y)) + cI*(x + cI*y)) + cI*log(abs(sqrt(1. - sqr(x + cI*y)) + cI*(x + cI*y))); } // // Amatrix() calculates the matrix A given by Eq. (8.17) of B&V // void Bobbert_Vlieger_BRDF_Model:: Amatrix(ScatterTMatrix& A) { // Choose number of points in Gaussian integration, depending upon // LMAX, and round up to nearest 10. int npts=((LMAX/10)+1)*10; if (npts>100) npts=100; int ipt = npts/10-1; // Calculate the coefficients in front of the // Legendre polynomials found in Eqs. (8.5a) and (8.5b) of B&V. vector U1(index(LMAX,LMAX)+1); vector U2(index(LMAX,LMAX)+1); vector U3(index(LMAX,LMAX)+1); vector U4(index(LMAX,LMAX)+1); vector V1(index(LMAX,LMAX)+1); vector V2(index(LMAX,LMAX)+1); for (int l=1;l<=LMAX;++l) { for (int m=0;m<=l;++m) { // We don't need negative m values int i=index(l,m); double temp1=(2.*l-1.)*(2.*l+1.); double temp2=(2.*l+3.)*(2.*l+1.); U1[i] = (l-1.)/2.*ipow(-(l-1))*sqrt((l+m-1.)*(l+m)/temp1); U2[i] = (l-1.)/2.*ipow(-(l-1))*sqrt((l-m-1.)*(l-m)/temp1); U3[i] =-(l+2.)/2.*ipow(-(l+1))*sqrt((l-m+1.)*(l-m+2.)/temp2); U4[i] =-(l+2.)/2.*ipow(-(l+1))*sqrt((l+m+1.)*(l+m+2.)/temp2); V1[i] = 0.5*ipow(-(l-1))*sqrt((l-m+1.)*(l+m)); V2[i] =-0.5*ipow(-(l-1))*sqrt((l+m+1.)*(l-m)); } } // Normal incidence reflection coefficients... COMPLEX rsnormal = rs(COMPLEX(1.,0.)); COMPLEX rpnormal = rp(COMPLEX(1.,0.)); vector reflect_s(npts); vector reflect_p(npts); vector > Umatrix(npts,vector(index(LMAX,LMAX)+1)); vector > Vmatrix(npts,vector(index(LMAX,LMAX)+1)); vector > dminusmatrix(npts,vector(index(LMAX,LMAX)+1)); vector > dplusmatrix(npts,vector(index(LMAX,LMAX)+1)); for (int j=0;j N ) J = 1; if ( J == L ) goto Line10; Z = VV(P-1,J-1); VV(P-1,J-1) = VV(L-1,J-1); VV(L-1,J-1) = Z; } while ( abs(Z) == 0. ); // goto Line50; //C ------------------------------ //C |*** ELIMINATE BY COLUMNS ***| //C ------------------------------ if ( K != 0 ) { for (I=1;I<=K;++I) { // DO 60 I = 1,K VV(I-1,J-1) = VV(I-1,J-1) + Z*VV(I-1,L-1); } } VV(L-1,J-1) = Y*Z; if ( M <= N ) { for (I=M;I<=N;++I) { VV(I-1,J-1) = VV(I-1,J-1) + Z*VV(I-1,L-1); } } }; // goto Line50; //C ----------------------- //C |*** PIVOT COLUMNS ***| //C ----------------------- } do { L = W[K-1]; for (I=1;I<=N;++I) { Y = VV(I-1,L-1); VV(I-1,L-1) = VV(I-1,K-1); VV(I-1,K-1) = Y; } K = K - 1; } while ( K > 0 ); return; } if ( abs(VV(0,0)) != 0. ) { VV(0,0) = COMPLEX(1.,0.)/VV(0,0); return; } throw SCATMECH_exception("Matrix has no inverse (2)"); } // // MatrixInvert_by_Series inverts a matrix 1 + X by calculating // the series 1 - X + XX - XXX ... where X is a matrix. // // It is included for pedagogical reasons. One can consider the // order as being the number of interactions included in the // sphere surface interaction. // static void MatrixInvert_by_Series(COMPLEX **a,int n,int order) { vector > temp(n,vector(n)); vector > prev(n,vector(n)); vector diag(n); int i,j,k,q; // Get diagonal elements... for (i=0;iLMAX) BH_LMAX=LMAX; sqrsize = index(LMAX,LMAX,1)+1; lvector.resize(LMAX+1); for (int ll=1;ll<=LMAX;++ll) { lvector[ll]=sqrt((2.*ll+1.)/(ll*(ll+1.))); } message("Allocating Memory"); //Non-temporary-arrays... ScatMatrix.resize(LMAX); ScatMatrixInverse.resize(LMAX); Zp.resize(sqrsize); Zs.resize(sqrsize); eIP.resize(sqrsize); Wp.resize(sqrsize); Ws.resize(sqrsize); Vp.resize(sqrsize); Vs.resize(sqrsize); vector B(sqrsize); // // Calculate A matrix // message("Calculating matrix A"); Amatrix(ScatMatrix); // Calculate the diagonal B matrix... message("Calculating matrix B"); for (l=1;l<=LMAX;++l) { for (f=0;f<=1;++f) { COMPLEX b = Bmatrix(l,0,f,l,0,f); for (m=-l;m<=l;++m) { B[index(l,m,f)]=b; } } } // // Matrix A becomes B^(-1)*(1-B*A)... // message("Calculating matrix (1/B)(1-BA)"); for (m=-LMAX;m<=LMAX;++m) { int beginl = (m==0) ? 1 : abs(m); for (l=beginl;l<=LMAX;++l) { for (f=0;f<=1;++f) { int i = index(l,m,f); for (l_=beginl;l_<=LMAX;++l_) { for (f_=0;f_<=1;++f_) { int i_ = index(l_,m,f_); int mm = LMAX+m; int ll = 2*(LMAX-l)+f; int ll_ = 2*(LMAX-l_)+f_; ScatMatrix[mm][ll_][ll]=((double)(i==i_) - B[i_]*ScatMatrix[mm][ll_][ll]); ScatMatrix[mm][ll_][ll]/=B[i_]; ScatMatrixInverse[mm][ll_][ll]=ScatMatrix[mm][ll_][ll]; } } } } } // // Invert the matrix B^(-1)*(1-B*A) // invert_block_diagonal(ScatMatrix); // Reset previous geometry... old_thetai=-1000; old_thetas=-1000; old_phis=-1000; } // // The following function must be called before any attempt to evaluate // the scattering field. It sets the geometry for the measurement... // void Bobbert_Vlieger_BRDF_Model:: set_geometry(double thetai,double thetas,double phis) { SETUP(); if (thetai<0) { thetai=-thetai; phis = pi+phis; } if (thetas<0) { thetas=-thetas; phis=pi+phis; } if (thetai!=old_thetai) { calculate_W(thetai); old_thetai=thetai; } if (thetas!=old_thetas) { calculate_Z(pi-thetas); old_thetas=thetas; } if (phis!=old_phis) { calculate_eIP(phis); old_phis=phis; } } // The electric field version of the p-->p // differential scattering cross-section... COMPLEX Bobbert_Vlieger_BRDF_Model:: Epp(double thetai,double thetas,double phis) { set_geometry(thetai,thetas,phis); return E(Wp,Zp); } // The electric field version of the p-->s // differential scattering cross-section... COMPLEX Bobbert_Vlieger_BRDF_Model:: Eps(double thetai,double thetas,double phis) { set_geometry(thetai,thetas,phis); return E(Wp,Zs); } // The electric field version of the s-->p // differential scattering cross-section... COMPLEX Bobbert_Vlieger_BRDF_Model:: Esp(double thetai,double thetas,double phis) { set_geometry(thetai,thetas,phis); return E(Ws,Zp); } // The electric field version of the s-->s // differential scattering cross-section... COMPLEX Bobbert_Vlieger_BRDF_Model:: Ess(double thetai,double thetas,double phis) { set_geometry(thetai,thetas,phis); return E(Ws,Zs); } // // Jones matrix differential scattering cross section... // JonesMatrix Bobbert_Vlieger_BRDF_Model:: jonesDSC() { set_geometry(thetai,thetas,phis); COMPLEX pp=E(Wp,Zp); COMPLEX ps=E(Wp,Zs); COMPLEX sp=E(Ws,Zp); COMPLEX ss=E(Ws,Zs); return JonesMatrix(pp,ss,ps,sp); } // // Constructor for class Bobbert_Vlieger_BRDF_Model... // Bobbert_Vlieger_BRDF_Model:: Bobbert_Vlieger_BRDF_Model() { // Initialize parameters ... LMAX=0; // Initialize array addresses to zero ... ScatMatrix=0; ScatMatrixInverse=0; // Initialize old angles ... old_thetai=-1000.; old_thetas=-1000.; old_phis=-1000; } DEFINE_MODEL(Bobbert_Vlieger_BRDF_Model,Local_BRDF_Model, "Bobbert_Vlieger_BRDF_Model", "Theory for scattering by a sphere on a substrate."); DEFINE_PARAMETER(Bobbert_Vlieger_BRDF_Model,dielectric_function,n2,"Particle","(1.59,0)"); DEFINE_PARAMETER(Bobbert_Vlieger_BRDF_Model,double,r,"Radius [um]","0.05"); DEFINE_PARAMETER(Bobbert_Vlieger_BRDF_Model,dielectric_function,n3,"Particle film","(1,0)"); DEFINE_PARAMETER(Bobbert_Vlieger_BRDF_Model,double,d,"Particle film thickness [um]","0"); DEFINE_PARAMETER(Bobbert_Vlieger_BRDF_Model,dielectric_stack,stack,"Substrate films",""); DEFINE_PARAMETER(Bobbert_Vlieger_BRDF_Model,double,delta,"Delta [um] (in contact: 0)","0"); DEFINE_PARAMETER(Bobbert_Vlieger_BRDF_Model,int,lmax,"Maximum l (use Bohren & Huffman estimate: 0)","0"); DEFINE_PARAMETER(Bobbert_Vlieger_BRDF_Model,int,order,"Order (exact: -1)","-1"); DEFINE_PARAMETER(Bobbert_Vlieger_BRDF_Model,int,Norm_Inc_Approx,"Normal Incidence Approximation (exact: 0)","0"); DEFINE_PARAMETER(Bobbert_Vlieger_BRDF_Model,int,improve,"Iterative improvement steps (recommend: 3)","3"); } // namespace SCATMECH