//****************************************************************************** //** SCATMECH: Polarized Light Scattering C++ Class Library //** //** File: crossgrating.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 "crossgrating.h" #include "crossgrating2.h" #include "gcross.h" #include "matrixmath.h" #include "scatmech.h" #include "fft.h" #include "bobvlieg.h" #include using namespace std; namespace SCATMECH { namespace { void print(CFARRAY a, int n1, int n2, ostream& os,int option=0) { a.array(n1,n2); for (int i=1; i<=n1; ++i) { for (int j=1; j<=n2; ++j) { if (option==0) os << abs(a(i,j)); else if (option==1) os << real(a(i,j)); else if (option==2) os << imag(a(i,j)); if (j!=n2) os << tab; } os << endl; } } } void CrossGrating::setup() { Model::setup(); } void Gridded_CrossGrating::FourierFactorize() { if (isotropic) { FourierFactorize(eps, eps, eps, EPS0, EPS11, EPS12, EPS2, EPS3); } else { FourierFactorize(eps1, eps2, eps3, EPS0, EPS11, EPS12, EPS2, EPS3); } if (nonmagnetic) { int M1 = 2 * order1 + 1; int M2 = 2 * order2 + 1; MU0.allocate(M1, M2, M1, M2, levels); MU11.allocate(M1, M2, M1, M2, levels); MU12.allocate(M1, M2, M1, M2, levels); MU2.allocate(M1, M2, M1, M2, levels); MU3.allocate(M1, M2, M1, M2, levels); for (int level = 1;level <= levels;++level) { for (int i = 1; i <= M1; ++i) { for (int j = 1; j <= M2; ++j) { for (int k = 1; k <= M1; ++k) { for (int l = 1; l <= M2; ++l) { if (i == k&&j == l) { MU0(i, j, k, l, level) = MU11(i, j, k, l, level) = MU12(i, j, k, l, level) = MU2(i, j, k, l, level) = MU3(i, j, k, l, level) = 1.; } else { MU0(i, j, k, l, level) = MU11(i, j, k, l, level) = MU12(i, j, k, l, level) = MU2(i, j, k, l, level) = MU3(i, j, k, l, level) = 0.; } } } } } } } else { if (isotropic) { FourierFactorize(mu, mu, mu, MU0, MU11, MU12, MU2, MU3); } else { FourierFactorize(mu1, mu2, mu3, MU0, MU11, MU12, MU2, MU3); } } } void Gridded_CrossGrating::FourierFactorize(CFARRAY& eps1, CFARRAY& eps2, CFARRAY& eps3,CFARRAY& _EPS0,CFARRAY& _EPS11,CFARRAY& _EPS12,CFARRAY& _EPS2, CFARRAY& _EPS3) { using BobVlieg_Supp::mpow; CrossGrating::zeta = Gridded_CrossGrating::zeta; CrossGrating::d1 = Gridded_CrossGrating::d1; CrossGrating::d2 = Gridded_CrossGrating::d2; int i,j,k,l; int level; int M1 = 2*order1+1; int M2 = 2*order2+1; int M1a = 4*order1+1; int M2a = 4*order2+1; int MM = M1*M2; int N1 = grid1; int N2 = grid2; _EPS0.allocate(M1,M2,M1,M2,levels); _EPS11.allocate(M1,M2,M1,M2,levels); _EPS12.allocate(M1,M2,M1,M2, levels); _EPS2.allocate(M1,M2,M1,M2,levels); _EPS3.allocate(M1,M2,M1,M2,levels); CFARRAY epsFT0(M1a,M2a); CFARRAY epsFT11(M1a,M2a); CFARRAY epsFT12(M1a,M2a); CFARRAY epsFT2(M1,M1,M2a); CFARRAY epsFT3(M2,M2,M1a); CFARRAY epsFT0a(M1a,N2); CFARRAY epsFT11a(M1a,N2); CFARRAY epsFT12a(M1a,N2); CFARRAY epsFT2a(M1a,N2); CFARRAY epsFT3a(M2a,N1); CFARRAY epsFT2b(M1,M1,N2); CFARRAY epsFT3b(M2,M2,N1); CFARRAY matrix1(M1,M1); CFARRAY matrix2(M2,M2); CFARRAY matrix3(M1,M2,M1,M2); CFARRAY tempN1(N1,1); CFARRAY tempN2(N2,1); // // Create FTs ... // // For each level in the stack... for (level=1; level<=levels; ++level) { // Start with FT'ing along 1st dimension... for (j = 1; j <= N2; ++j) { for (i = 1; i <= N1; ++i) tempN1(i) = eps3(i, j, level); // This is eps3 fft1d(tempN1, N1, -1); for (i = 1; i <= M1a; ++i) epsFT0a(i, j) = tempN1((i - M1 + N1) % N1 + 1) / (double)N1; for (i = 1; i <= N1; ++i) tempN1(i) = 1. / eps1(i, j, level); // This is eps1 fft1d(tempN1, N1, -1); for (i = 1; i <= M1a; ++i) { epsFT11a(i, j) = tempN1((i - M1 + N1) % N1 + 1) / (double)N1; epsFT2a(i, j) = tempN1((i - M1 + N1) % N1 + 1) / (double)N1; } if (isotropic) { for (i = 1; i <= M1a; ++i) { epsFT12a(i, j) = epsFT12a(i, j); } } else { for (i = 1; i <= N1; ++i) tempN1(i) = 1. / eps2(i, j, level); // This is eps2 fft1d(tempN1, N1, -1); for (i = 1; i <= M1a; ++i) { epsFT12a(i, j) = tempN1((i - M1 + N1) % N1 + 1) / (double)N1; } } } // First FT for type 3 is along x2 direction... for (j=1; j<=N1; ++j) { for (i=1; i<=N2; ++i) tempN2(i) = 1./eps2(j,i,level); // This is eps2 fft1d(tempN2,N2,-1); for (i=1; i<=M2a; ++i) epsFT3a(i,j) = tempN2((i-M2+N2)%N2+1)/(double)N2; } // For types 0 and 1, finish the FT along the other dimension... for (i=1; i<=M1a; ++i) { for (j=1; j<=N2; ++j) tempN2(j) = epsFT0a(i,j); fft1d(tempN2,N2,-1); for (j=1; j<=M2a; ++j) epsFT0(i,j) = tempN2((j-M2+N2)%N2+1)/(double)N2; for (j=1; j<=N2; ++j) tempN2(j) = epsFT11a(i,j); fft1d(tempN2,N2,-1); for (j = 1; j <= M2a; ++j) { epsFT11(i, j) = tempN2((j - M2 + N2) % N2 + 1) / (double)N2; } if (isotropic) { for (j = 1; j <= M2a; ++j) { epsFT12(i, j) = epsFT11(i, j); } } else { for (j = 1; j <= N2; ++j) tempN2(j) = epsFT12a(i, j); fft1d(tempN2, N2, -1); for (j = 1; j <= M2a; ++j) { epsFT12(i, j) = tempN2((j - M2 + N2) % N2 + 1) / (double)N2; } } } // Invert the partial 1/e matrices for type 2 ... for (i=1; i<=N2; ++i) { for (j=1; j<=M1; ++j) { for (k=1; k<=M1; ++k) { matrix1(j,k) = epsFT2a(j-k+2*order1+1,i); } } Inverse(matrix1,M1); for (j=1; j<=M1; ++j) { for (k=1; k<=M1; ++k) { epsFT2b(j,k,i) = matrix1(j,k); } } } // Invert the partial 1/e matrices for type 3 ... for (i=1; i<=N1; ++i) { for (j=1; j<=M2; ++j) { for (k=1; k<=M2; ++k) { matrix2(j,k) = epsFT3a(j-k+2*order2+1,i); } } Inverse(matrix2,M2); for (j=1; j<=M2; ++j) { for (k=1; k<=M2; ++k) { epsFT3b(j,k,i) = matrix2(j,k); } } } // Then finish FT'ing the type 2 matrices by integrating along x2 direction... for (i=1; i<=M1; ++i) { for (j=1; j<=M1; ++j) { for (l=1; l<=N2; ++l) tempN2(l) = epsFT2b(i,j,l); fft1d(tempN2,N2,-1); for (l=1; l<=M2a; ++l) epsFT2(i,j,l) = tempN2((l-M2+N2)%N2+1)/(double)N2; } } // Then finish FT'ing the type 3 matrices by integrating along x1 direction... for (i=1; i<=M2; ++i) { for (j=1; j<=M2; ++j) { for (l=1; l<=N1; ++l) tempN1(l) = epsFT3b(i,j,l); fft1d(tempN1,N1,-1); for (l=1; l<=M1a; ++l) epsFT3(i,j,l) = tempN1((l-M1+N1)%N1+1)/(double)N1; } } for (i=1; i<=M1; ++i) { for (j=1; j<=M2; ++j) { for (k=1; k<=M1; ++k) { for (l=1; l<=M2; ++l) { _EPS2(i,j,k,l,level) = epsFT2(i,k,j-l+2*order2+1); _EPS3(i,j,k,l,level) = epsFT3(j,l,i-k+2*order1+1); } } } } for (i=1; i<=M1; ++i) { for (j=1; j<=M2; ++j) { for (k=1; k<=M1; ++k) { for (l=1; l<=M2; ++l) { matrix3(i,j,k,l) = epsFT0(i-k+2*order1+1,j-l+2*order2+1); } } } } Inverse(matrix3,MM); for (i=1; i<=M1; ++i) { for (j=1; j<=M2; ++j) { for (k=1; k<=M1; ++k) { for (l=1; l<=M2; ++l) { _EPS0(i,j,k,l,level) = matrix3(i,j,k,l); } } } } for (i=1; i<=M1; ++i) { for (j=1; j<=M2; ++j) { for (k=1; k<=M1; ++k) { for (l=1; l<=M2; ++l) { matrix3(i,j,k,l) = epsFT11(i-k+2*order1+1,j-l+2*order2+1); } } } } Inverse(matrix3,MM); for (i=1; i<=M1; ++i) { for (j=1; j<=M2; ++j) { for (k=1; k<=M1; ++k) { for (l=1; l<=M2; ++l) { _EPS11(i, j, k, l, level) = matrix3(i,j,k,l); } } } } if (isotropic) { for (i = 1; i <= M1; ++i) { for (j = 1; j <= M2; ++j) { for (k = 1; k <= M1; ++k) { for (l = 1; l <= M2; ++l) { _EPS12(i, j, k, l, level) = matrix3(i, j, k, l); } } } } } else { for (i = 1; i <= M1; ++i) { for (j = 1; j <= M2; ++j) { for (k = 1; k <= M1; ++k) { for (l = 1; l <= M2; ++l) { matrix3(i, j, k, l) = epsFT12(i - k + 2 * order1 + 1, j - l + 2 * order2 + 1); } } } } Inverse(matrix3, MM); for (i = 1; i <= M1; ++i) { for (j = 1; j <= M2; ++j) { for (k = 1; k <= M1; ++k) { for (l = 1; l <= M2; ++l) { _EPS12(i, j, k, l, level) = matrix3(i, j, k, l); } } } } } } } void CrossGrating::set_parameter_base( const STRING& parameter, ///< The parameter name const STRING& value ///< String represention of a value ) { if (parameter=="lambda") { lambda = from_string(value); set_recalc(0xFF); } else if (parameter=="order1") { order1 = from_string(value); set_recalc(0xFF); } else if (parameter=="order2") { order2 = from_string(value); set_recalc(0xFF); } else if (parameter=="SaveGratingE0") { SETUP(); int M1 = 2*order1+1; int M2 = 2*order2+1; ofstream image(value.c_str()); if (!image) error("Cannot open file: " + value); for (int level=1; level<=levels; ++level) { print(EPS0(1,1,1,1,level),M1*M2,M1*M2,image); image << endl; } set_recalc(0); } else if (parameter == "SaveGratingE11") { SETUP(); int M1 = 2 * order1 + 1; int M2 = 2 * order2 + 1; ofstream image(value.c_str()); if (!image) error("Cannot open file: " + value); for (int level = 1; level <= levels; ++level) { print(EPS11(1, 1, 1, 1, level), M1*M2, M1*M2, image); image << endl; } set_recalc(0); } else if (parameter == "SaveGratingE12") { SETUP(); int M1 = 2 * order1 + 1; int M2 = 2 * order2 + 1; ofstream image(value.c_str()); if (!image) error("Cannot open file: " + value); for (int level = 1; level <= levels; ++level) { print(EPS12(1, 1, 1, 1, level), M1*M2, M1*M2, image); image << endl; } set_recalc(0); } else if (parameter=="SaveGratingE2") { SETUP(); int M1 = 2*order1+1; int M2 = 2*order2+1; ofstream image(value.c_str()); if (!image) error("Cannot open file: " + value); for (int level=1; level<=levels; ++level) { print(EPS2(1,1,1,1,level),M1*M2,M1*M2,image); image << endl; } set_recalc(0); } else if (parameter=="SaveGratingE3") { SETUP(); int M1 = 2*order1+1; int M2 = 2*order2+1; ofstream image(value.c_str()); if (!image) error("Cannot open file: " + value); for (int level=1; level<=levels; ++level) { print(EPS3(1,1,1,1,level),M1*M2,M1*M2,image); image << endl; } set_recalc(0); } else if (parameter=="SaveLevelThickness") { SETUP(); ofstream file(value.c_str()); if (!file) error("Cannot open file: " + value); for (int level=1; level<=levels; ++level) { file << level << tab << thick(level) << endl; } } else { Model::set_parameter_base(parameter,value); } } void Gridded_CrossGrating::set_parameter_base( const STRING& parameter, ///< The parameter name const STRING& value ///< String represention of a value ) { if (parameter=="SaveGratingImage") { SETUP(); ofstream image(value.c_str()); if (!image) error("Cannot open file: " + value); for (int level=1; level<=levels; ++level) { print(eps(1,1,level),grid1,grid2,image); image << endl; } set_recalc(0); } else if (parameter=="SaveGratingImageReal") { SETUP(); ofstream image(value.c_str()); if (!image) error("Cannot open file: " + value); for (int level=1; level<=levels; ++level) { print(eps(1,1,level),grid1,grid2,image,1); image << endl; } set_recalc(0); } else if (parameter=="SaveGratingImageImag") { SETUP(); ofstream image(value.c_str()); if (!image) error("Cannot open file: " + value); for (int level=1; level<=levels; ++level) { print(eps(1,1,level),grid1,grid2,image,2); image << endl; } set_recalc(0); } else { CrossGrating::set_parameter_base(parameter,value); } } void Gridded_CrossGrating::getxy(int i,int j,double &x, double &y) { double x1 = (i-0.5-grid1/2.)/grid1*d1; double x2 = (j-0.5-grid2/2.)/grid2*d2; x = x1 + x2*sinzeta; y = x2*coszeta; } void Register(const CrossGrating* x) { static bool regd=false; if (!regd) { regd=true; Register_Model(CrossGrating); Register_Model(OneD_CrossGrating); Register_Model(Overlaid_CrossGrating); Register_Model(Overlaid_1D_CrossGrating); Register_Model(Null_CrossGrating); Register_Model(Gridded_CrossGrating); Register_Model(Cylinder_CrossGrating); Register_Model(Rectangle_CrossGrating); Register_Model(Sphere_CrossGrating); Register_Model(Pyramidal_Pit_CrossGrating); Register_Model(Generic_CrossGrating); } } DEFINE_VIRTUAL_MODEL(CrossGrating,Model,"Generalized cross grating"); DEFINE_PARAMETER(CrossGrating,dielectric_function,medium_i,"Incident medium","(1,0)",0xFF); DEFINE_PARAMETER(CrossGrating,dielectric_function,medium_t,"Transmitted medium","(4.05,0.05)",0xFF); DEFINE_VIRTUAL_MODEL(Gridded_CrossGrating,CrossGrating,"Cross grating defined on a discrete grid"); DEFINE_PARAMETER(Gridded_CrossGrating,double,zeta,"Angle of lattice vectors from perpendicular [deg]","0.",0xFF); DEFINE_PARAMETER(Gridded_CrossGrating,double,d1,"Lattice constant #1 [um]","0.5",0xFF); DEFINE_PARAMETER(Gridded_CrossGrating,double,d2,"Lattice constant #2 [um]","0.5",0xFF); DEFINE_PARAMETER(Gridded_CrossGrating,int,grid1,"Number of sampling points in direction #1","1024",0xFF); DEFINE_PARAMETER(Gridded_CrossGrating,int,grid2,"Number of sampling points in direction #2","1024",0xFF); }