//****************************************************************************** //** 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 "scatmech.h" #include "bobvlieg.h" #include "axipart.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. // static complex cfI(0.,1.); static COMPLEX D(int n,int m,int f) { int mm = (m==0 ? 1 : 2); double d = mm*(2*n+1)*Fact(n-abs(m))/(4*n*(n+1)*Fact(n+abs(m))); double e = sqrt((2*n+1)*Fact(n-abs(m))/Fact(n+abs(m))); COMPLEX ff = (f==0) ? 1. : -1.; return 1./(ff*(double)(e/d)); } int Axisymmetric_Particle_BRDF_Model:: get_recalc() { return Local_BRDF_Model::get_recalc()||Shape->get_recalc(); } // // Bmatrix() calculates the Mie scattering matrix found // in Eq. (4.2) of B&V. // void Axisymmetric_Particle_BRDF_Model:: Bmatrix(ScatterTMatrix& T) { //float xdummy; //long ldummy; complex dummy; int m; for (m=-MMAX;m<=MMAX;++m) { int mm = LMAX+m; int beginl = (m==0) ? 1 : abs(m); for (int l=beginl;l<=LMAX;++l) { for (int f=0;f<=1;++f) { int i = index(l,m,f); int ll = 2*(LMAX-l)+f; for (int l_=beginl;l_<=LMAX;++l_) { for (int f_=0;f_<=1;++f_) { int i_ = index(l_,m,f_); int ll_ = 2*(LMAX-l_)+f_; T[mm][ll_][ll]=0; } } } } } Shape->Get_TMatrix(T, LMAX, MMAX, k, N2); for (m=-MMAX;m<=MMAX;++m) { int mm = LMAX+m; int beginl = (m==0) ? 1 : abs(m); for (int l=beginl;l<=LMAX;++l) { for (int f=0;f<=1;++f) { int ll = 2*(LMAX-l)+f; for (int l_=beginl;l_<=LMAX;++l_) { for (int f_=0;f_<=1;++f_) { int ll_ = 2*(LMAX-l_)+f_; T[mm][ll_][ll]=T[mm][ll_][ll]*D(l_,m,f_)/D(l,m,f); } } } } } } // // The complex arccosine is not part of the standard C++ library (!)... // static COMPLEX 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 Axisymmetric_Particle_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)"); } // // Matrix 1-BA in Eq. 5.3 of B&V is block diagonal. // The following routine inverts that matrix. // void Axisymmetric_Particle_BRDF_Model:: invert_block_diagonal(ScatterTMatrix& AA) { int m; for (m=-MMAX;m<=MMAX;++m) { ostringstream msg; msg << "Inverting matrix (m = " << m << ") " << ret; message(msg.str()); int n= 2*((m==0) ? LMAX : LMAX-abs(m)+1); cvert(AA[LMAX+m],n); } message("Done Inverting Matrices"); } // // setup() is called whenever the model needs to be "recalculated" // void Axisymmetric_Particle_BRDF_Model:: setup() { Local_BRDF_Model::setup(); Shape->Write("shape.dat"); double length = Shape->Get_Base_Length(); ostringstream msg; msg << "Distance of origin from surface: " << length << endl; message(msg.str()); k = 2.0*pi/lambda; double q = k * length; qq = q+k*delta; double qqq = Shape->Get_MaxRadius(); // Bohren and Huffman recommended lmax... BH_LMAX = (int)(qqq+4.05*pow(qqq,0.3333)+2.); if (lmax==0) LMAX = BH_LMAX; if (lmax>0) LMAX = lmax; if (lmax<0) LMAX = BH_LMAX+abs(lmax); if (mmax==0) MMAX = LMAX; if (mmax>0) MMAX = mmax; if (mmax<0) MMAX = LMAX+abs(mmax); if (MMAX>LMAX) MMAX = LMAX; tau = k*t; N0 = COMPLEX(substrate.index(lambda)); N2 = COMPLEX(n2.index(lambda)); ScatterTMatrix BMatrix(LMAX); Bmatrix(BMatrix); N1 = n1.index(lambda); N2 = n2.index(lambda); N3 = n3.index(lambda); int m,l,l_,f,f_,l__,f__; if (type==TRANSMISSION) error("No code for TRANSMISSION mode"); if (delta<0.) error("delta cannot be less than zero."); // The Bohren and Huffman recommended LMAX... // BH_LMAX = (int)(q+4.*pow(q,0.3333)+2.); 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 or read it from file and // write it to a file... // if (order!=0) { int retvalue=1; old_LMAX=0; if (old_LMAXp // differential scattering cross-section... COMPLEX Axisymmetric_Particle_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 Axisymmetric_Particle_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 Axisymmetric_Particle_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 Axisymmetric_Particle_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 Axisymmetric_Particle_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 Axisymmetric_Particle_BRDF_Model... // Axisymmetric_Particle_BRDF_Model:: Axisymmetric_Particle_BRDF_Model() { n3=vacuum_function; // Initialize array addresses to zero ... ScatMatrix=0; ScatMatrixInverse=0; // Initialize old angles ... old_thetai=-1000.; old_thetas=-1000.; old_phis=-1000; LMAX = 0; MMAX = 0; } DEFINE_MODEL(Axisymmetric_Particle_BRDF_Model,Local_BRDF_Model, "Axisymmetric_Particle_BRDF_Model", "Axisymmetric particle on a substrate."); DEFINE_PTRPARAMETER(Axisymmetric_Particle_BRDF_Model, Axisymmetric_Shape_Ptr, Shape, "Particle Shape", "Ellipsoid_Axisymmetric_Shape"); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,dielectric_function,n2,"Particle","(1.46,0)"); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,dielectric_function,n1,"Substrate Film","(1.59,0)"); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,double,t,"Film thickness [um]","0"); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,double,delta,"Particle-substrate separation [um]","0"); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,int,lmax,"Maximum polar order (LMAX)","0"); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,int,mmax,"Maximum azimuthal order (mmax)","0"); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,int,order,"Surface interaction order (-1=exact)","-1"); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,int,Norm_Inc_Approx,"Normal incidence approximation","0"); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,int,improve,"Iterative improvement steps","0"); } // namespace SCATMECH