Skip to content

Commit a334ba6

Browse files
committed
First step towards DDA with particles above surface. Currently, mostly infrastructure parts have been handled. The only limitation of the scattering problem is that the particle is located fully above the surface and the upper medium is vacuum (the lower has any complex refractive index). Also, -orient, non-plane waves, -init_field wkb, and radiation forces are currently incompatible with surface.
Implemented: - command line options '-surf ...', '-int_surf ...' and -scat_plane. The latter defines that the scattering should be calculate in the scattering plane, which passes through prop and ez (in laboratory frame). Two difference from the default behavior (-yz): for default prop, it is the xz-plane, and for non-default prop, the angle is counted from ez, not from prop. - new definitions of scattered angle as -scat_plane for default calculation, and with respect to the laboratory (surface) reference frame for scat_grid and alldir. Such new definitions are now used only for surface, but may become universal ones in the future (issue 170). - incident beam due to surface both for propagation from above and from below surface, including evanescent fields and other complex waves. Still to do: - Calculation of scattered fields in the presence of surface (simple reflection and transmission). - Actually plugging in the surface-interaction Green's tensor, both rigorous (Sommerfeld integrals) and approximate (image dipole) ones - FFT acceleration of surface mode Also done: - A few macros were implemented to specify all components of a real or complex vector (or both real and imaginary parts of the complex number) at once in printf-family arguments. - Special test mode was added to tests/2exec to test new version with trivial surface (of refractive index 1) against the standard implementation. Also added a combination of -orient -prop, and -scat_matr both to all tests. Improved handling of diffs in IncBeam files. - Several functions have been added to cmplx.h. In particular, s few memcpy calls were replaced by vCopy. - Handling of scattering directions based on angles theta and phi (alldir and scat_grid) was localized to a separate function SetScatPlane in crosssec.c. Currently, it contains rather complicated logic to handle differences with surface and all special cases. The following tests were performed: - In the default mode no changes with the previous version - tested by tests/2exec (including the new surf_standard test mode, where applicable) - Use of -scat_plane is equivalent to -store_scat_grid with (phi: type=values, values=90) - The above equivalence also holds for non-trivial -prop with corresponding shift of theta range. For example, -prop 1 0 1 can be compensated by (theta: min=-45, max=315, and double value of N) in scat_params.dat - When using non-trivial prop with alldir and trivial -surf (like '-surf 1 0 10'), Csca is the same, while g and Csca.g are rotated from beam RF to laboratory RF. - When using the non-trivial surface the calculation of incident field was tested (both by -store_beam and by comparing calculated Cext, which is supposed to scale accordingly, since other effects of surface are not yet implemented).
1 parent 653fbf5 commit a334ba6

File tree

20 files changed

+1064
-160
lines changed

20 files changed

+1064
-160
lines changed

src/CalculateE.c

Lines changed: 168 additions & 50 deletions
Large diffs are not rendered by default.

src/GenerateB.c

Lines changed: 104 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,22 @@ extern opt_index opt_beam;
4747

4848
// used in crosssec.c
4949
double beam_center_0[3]; // position of the beam center in laboratory reference frame
50+
/* complex wave amplitudes of secondary waves (with phase relative to particle center);
51+
* they satisfy (e,e)=e_x^2+e_y^2+e_z^2=1, which doesn't necessarily means that (e,e*)=||e||^2=|e_x|^2+|e_y|^2+|e_z|^2=1
52+
* the latter condition may be broken for eIncTran of inhomogeneous wave (when msub is complex). In that case
53+
* for E=E0*e, ||E||!=|E0| (which is counterintuitive)
54+
*
55+
* !!! TODO: determine whether they are actually needed in crosssec.c, or make them static here
56+
*/
57+
doublecomplex eIncRefl[3],eIncTran[3];
5058
// used in param.c
5159
char beam_descr[MAX_MESSAGE2]; // string for log file with beam parameters
5260

5361
// LOCAL VARIABLES
5462
static double s,s2; // beam confinement factor and its square
5563
static double scale_x,scale_z; // multipliers for scaling coordinates
64+
static doublecomplex ki,kt; // abs of normal components of k_inc/k0, and ktran/k0
65+
static doublecomplex ktVec[3]; // k_tran/k0, abs of its normal component
5666
/* TO ADD NEW BEAM
5767
* Add here all internal variables (beam parameters), which you initialize in InitBeam() and use in GenerateB()
5868
* afterwards. If you need local, intermediate variables, put them into the beginning of the corresponding function.
@@ -76,16 +86,45 @@ void InitBeam(void)
7686
case B_PLANE:
7787
if (IFROOT) strcpy(beam_descr,"plane wave");
7888
beam_asym=false;
89+
if (surface) {
90+
// Here we set ki,kt,ktVec and propagation directions prIncRefl,prIncTran
91+
doublecomplex q2; // square of relative component of k_inc/k0 along the surface
92+
if (prop_0[2]>0) { // beam comes from the substrate (below)
93+
ki=msub*prop_0[2];
94+
q2=msub*msub-ki*ki;
95+
kt=cSqrtCut(1-q2);
96+
// determine propagation direction and full wavevector of wave transmitted into substrate
97+
ktVec[0]=msub*prop_0[0];
98+
ktVec[1]=msub*prop_0[1];
99+
ktVec[2]=kt;
100+
}
101+
else if (prop_0[2]<0) { // beam comes from above the substrate
102+
vRefl(prop_0,prIncRefl);
103+
ki=-prop_0[2];
104+
q2=1-ki*ki;
105+
kt=cSqrtCut(msub*msub-q2);
106+
// determine propagation direction of wave transmitted into substrate
107+
ktVec[0]=prop_0[0];
108+
ktVec[1]=prop_0[1];
109+
ktVec[2]=-kt;
110+
}
111+
else LogError(ONE_POS,"Ambiguous setting of beam propagating along the surface. Please specify the"
112+
"incident direction to have (arbitrary) small positive or negative z-component");
113+
vRefl(prop_0,prIncRefl);
114+
vReal(ktVec,prIncTran);
115+
vNormalize(prIncTran);
116+
}
79117
return;
80118
case B_LMINUS:
81119
case B_DAVIS3:
82120
case B_BARTON5:
121+
if (surface) PrintErrorHelp("Currently, Gaussian incident beam is not supported for '-surf'");
83122
// initialize parameters
84123
w0=beam_pars[0];
85124
TestPositive(w0,"beam width");
86125
beam_asym=(beam_Npars==4 && (beam_pars[1]!=0 || beam_pars[2]!=0 || beam_pars[3]!=0));
87126
if (beam_asym) {
88-
memcpy(beam_center_0,beam_pars+1,3*sizeof(double));
127+
vCopy(beam_pars+1,beam_center_0);
89128
// if necessary break the symmetry of the problem
90129
if (beam_center_0[0]!=0) symX=symR=false;
91130
if (beam_center_0[1]!=0) symY=symR=false;
@@ -112,8 +151,8 @@ void InitBeam(void)
112151
default: break;
113152
}
114153
sprintf(beam_descr+strlen(beam_descr),"\tWidth="GFORMDEF" (confinement factor s="GFORMDEF")\n",w0,s);
115-
if (beam_asym) sprintf(beam_descr+strlen(beam_descr),"\tCenter position: "GFORMDEF3V,beam_center_0[0],
116-
beam_center_0[1],beam_center_0[2]);
154+
if (beam_asym)
155+
sprintf(beam_descr+strlen(beam_descr),"\tCenter position: "GFORMDEF3V,COMP3V(beam_center_0));
117156
else strcat(beam_descr,"\tCenter is in the origin");
118157
}
119158
return;
@@ -177,12 +216,71 @@ void GenerateB (const enum incpol which, // x - or y polarized incident light
177216
}
178217
else { // which==INCPOL_X
179218
ex=incPolX;
180-
memcpy(ey,incPolY,3*sizeof(double));
219+
vCopy(incPolY,ey);
181220
}
182221

183222
switch (beamtype) {
184-
case B_PLANE: // plane is separate to be fast
185-
for (i=0;i<local_nvoid_Ndip;i++) {
223+
case B_PLANE: // plane is separate to be fast (for non-surface)
224+
if (surface) {
225+
/* With respect to normalization we use here the same assumption as in the free space - the origin is in
226+
* the particle center, and beam irradiance is equal to that of a unity-amplitude field in the vacuum
227+
* (i.e. 1/8pi in CGS). Thus, original incident beam propagating from the vacuum (above) is
228+
* Exp(i*k*r.a), while - from the substrate (below) is Exp(i*k*msub*r.a)/sqrt(Re(msub)). We assume that
229+
* the incident beam is homogeneous in its original medium.
230+
*/
231+
doublecomplex rc,tc; // reflection and transmission coefficients
232+
if (prop[2]>0) { // beam comes from the substrate (below)
233+
// determine amplitude of the reflected and transmitted waves
234+
if (which==INCPOL_Y) { // s-polarized
235+
cvBuildRe(ex,eIncRefl);
236+
cvBuildRe(ex,eIncTran);
237+
rc=FresnelRS(ki,kt);
238+
tc=FresnelTS(ki,kt);
239+
}
240+
else { // p-polarized
241+
vInvRefl_cr(ex,eIncRefl);
242+
crCrossProd(ey,ktVec,eIncTran);
243+
rc=FresnelRP(ki,kt,1/msub);
244+
tc=FresnelTP(ki,kt,1/msub);
245+
}
246+
// phase shift due to the origin at height hsub
247+
cvMultScal_cmplx(rc*cexp(-2*I*WaveNum*ki*hsub)/sqrt(creal(msub)),eIncRefl,eIncRefl);
248+
cvMultScal_cmplx(tc*cexp(I*WaveNum*(kt-ki)*hsub)/sqrt(creal(msub)),eIncTran,eIncTran);
249+
// main part
250+
for (i=0;i<local_nvoid_Ndip;i++) {
251+
j=3*i;
252+
// b[i] = eIncTran*exp(ik*kt.r)
253+
cvMultScal_cmplx(cexp(I*WaveNum*crDotProd(ktVec,DipoleCoord+j)),eIncTran,b+j);
254+
}
255+
}
256+
else if (prop[2]<0) { // beam comes from above the substrate
257+
// determine amplitude of the reflected and transmitted waves
258+
if (which==INCPOL_Y) { // s-polarized
259+
cvBuildRe(ex,eIncRefl);
260+
cvBuildRe(ex,eIncTran);
261+
rc=FresnelRS(ki,kt);
262+
tc=FresnelTS(ki,kt);
263+
}
264+
else { // p-polarized
265+
vInvRefl_cr(ex,eIncRefl);
266+
crCrossProd(ey,ktVec,eIncTran);
267+
cvMultScal_cmplx(1/msub,eIncTran,eIncTran); // normalize eIncTran by ||ktVec||=msub
268+
rc=FresnelRP(ki,kt,msub);
269+
tc=FresnelTP(ki,kt,msub);
270+
}
271+
// phase shift due to the origin at height hsub
272+
cvMultScal_cmplx(rc*imExp(2*WaveNum*ki*hsub),eIncRefl,eIncRefl);
273+
cvMultScal_cmplx(tc*cexp(I*WaveNum*(ki-kt)*hsub),eIncTran,eIncTran);
274+
// main part
275+
for (i=0;i<local_nvoid_Ndip;i++) {
276+
j=3*i;
277+
// b[i] = ex*exp(ik*r.a) + eIncRefl*exp(ik*prIncRefl.r)
278+
cvMultScal_RVec(imExp(WaveNum*DotProd(DipoleCoord+j,prop)),ex,b+j);
279+
cvLinComb1_cmplx(eIncRefl,b+j,imExp(WaveNum*DotProd(DipoleCoord+j,prIncRefl)),b+j);
280+
}
281+
}
282+
}
283+
else for (i=0;i<local_nvoid_Ndip;i++) { // standard (non-surface) plane wave
186284
j=3*i;
187285
ctemp=imExp(WaveNum*DotProd(DipoleCoord+j,prop)); // ctemp=exp(ik*r.a)
188286
cvMultScal_RVec(ctemp,ex,b+j); // b[i]=ctemp*ex

src/calculator.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ extern size_t TotalEval;
5252
// used in CalculateE.c
5353
double * restrict muel_phi; // used to store values of Mueller matrix for different phi (to integrate)
5454
double * restrict muel_phi_buf; // additional for integrating with different multipliers
55-
// scattered E (for scattering in one plane) for two incident polarizations
55+
// scattered E (for scattering in the default scattering plane) for two incident polarizations
5656
doublecomplex * restrict EplaneX, * restrict EplaneY;
57+
doublecomplex * restrict EyzplX, * restrict EyzplY; // same for scattering in yz-plane
5758
double dtheta_deg,dtheta_rad; // delta theta in degrees and radians
5859
doublecomplex * restrict ampl_alphaX,* restrict ampl_alphaY; // amplitude matrix for different values of alpha
5960
double * restrict muel_alpha; // mueller matrix for different values of alpha
@@ -184,12 +185,11 @@ static void CoupleConstant(doublecomplex *mrel,const enum incpol which,doublecom
184185
}
185186
}
186187
if (asym || anisotropy) {
187-
if (!orient_avg && IFROOT) PrintBoth(logfile, "CoupleConstant:"CFORM3V"\n",creal(coup_con[0]),
188-
cimag(coup_con[0]),creal(coup_con[1]),cimag(coup_con[1]),creal(coup_con[2]),cimag(coup_con[2]));
188+
if (!orient_avg && IFROOT) PrintBoth(logfile, "CoupleConstant:"CFORM3V"\n",REIM3V(coup_con));
189189
}
190190
else {
191191
coup_con[2]=coup_con[1]=coup_con[0];
192-
if (!orient_avg && IFROOT) PrintBoth(logfile,"CoupleConstant:"CFORM"\n",creal(coup_con[0]),cimag(coup_con[0]));
192+
if (!orient_avg && IFROOT) PrintBoth(logfile,"CoupleConstant:"CFORM"\n",REIM(coup_con[0]));
193193
}
194194
memcpy(res,coup_con,3*sizeof(doublecomplex));
195195
}
@@ -263,10 +263,7 @@ static void calculate_one_orientation(double * restrict res)
263263
D("MuellerMatrix finished");
264264
if (IFROOT && orient_avg) {
265265
tstart=GET_TIME();
266-
/* it is more logical to use store_mueller in the following test, but for orientation averaging these two flags
267-
* are identical
268-
*/
269-
if (yzplane) printf("\nError of alpha integration (Mueller) is "GFORMDEF"\n",
266+
if (store_mueller) printf("\nError of alpha integration (Mueller) is "GFORMDEF"\n",
270267
Romberg1D(parms_alpha,block_theta,muel_alpha,res+2));
271268
memcpy(res,muel_alpha-2,2*sizeof(double));
272269
D("Integration over alpha completed on root");
@@ -369,6 +366,16 @@ static void AllocateEverything(void)
369366
MALLOC_VECTOR(expsZ,complex,local_Nz_unif,ALL);
370367
#endif // !SPARSE
371368
if (yzplane) {
369+
tmp=2*(double)nTheta;
370+
if (!prognosis) {
371+
CheckOverflow(2*tmp,ONE_POS_FUNC);
372+
temp_int=tmp;
373+
MALLOC_VECTOR(EyzplX,complex,temp_int,ALL);
374+
MALLOC_VECTOR(EyzplY,complex,temp_int,ALL);
375+
}
376+
memory+=2*tmp*sizeof(doublecomplex);
377+
}
378+
if (scat_plane) {
372379
tmp=2*(double)nTheta;
373380
if (!prognosis) {
374381
CheckOverflow(2*tmp,ONE_POS_FUNC);
@@ -419,7 +426,7 @@ static void AllocateEverything(void)
419426
if (!prognosis) {
420427
// this covers these 2 and next 2 malloc calls
421428
CheckOverflow(8*tmp+2,ONE_POS_FUNC);
422-
if (yzplane) {
429+
if (store_mueller) {
423430
temp_int=tmp;
424431
MALLOC_VECTOR(ampl_alphaX,complex,temp_int,ONE);
425432
MALLOC_VECTOR(ampl_alphaY,complex,temp_int,ONE);
@@ -517,6 +524,10 @@ static void FreeEverything(void)
517524
* in AllocateEverything() above.
518525
*/
519526
if (yzplane) {
527+
Free_cVector(EyzplX);
528+
Free_cVector(EyzplY);
529+
}
530+
if (scat_plane) {
520531
Free_cVector(EplaneX);
521532
Free_cVector(EplaneY);
522533
}
@@ -542,7 +553,7 @@ static void FreeEverything(void)
542553

543554
if (orient_avg) {
544555
if (IFROOT) {
545-
if (yzplane) {
556+
if (store_mueller) {
546557
Free_cVector(ampl_alphaX);
547558
Free_cVector(ampl_alphaY);
548559
}

0 commit comments

Comments
 (0)