//****************************************************************************** //** SCATMECH: Polarized Light Scattering C++ Class Library //** //** File: axipart1.cpp //** //** Thomas A. Germer //** Sensor Science Division, National Institute of Standards and Technology //** 100 Bureau Dr. Stop 8443; Gaithersburg, MD 20899-8443 //** Phone: (301) 975-2876 //** Email: thomas.germer@nist.gov //** //****************************************************************************** //#include #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)); } // // Bmatrix() calculates the particle's 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); } } } } } } // // 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 = stack->rs12(0.,lambda,vacuum,substrate); COMPLEX rpnormal = stack->rp12(0.,lambda,vacuum,substrate); 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; jWrite("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*k+4.05*pow(qqq*k,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; N0 = COMPLEX(substrate.index(lambda)); N2 = COMPLEX(particle.index(lambda)); ScatterTMatrix BMatrix(LMAX); Bmatrix(BMatrix); N2 = particle.index(lambda); N3 = n3.index(lambda); int m,l,l_,f,f_,l__,f__; 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; 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; // 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; } MuellerMatrix Axisymmetric_Particle_BRDF_Model:: Specular(double theta) { SETUP(); // This function returns the Mueller matrix specular reflectance (for type==0 or // type==2) or the regular transmittance (for type==1 or type==3) for an incident // angle of theta (in radians). The result is derived from the optical theorem // and is only valid when density is suffiently low that multiple scattering // between spheres can be neglected. switch (type) { case 0: { JonesMatrix X = JonesDSC(theta, theta, 0., 0.); JonesMatrix r = stack->r12(theta, lambda, vacuum, substrate); r *= exp(2. * cI * qq * cos(theta)); MuellerMatrix sigma = (4. * pi / k) * ReCrossMueller(X, r); return MuellerMatrix(r) - sigma * (density / cos(theta)); } break; case 1: { double index = substrate.n(lambda); double sint = sin(theta) / index; if (sint >= 1. || substrate.k(lambda) != 0) return MuellerZero(); double thetat = asin(sint); JonesMatrix X = JonesDSC(theta, thetat, 0., 0.); COMPLEX phase = exp(cI * qq * (cos(theta) - index * cos(thetat))); //double factor = cos(thetat)/cos(theta); JonesMatrix t = stack->t12(theta, lambda, vacuum, substrate); t *= phase; MuellerMatrix sigma = (4. * pi / k / sqrt(index)) * ReCrossMueller(X, t); return MuellerMatrix(t) * (cos(thetat) / cos(theta) * index) - sigma * (density / cos(theta)); } break; case 2: { double index = substrate.n(lambda); JonesMatrix X = JonesDSC(theta, theta, 0., 0.); JonesMatrix r = stack->r21i(theta, lambda, substrate, vacuum); r *= exp(-2. * cI * index * qq * cos(theta)); MuellerMatrix sigma = (4. * pi / k / index) * ReCrossMueller(X, r); return MuellerMatrix(r) - sigma * (density / cos(theta)); } break; case 3: { double index = substrate.n(lambda); double sint = sin(theta) * index; COMPLEX cost = sqrt(1. - sqr(sint)); if (imag(cost) < 0) cost = -cost; if (sint >= 1.) return MuellerZero(); double thetat = asin(sint); JonesMatrix X = JonesDSC(theta, thetat, 0., 0.); COMPLEX phase = exp(cI * qq * (cost - index * cos(theta))); //double factor = cos(thetat)/cos(theta); JonesMatrix t = stack->t21i(theta, lambda, substrate, vacuum); t *= phase; MuellerMatrix sigma = (4. * pi / k / sqrt(index)) * ReCrossMueller(X, t); return MuellerMatrix(t) * (cos(theta) / index / cos(thetat)) - sigma * (density / cos(theta)); } break; default: error("Invalid type = " + to_string(type)); } return MuellerZero(); } DEFINE_MODEL(Axisymmetric_Particle_BRDF_Model,Local_BRDF_Model, "Axisymmetric particle on a substrate."); DEFINE_PTRPARAMETER(Axisymmetric_Particle_BRDF_Model, Axisymmetric_Shape_Ptr, Shape, "Particle Shape", "Ellipsoid_Axisymmetric_Shape",0xFF); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,dielectric_function,particle,"Particle optical properties","(1.59,0)",0xFF); DEFINE_PTRPARAMETER(Axisymmetric_Particle_BRDF_Model,StackModel_Ptr,stack,"Substrate films","No_StackModel",0xFF); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,double,delta,"Separation of particle from substrate [um] (in contact: 0)","0",0xFF); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,int,lmax,"Maximum polar order (lmax)","0",0xFF); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,int,mmax,"Maximum azimuthal order (mmax)","0",0xFF); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,int,order,"Perturbation order (exact: -1)","-1",0xFF); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,int,Norm_Inc_Approx,"Normal incidence approximation (exact: 0)","0",0xFF); DEFINE_PARAMETER(Axisymmetric_Particle_BRDF_Model,int,improve,"Iterative improvement steps (recommend: 3)","3",0xFF); } // namespace SCATMECH