rl_raylib  1.1.10
rl_DielectricLayer.cc
1 // File: rl_DielectricLayer.cc
2 // Author: Terry Gaetz
3 //
4 // --8<--8<--8<--8<--
5 //
6 // Copyright (C) 2006, 2007 Smithsonian Astrophysical Observatory
7 //
8 // This file is part of rl_raylib
9 //
10 // rl_raylib is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License
12 // as published by the Free Software Foundation; either version 2
13 // of the License, or (at your option) any later version.
14 //
15 // rl_raylib is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the
22 // Free Software Foundation, Inc.
23 // 51 Franklin Street, Fifth Floor
24 // Boston, MA 02110-1301, USA
25 //
26 // -->8-->8-->8-->8--
27 
28 // #define DEBUG_DIELECTRICLAYER
29 #define DIEL_GAMMA_NEGATIVE 1
30 
31 #include <rl_DielectricLayer.h> // rl_DielectricLayer
32 
33 #include <cstring> // strlen strcpy
34 #include <cstdio> // stdout
35 // #include <cfloat> // DBL_MAX
36 #include <mathconst/mathconst.h> // M_PI
37 
38 #include <iomanip>
39 
40 using namespace std;
41 
42 //=========================================================================
43 // dtor, ctors...
44 
45 //-------------------------------------------------------------------------
48 {
49  if ( name_ ) { delete [] name_; }
50 }
51 
52 //-------------------------------------------------------------------------
53 // default constructor: initialize as an infinitely thick vacuum layer.
54 
56 rl_DielectricLayer( char const layer_name[] )
57  : diel_info_()
58  , thickness_(-1.0)
59  , zcoat_(-1.0)
60  , alpha_(0.0)
61  , gamma_(0.0)
62  , rtype_(rl_Traits::ERoughNone)
63  , srough_(0.0)
64  , lambda_(826.5)
65  , prop_( complex(1.0,0.0) )
66  , kt_perp_( complex(0.0,0.0) )
67  , phase_factor_(0.0)
68  , rflcoef_()
69  , t_ij_()
70  , t_ji_()
71  , is_substrate_(rl_Traits::False)
72 {
73  try {
74 
75  if ( layer_name )
76  {
77  name_ = new char[strlen(layer_name)+1];
78  }
79  else
80  {
81  name_ = new char[1];
82  *name_ = '\0';
83  }
84 
85  } catch ( std::exception& bad_alloc ) {
86 
87  char msg[] = "rl_DielectricLayer(layername): "
88  "unable to allocate space for the layer name";
89 
90  throw rl_Exception( msg );
91  }
92 }
93 
94 //-------------------------------------------------------------------------
95 // DEEP Copy Constructor.
96 
99  : diel_info_()
100  , thickness_(-1.0)
101  , zcoat_(-1.0)
102  , alpha_(0.0)
103  , gamma_(0.0)
104  , rtype_(rl_Traits::ERoughNone)
105  , srough_(0.0)
106  , lambda_(826.5)
107  , prop_( complex(1.0,0.0) )
108  , kt_perp_( complex(0.0,0.0) )
109  , phase_factor_(0.0)
110  , rflcoef_()
111  , t_ij_()
112  , t_ji_()
113  , is_substrate_(rl_Traits::False)
114 {
115  try {
116 
117  if ( other.name_ )
118  {
119  name_ = new char[strlen(other.name_)+1];
120  strcpy( name_, other.name_ );
121  }
122  else
123  {
124  name_ = new char[1];
125  *name_ = '\0';
126  }
127 
128  } catch ( std::exception& bad_alloc ) {
129 
130  char msg[] = "rl_DielectricLayer copy constructor: "
131  "unable to allocate space for the layer name";
132 
133  throw rl_Exception( msg );
134  }
135 }
136 
137 //-------------------------------------------------------------------------
138 
141  std::size_t ndielpts,
142  double layer_thickness,
143  double roughness,
144  rl_Traits::ERoughType roughness_type,
145  rl_Traits::EInterpMode interp_mode,
146  double bulkdensity,
147  char const* layer_name,
148  rl_Traits::Bool is_substrate )
149 {
150  init( diel, ndielpts, layer_thickness, roughness, roughness_type,
151  interp_mode, bulkdensity, layer_name, is_substrate );
152 }
153 
154 //-------------------------------------------------------------------------
155 
158  std::size_t ndielpts,
159  double layer_thickness,
160  double roughness,
161  rl_Traits::ERoughType roughness_type,
162  rl_Traits::EInterpMode interp_mode,
163  double bulkdensity,
164  char const* layer_name,
165  rl_Traits::Bool is_substrate )
166 {
167  diel_info_.init( diel, ndielpts, interp_mode, bulkdensity );
168 
169  try {
170 
171  if ( layer_name )
172  {
173  name_ = new char[strlen(layer_name)+1];
174  strcpy( name_, layer_name );
175  }
176  else
177  {
178  name_ = new char[1];
179  *name_ = '\0';
180  }
181 
182  } catch ( std::exception& bad_alloc ) {
183 
184  char msg[256] = "rl_DielectricLayer::init(...): "
185  "unable to allocate space for layer name";
186 
187  throw rl_Exception( msg );
188  }
189 
190  thickness_ = layer_thickness; // layer thickness (Angstroms)
191  rtype_ = roughness_type; // layer roughness type
192  srough_ = roughness; // roughness parameter (Angstroms)
193  is_substrate_ = is_substrate; // 0; 1, if this is the substrate,
194 
195  switch ( rtype_ )
196  {
197  case rl_Traits::ERoughDebyeWaller_RSAO : // fall through
198  case rl_Traits::ERoughDebyeWaller_CSAO : // fall through
199  case rl_Traits::ERoughDebyeWaller_Spiller : // fall through
200  case rl_Traits::ERoughNevotCroce : // fall through
201  case rl_Traits::ERoughModifiedDebyeWaller : // fall through
202  case rl_Traits::ERoughNone : break;
203 
204  default :
205  { char msg[256];
206  char const format[] = "rl_DielectricPODArray::init(...): "
207  "Invalid roughness type was %d\n";
208  sprintf( msg, format, rtype_ );
209  throw rl_Exception( msg );
210  }
211  } /* end rl_Traits::ERoughType cases */
212 
213 }
214 
215 //=========================================================================
216 // mutators...
217 
218 //-------------------------------------------------------------------------
220 setup_for( double energy, double sinphi )
221 {
222  lambda_ = 12.39854 / energy; // wavelength (Angstrom)
223 
224  if ( rtype_ != rl_Traits::ERoughNone )
225  {
226  phase_factor_ = 2.0 * M_PI * srough_ / lambda_;
227  }
228  else
229  {
230  phase_factor_ = 0.0;
231  }
232 
233  int rc = diel_info_.alpha_gamma( energy, alpha_, gamma_ );
234 
235  //-------------------
236  // kt_perp_
237  //
238  // This is the component of the complex wave vector perpendicular
239  // to the interface divided by k0, the magnitude of the wave vector
240  // in the vacuum.
241  //
242  // The boundary condition at the interface requires that the component
243  // of the wave vector parallel to the interface is the same for each
244  // layer. The perpendicular component is then
245  // k_{\perp,j} = \sqrt{ \sin^2 \phi_0 + \Delta \epsilon }
246  // where \phi_0 is the graze angle in the vacuum and
247  // \Delta\epsilon is the dielectric decrement, i.e.,
248  // complex( -alpha, -gamma ).
249  // Note that in obtaining k_{\perp,j} we take a complex square
250  // root. The imaginary part of the principal root is obtained
251  // by multiplying b by the sign of gamma_.
252 
253  double const difab = sinphi * sinphi - alpha_;
254  double const sumab = sqrt( difab * difab + gamma_ * gamma_ );
255 
256  // Force b to be evaluated to avoid sqrt(-tiny) when i86
257  // extended FP registers in use. Is there a g++ compiler option
258  // to force this? There's supposed to be a way to set the FP mode...
259 
260  double const a = sqrt( (sumab + difab) / 2.0 );
261  double const tmp = (sumab - difab) / 2.0;
262  double const b = (tmp >= 0.0) ? sqrt( tmp ) : sqrt( -tmp );
263 
264  // the following ifdefs allow hardwiring the branch cut for efficiency
265  #ifdef DIEL_GAMMA_GENERAL
266  kt_perp_ = complex( a, ((gamma_ > 0.0) ? 1.0 : -1.0) * b );
267  #else
268  #ifdef DIEL_GAMMA_NEGATIVE
269  kt_perp_ = complex( a, -b );
270  #endif
271  #ifdef DIEL_GAMMA_POSITIVE
272  kt_perp_ = complex( a, b );
273  #endif
274  #endif
275 
276  #if defined(DEBUG_DIELECTRICLAYER)
277  fprintf(stdout, "\nDEBUG: ___SETUP_FOR___ %s ---------------------\n",
278  name_ );
279  fprintf(stdout, "kt_perp_ (%.15e %.15e)\n",
280  kt_perp_.real(),
281  kt_perp_.imag() );
282  fprintf(stdout, "alpha_ gamma_ (%.15e %.15e)\n",
283  alpha_, gamma_ );
284  fprintf(stdout, "energy, sinphi (%.15e %.15e)\n",
285  energy, sinphi );
286  fprintf(stdout, "difab sumab tmp (%.15e %.15e %.15e)\n",
287  difab, sumab, tmp );
288  fprintf(stdout, "a, b (%.15e %.15e)\n",
289  a, b );
290  #endif
291 
292  //-------------------
293  // evaluate layer propagator
294  // the layer propagator is exp( phase_factor )
295 
296  if (! rc )
297  {
298  if (! is_vacuum() && ! is_substrate() )
299  {
300  zcoat_ = 4.0 * M_PI * thickness_ / lambda_;
301  // dimensionless thickness of layer
302 
303  prop_ = exp( complex( -b * zcoat_, -a * zcoat_ ) );
304  #if defined(DEBUG_DIELECTRICLAYER)
305  fprintf(stdout, "zcoat_ %.15e\n",
306  zcoat_ );
307  fprintf(stdout, "prop_ (r,i) (%.15e %.15e)\n",
308  prop_.real(), prop_.imag() );
309  #endif
310  }
311  }
312  return rc; // 0 if successful
313 }
314 
315 //-------------------------------------------------------------------------
316 // calculate complex reflection coefficients at interface between
317 // this layer and layer immediately above it.
318 
320 reflect_amp( rl_DielectricLayer const& upper, double sinphi )
321 {
322  double alpha_jm1 = upper.alpha_;
323  double gamma_jm1 = upper.gamma_;
324  double alpha_j = alpha_;
325  double gamma_j = gamma_;
326 
327  complex upper_delta_eps( -alpha_jm1, -gamma_jm1 );
328  complex delta_eps( -alpha_j, -gamma_j );
329 
330  complex eps_upper( upper_delta_eps + 1.0 );
331  complex eps( delta_eps + 1.0 );
332 
333  complex num_perp = upper.kt_perp_ - kt_perp_;
334  complex denom_perp = upper.kt_perp_ + kt_perp_;
335 
336  rflcoef_.perp() = num_perp / denom_perp;
337 
338  #if defined(DEBUG_DIELECTRICLAYER)
339  fprintf(stdout, "\nDEBUG: ___REFLECT_AMP___ ___AAA0___ --------\n");
340  fprintf(stdout, "upper, this layer (%s %s)\n",
341  upper.name_, name_);
342  fprintf(stdout, "alpha, gamma (j-1): (%.15e, %.15e)\n",
343  alpha_jm1, gamma_jm1);
344  fprintf(stdout, "alpha, gamma (j): (%.15e, %.15e)\n",
345  alpha_j, gamma_j);
346  fprintf(stdout, "rflcoef (perp) (%.15e %.15e)\n",
347  rflcoef_.perp().real(),
348  rflcoef_.perp().imag() );
349  fprintf(stdout, "num_perp (%.15e %.15e)\n",
350  num_perp.real(),
351  num_perp.imag() );
352  fprintf(stdout, "denom_perp (%.15e %.15e)\n",
353  denom_perp.real(),
354  denom_perp.imag() );
355  fprintf(stdout, "upper.kt_perp_ (%.15e %.15e)\n",
356  upper.kt_perp_.real(),
357  upper.kt_perp_.imag() );
358  fprintf(stdout, "kt_perp_ %.15e %.15e)\n",
359  kt_perp_.real(),
360  kt_perp_.imag() );
361  #endif
362 
363  complex num_para = delta_eps * upper.kt_perp_;
364  num_para -= upper_delta_eps * kt_perp_;
365  num_para += num_perp;
366 
367  complex denom_para = delta_eps * upper.kt_perp_;
368  denom_para += upper_delta_eps * kt_perp_;
369  denom_para += denom_perp;
370 
371  rflcoef_.para() = num_para / denom_para;
372 
373  double eps_epsupper_r = alpha_jm1 * alpha_j - gamma_jm1 * gamma_j;
374  eps_epsupper_r -= alpha_jm1 + alpha_j;
375  eps_epsupper_r += 1.0;
376 
377  double eps_epsupper_i = alpha_jm1 * gamma_j + gamma_jm1 * alpha_j;
378  eps_epsupper_i -= gamma_jm1 + gamma_j;
379 
380  eps_epsupper_ = complex( eps_epsupper_r, eps_epsupper_i );
381 
382  #if defined(DEBUG_DIELECTRICLAYER)
383  fprintf(stdout, "eps_epsupper (r,i): (%.15e, %.15e)\n",
384  eps_epsupper_r, eps_epsupper_i);
385  fprintf(stdout, "num_para (%.15e %.15e)\n",
386  num_para.real(),
387  num_para.imag() );
388  fprintf(stdout, "denom_perp (%.15e %.15e)\n",
389  denom_para.real(),
390  denom_para.imag() );
391  fprintf(stdout, "rflcoef (para) (%.15e %.15e)\n",
392  rflcoef_.para().real(),
393  rflcoef_.para().imag() );
394  #endif
395 
396  if (! is_substrate() )
397  {
398  t_ij_.perp() = 2.0 * upper.kt_perp_ / denom_perp;
399  t_ji_.perp() = 2.0 * kt_perp_ / denom_perp;
400 
401  t_ij_.para() = 2.0 * ( eps * upper.kt_perp_ ) / denom_para;
402  t_ji_.para() = 2.0 * ( eps_upper * kt_perp_ ) / denom_para;
403 
404  tij_tji_perp_ = t_ij_.perp() * t_ji_.perp();
405  tij_tji_para_ = t_ij_.para() * t_ji_.para();
406 
407  r_perp_ = rflcoef_.perp();
408  r_para_ = rflcoef_.para();
409  r2_perp_ = rflcoef_.perp() * rflcoef_.perp();
410  r2_para_ = rflcoef_.para() * rflcoef_.para();
411  r2_tij_tji_perp_ = r2_perp_ + tij_tji_perp_;
412  r2_tij_tji_para_ = r2_para_ + tij_tji_para_;
413 
414  #if defined(DEBUG_DIELECTRICLAYER)
415  fprintf(stdout, "t_ij_ (para) (%.15e %.15e)\n",
416  t_ij_.para().real(),
417  t_ij_.para().imag() );
418  fprintf(stdout, "t_ji_ (para) (%.15e %.15e)\n",
419  t_ji_.para().real(),
420  t_ji_.para().imag() );
421  fprintf(stdout, "t_ij_ (perp) (%.15e %.15e)\n",
422  t_ij_.perp().real(),
423  t_ij_.perp().imag() );
424  fprintf(stdout, "t_ji_ (perp) (%.15e %.15e)\n",
425  t_ji_.perp().real(),
426  t_ji_.perp().imag() );
427  fprintf(stdout, "tij_tji_perp_ (%.15e %.15e)\n",
428  tij_tji_perp_.real(),
429  tij_tji_perp_.imag() );
430  fprintf(stdout, "tij_tji_para_ (%.15e %.15e)\n",
431  tij_tji_para_.real(),
432  tij_tji_para_.imag() );
433  fprintf(stdout, "r_perp_ (%.15e %.15e)\n",
434  r_perp_.real(),
435  r_perp_.imag() );
436  fprintf(stdout, "r_para_ (%.15e %.15e)\n",
437  r_para_.real(),
438  r_para_.imag() );
439  fprintf(stdout, "r2_perp_ (%.15e %.15e)\n",
440  r2_perp_.real(),
441  r2_perp_.imag() );
442  fprintf(stdout, "r2_para_ (%.15e %.15e)\n",
443  r2_para_.real(),
444  r2_para_.imag() );
445  fprintf(stdout, "r2_tij_tji_perp_ (%.15e %.15e)\n",
446  r2_tij_tji_perp_.real(),
447  r2_tij_tji_perp_.imag() );
448  fprintf(stdout, "r2_tij_tji_para_ (%.15e %.15e)\n",
449  r2_tij_tji_para_.real(),
450  r2_tij_tji_para_.imag() );
451  #endif
452 
453  }
454 
455  switch ( rtype_ )
456  {
458 
459  apply_DebyeWaller_RSAO_factor( upper, sinphi );
460  break;
461 
463 
464  apply_DebyeWaller_CSAO_factor( upper, sinphi );
465  break;
466 
468 
469  apply_DebyeWaller_Spiller_factor( sinphi );
470  break;
471 
473 
474  apply_NevotCroce_factor( upper, sinphi );
475  break;
476 
478 
479  apply_ModifiedDW_factor( upper, sinphi );
480  break;
481 
482  case rl_Traits::ERoughNone :
483 
484  /* do nothing */
485  break;
486 
487  default :
488 
489  cerr << "Invalid roughness type in rl_DielectricLayer::reflect_amp"
490  << endl;
491  cerr << "Roughness type was " << rtype_ << endl;
492  exit(1);
493 
494  } /* end rl_Traits::ERoughType cases */
495 }
496 
497 //-------------------------------------------------------------------------
498 // c Calculate n-layer reflectivity using recurrence relation.
499 // c
500 // subroutine reflect_nlayer ( ca, cprop, n, refl )
501 // implicit complex (c)
502 // dimension ca(15), cprop(14)
503 // c
504 // ceps = ca( n )
505 // do m=n-1, 1, -1
506 // ceps = (ca(m) + cprop(m)*ceps) / (1.0 + cprop(m)*ca(m)*ceps)
507 // end do
508 // c
509 // rmod = abs( ceps )
510 // refl = rmod*rmod
511 // c
512 // return
513 // end
514 
517  int num )
518 {
519  complex eps_para( layer[num-1].rflcoef_.para() );
520  complex eps_perp( layer[num-1].rflcoef_.perp() );
521  const complex one( 1.0 );
522  #if defined(DEBUG_DIELECTRICLAYER)
523  fprintf(stdout, "\nDEBUG: ___REFLECT_NLAYER___ ___AAA0___ -----\n");
524  fprintf(stdout, "\n==> layer %5d -- ", num-1);
525  fprintf(stdout, "layer[n-1] (%5d %.s)\n",
526  num-1, layer[num-1].name_);
527  fprintf(stdout, "rl_DielectricLayer::reflect_nlayer ");
528  fprintf(stdout, "======================\n");
529  fprintf(stdout, "eps (para) %5d (%.15e %.15e)\n",
530  num-1, eps_para.real(), eps_para.imag());
531  fprintf(stdout, "eps (perp) %5d (%.15e %.15e)\n",
532  num-1, eps_perp.real(), eps_perp.imag());
533  #endif
534 
535  for ( int n = num-2; n >= 0; --n )
536  {
537  rl_Traits::complex prop_eps_para( layer[n].propagator() * eps_para );
538  eps_para = (layer[n].rflcoef_.para()
539  + layer[n].r2_tij_tji_para_ * prop_eps_para)
540  / (one + layer[n].rflcoef_.para() * prop_eps_para);
541 
542  rl_Traits::complex prop_eps_perp( layer[n].propagator() * eps_perp );
543  eps_perp = (layer[n].rflcoef_.perp()
544  + layer[n].r2_tij_tji_perp_ * prop_eps_perp)
545  / (one + layer[n].rflcoef_.perp() * prop_eps_perp);
546 
547  #if defined(DEBUG_DIELECTRICLAYER)
548  fprintf(stdout, "\nDEBUG: ___REFLECT_NLAYER___ ___AAA1___ -----\n");
549  fprintf(stdout, "\n==> layer %5d -- ", n);
550  fprintf(stdout, "rl_DielectricLayer::reflect_nlayer ");
551  fprintf(stdout, "======================\n");
552  cprint_constraints_on( stdout );
553  fprintf(stdout, "rflcoef (para) %5d, (%.15e %.15e)\n",
554  n, layer[n].rflcoef_.para().real(),
555  layer[n].rflcoef_.para().imag() );
556 
557  fprintf(stdout, "rflcoef (perp) %5d, (%.15e %.15e)\n",
558  n, layer[n].rflcoef_.perp().real(),
559  layer[n].rflcoef_.perp().imag() );
560 
561  fprintf(stdout, "r2_tt (para) %5d, (%.15e %.15e)\n",
562  n, layer[n].r2_tij_tji_para_.real(),
563  layer[n].r2_tij_tji_para_.imag() );
564 
565  fprintf(stdout, "r2_tt (perp) %5d, (%.15e %.15e)\n",
566  n, layer[n].r2_tij_tji_perp_.real(),
567  layer[n].r2_tij_tji_perp_.imag() );
568 
569  fprintf(stdout, "eps (para) %5d, (%.15e %.15e)\n",
570  n, eps_para.real(), eps_para.imag());
571  fprintf(stdout, "eps (perp) %5d, (%.15e %.15e)\n",
572  n, eps_perp.real(), eps_perp.imag());
573  #endif
574  }
575  layer[0].rflcoef_.para() = eps_para;
576  layer[0].rflcoef_.perp() = eps_perp;
577 
578  #if defined(DEBUG_DIELECTRICLAYER)
579  fprintf(stdout, "\n");
580  #endif
581 
582 #if 0
583  refl = abs( eps );
584  refl *= refl;
585 #endif
586 }
587 
588 //=========================================================================
589 
590 //-------------------------------------------------------------------------
591 // Routine to evaluate Debye-Waller roughness factor
592 // <code>phase_factor</code> is <code>2 pi srough / lambda</code>
593 //
594 // Implemented in the IDL code as dw_csao: SAO variant on Windt's DW,
595 // using complex factor
596 // exp(double(-2d*kc*kc*sigma_t(j)*sigma_t(j)*c_t(*,*,j)*c_t(*,*,j)))
597 
598 void rl_DielectricLayer::
599 apply_DebyeWaller_CSAO_factor( rl_DielectricLayer const& upper, // upper layer
600  double sinphi // sin(graze angle)
601  )
602 {
603  double phase_factor = -2 * phase_factor_ * phase_factor_;
604  double sinphi_sq = sinphi * sinphi;
605 
606  complex sinterm_0( sinphi_sq - upper.alpha_, -upper.gamma_ );
607  sinterm_0 /= complex( 1.0 - upper.alpha_, -upper.gamma_ );
608 
609  complex ckphase( sinterm_0 );
610  ckphase *= phase_factor;
611  ckphase = exp(ckphase);
612 
613  rflcoef_.para() *= ckphase;
614  rflcoef_.perp() *= ckphase;
615 }
616 
617 //-------------------------------------------------------------------------
618 // Routine to evaluate Debye-Waller roughness factor
619 // <code>phase_factor</code> is <code>2 pi srough / lambda</code>
620 //
621 // Implemented in the IDL code as dw_csao: SAO variant on Windt's DW,
622 // taking only the real part of the factor
623 // exp(double(-2d*kc*kc*sigma_t(j)*sigma_t(j)*c_t(*,*,j)*c_t(*,*,j)))
624 
625 void rl_DielectricLayer::
626 apply_DebyeWaller_RSAO_factor( rl_DielectricLayer const& upper, // upper layer
627  double sinphi // sin(graze angle)
628  )
629 {
630  double phase_factor = -2.0 * phase_factor_ * phase_factor_;
631  double sinphi_sq = sinphi * sinphi;
632 
633  complex sinterm_0( sinphi_sq - upper.alpha_, -upper.gamma_ );
634  sinterm_0 /= complex( 1.0 - upper.alpha_, -upper.gamma_ );
635 
636  complex ckphase( sinterm_0 );
637  ckphase *= phase_factor;
638  double real_phase_factor = ckphase.real();
639  real_phase_factor = exp( real_phase_factor );
640 
641  rflcoef_.para() *= real_phase_factor;
642  rflcoef_.perp() *= real_phase_factor;
643 }
644 
645 //-------------------------------------------------------------------------
646 // Routine to evaluate Debye-Waller roughness factor
647 // <code>phase_factor</code> is <code>2 pi srough / lambda</code>
648 //
649 // Implemented in the IDL code as dw_spiller: Variant on the DW rising
650 // from a paper by Spiller
651 // exp(-2d*kc*kc*sigma_t(j)*sigma_t(j)*c_t(*,*,j)*c_t(*,*,j)*
652 // n(*,*,j)*n(*,*,j))
653 
654 void rl_DielectricLayer::
655 apply_DebyeWaller_Spiller_factor( double sinphi // sin(graze angle)
656  )
657 {
658  double phase_factor = phase_factor_;
659 
660  phase_factor *= sinphi;
661  phase_factor *= phase_factor;
662  phase_factor *= 2.0;
663 
664  complex ckphase( phase_factor * (alpha_ - 1.0),
665  phase_factor * gamma_ );
666 
667  complex cexp_factor = exp(ckphase);
668 
669  rflcoef_.para() *= cexp_factor;
670  rflcoef_.perp() *= cexp_factor;
671 }
672 
673 //-------------------------------------------------------------------------
674 // Routine to evaluate "modified Debye-Waller" roughness factor
675 // <code>phase_factor</code> is <code>2 pi srough / lambda</code>
676 
677 void rl_DielectricLayer::
678 apply_ModifiedDW_factor( rl_DielectricLayer const& upper, // upper layer
679  double sinphi // sin(graze angle)
680  )
681 {
682  double phase_factor = phase_factor_;
683  double sinphi_sq = sinphi * sinphi;
684 
685  #if defined(DEBUG_DIELECTRICLAYER)
686  fprintf(stdout, "\nDEBUG: ___MDW___ ---------------------------\n");
687  cerr << "==================================================================="
688  << endl;
689  cerr << "Layer j-1:" << endl;
690  upper.cdump_on( stdout );
691  cerr << "-------------------------------------------------------------------"
692  << endl;
693  cerr << "Layer j:" << endl;
694  cdump_on( stdout );
695  cerr << "-------------------------------------------------------------------"
696  << endl;
697  #endif
698 
699  phase_factor *= -2.0 * phase_factor;
700 
701  #if defined(DEBUG_DIELECTRICLAYER)
702  cerr << "sinphi: " << sinphi << endl;
703  cerr << "phi: " << 60.0 * asin(sinphi) / M_DEG2RAD << endl;
704  cerr << "-2 (2pi sigma/lambda)^2: " << phase_factor << endl;
705  #endif
706 
707  complex sinterm_0( sinphi_sq - upper.alpha_, -upper.gamma_ );
708  complex nopt0 = sqrt( complex( 1.0 - upper.alpha_, -upper.gamma_ ));
709  complex cos2_0 = sqrt( sinterm_0 ) / nopt0;
710 
711  #if defined(DEBUG_DIELECTRICLAYER)
712  cerr << "cos_{j-1}: " << cos2_0 << endl;
713  #endif
714 
715  complex sinterm_1( sinphi_sq - alpha_, -gamma_ );
716  complex nopt1 = sqrt( complex( 1.0 - alpha_, -gamma_ ) );
717  complex cos2_1 = sqrt( sinterm_1 ) / nopt1;
718 
719  #if defined(DEBUG_DIELECTRICLAYER)
720  complex cosij = cos2_0 * cos2_1;
721  complex cosj = cos2_0 * nopt0 / nopt1;
722  complex sin2_0 = sqrt( complex(1.0) - cos2_0 * cos2_0 );
723  complex sin2_1 = sqrt( complex(1.0) - cos2_1 * cos2_1 );
724  cerr << "cos_{j}: " << cos2_1 << endl;
725  cerr << "cos_{j-1} n_{j-1} / n_{j} " << cos2_0 * nopt0 / nopt1 << endl;
726  cerr << "n_{j-1} sin_{j-1} " << sin2_0 * nopt0 << endl;
727  cerr << "n_{j} sin_{j} " << sin2_1 * nopt1 << endl;
728  cerr << "cos_{j} cos_{j-1} " << cosij << endl;
729  #endif
730 
731  complex cexp_factor( cos2_0 );
732  cexp_factor *= cos2_1;
733  cexp_factor *= phase_factor;
734  cexp_factor = exp( cexp_factor );
735 
736  rflcoef_.para() *= cexp_factor;
737  rflcoef_.perp() *= cexp_factor;
738 
739  #if defined(DEBUG_DIELECTRICLAYER)
740  cerr << "==================================================================="
741  << endl;
742  #endif
743 }
744 
745 //-------------------------------------------------------------------------
746 // Routine to evaluate Nevot-Croce factor
747 // <code>phase_factor</code> is <code>2 pi srough / lambda</code>
748 //
749 //<code>
750 // \NC_\mathit{j-1,j}
751 // = \exp\left[ -2 \k_0^2
752 // \left[ \left( \sin^2 \tilde\alpha_0 + \Delta\eps_{j} \right)
753 // \left( \sin^2 \tilde\alpha_0 + \Delta\eps_{j-1} \right)
754 // \right]^{1\over 2}
755 // \sigma_\j^2 \right]
756 //</code>
757 
758 void rl_DielectricLayer::
759 apply_NevotCroce_factor( rl_DielectricLayer const& upper, // upper layer
760  double sinphi // sin(graze angle)
761  )
762 {
763  double phase_factor = phase_factor_;
764  double sinphi_sq = sinphi * sinphi;
765 
766  phase_factor *= phase_factor;
767  phase_factor *= -2.0;
768 
769  complex sinterm_0( sinphi_sq - upper.alpha_, -upper.gamma_ );
770  complex sinterm_1( sinphi_sq - alpha_, -gamma_ );
771  complex ckphase( sinterm_0 );
772 
773  ckphase *= sinterm_1;
774  ckphase = sqrt( ckphase );
775  ckphase *= phase_factor;
776  ckphase = exp(ckphase);
777 
778  rflcoef_.para() *= ckphase;
779  rflcoef_.perp() *= ckphase;
780 }
781 
782 //=========================================================================
783 // i/o
784 
785 //-------------------------------------------------------------------------
786 std::ostream& rl_DielectricLayer::
787 dump_on( std::ostream& os, char const pre[], char const pst[] ) const
788 {
789  if ( strlen(pre) )
790  { os << pre; }
791 
792  os << "Layer: " << name_ << endl;
793  os.setf( ios::scientific, ios::floatfield );
794  os.precision(12);
795 
796  os << "minimum energy (keV): " << diel_info_.energy_min() << endl;
797  os << "maximum energy (keV): " << diel_info_.energy_max() << endl;
798  os << "bulk density scale: " << diel_info_.bulk_density_factor() << endl;
799 
800  os << "thickness (Angstrom): " << thickness_ << endl;
801  if (! is_vacuum() )
802  {
803  os << "reflection coefficient: " << rflcoef_ << endl;
804  }
805  os << "alpha: " << alpha_ << endl;
806  os << "gamma: " << gamma_ << endl;
807  os << "refractive index: "
808  << sqrt( complex( 1.0 - alpha_, -gamma_ )) << endl;
809  if (! is_vacuum() )
810  {
811  os << "roughness type: " << rtype_ << endl;
812  os << "sigma_rough: " << srough_ << endl;
813  os << "wavelength: " << lambda_ << endl;
814  os << "zcoat: " << zcoat_ << endl;
815  os << "propagator: " << prop_ << endl;
816  os << "kt_perp_: " << kt_perp_ << endl;
817  }
818  os << "is_vacuum: " << is_vacuum() << endl;
819  os << "is_substrate: " << is_substrate_ << endl;
820 
821  if ( strlen(pst) )
822  { os << pst; }
823 
824  return os;
825 }
826 
827 //=========================================================================
828 // i/o
829 
830 //-------------------------------------------------------------------------
832 cdump_on( std::FILE* of, char const pre[], char const pst[] ) const
833 {
834  if ( strlen(pre) )
835  { fprintf(of, "%s", pre); }
836 
837  fprintf(of, "Layer: %s\n", name_);
838 
839  fprintf(of, "minimum energy (keV): %.15e\n", diel_info_.energy_min());
840  fprintf(of, "maximum energy (keV): %.15e\n", diel_info_.energy_max());
841  fprintf(of, "bulk density scale: %.15e\n",
842  diel_info_.bulk_density_factor());
843 
844  fprintf(of, "thickness (Angstrom): %.15e\n", thickness_);
845  if (! is_vacuum() )
846  {
847  rflcoef_.cprint_on(of);
848  }
849  fprintf( of, "alpha: %.15e\n", alpha_);
850  fprintf( of, "gamma: %.15e\n", gamma_);
851 
852  complex srt = sqrt( complex( 1.0 - alpha_, -gamma_ ) );
853  fprintf(of, "refractive index: (%.15e, %.15e)\n",
854  srt.real(), srt.imag());
855 
856  if (! is_vacuum() )
857  {
858  fprintf(of, "roughness type: %d\n", rtype_);
859  fprintf(of, "sigma_rough: %.15e\n", srough_);
860  fprintf(of, "wavelength: %.15e\n", lambda_);
861  fprintf(of, "zcoat: %.15e\n", zcoat_);
862  fprintf(of, "propagator: (%.15e, %.15e)\n",
863  prop_.real(), prop_.imag());
864  fprintf(of, "kt_perp_: (%.15e, %.15e)\n",
865  kt_perp_.real(), kt_perp_.imag());
866  }
867  fprintf(of, "is_vacuum: %d\n", is_vacuum());
868  fprintf(of, "is_substrate: %d\n", is_substrate_);
869 
870  if ( strlen(pst) )
871  { fprintf(of, "%s", pst); }
872 }
873 
874 //-------------------------------------------------------------------------
876 cprint_constraints_on( std::FILE* of,
877  char const pre[], char const pst[] ) const
878 {
879  if ( strlen(pre) )
880  { fprintf(of, "%s", pre); }
881 
882  fprintf(of, "Layer: %s\n", name_);
883 
884  complex identperp = t_ij_.perp() - rflcoef_.perp();
885  complex identpara = t_ij_.para() - rflcoef_.para();
886 
887  fprintf(of, "minimum energy (keV): %.14e\n", diel_info_.energy_min());
888  fprintf(of, "maximum energy (keV): %.14e\n", diel_info_.energy_max());
889  fprintf(of, "bulk density scale: %.14e\n",
890  diel_info_.bulk_density_factor());
891 
892  fprintf(of, "thickness (Angstrom): %.14e\n", thickness_);
893  fprintf( of, "alpha: %.14e\n", alpha_);
894  fprintf( of, "gamma: %.14e\n", gamma_);
895 
896  complex srt = sqrt( complex( 1.0 - alpha_, -gamma_ ) );
897  fprintf(of, "refractive index: (%.14e, %.14e)\n",
898  srt.real(), srt.imag());
899 
900  if (! is_vacuum() )
901  {
902  fprintf(of, "roughness type: %d\n", rtype_);
903  fprintf(of, "sigma_rough: %.14e\n", srough_);
904  fprintf(of, "wavelength: %.14e\n", lambda_);
905  fprintf(of, "zcoat: %.14e\n", zcoat_);
906  fprintf(of, "propagator: (%.14e, %.14e)\n",
907  prop_.real(), prop_.imag());
908  fprintf(of, "kt_perp_: (%.14e, %.14e)\n",
909  kt_perp_.real(), kt_perp_.imag());
910  fprintf(of, "\n");
911 
912  fprintf(of, "Tji_perp: (%.14e, %.14e)\n",
913  t_ji_.perp().real(), t_ji_.perp().imag());
914  fprintf(of, "Tij_perp: (%.14e, %.14e)\n",
915  t_ij_.perp().real(), t_ij_.perp().imag());
916  fprintf(of, "Rij_perp: (%.14e, %.14e)\n",
917  rflcoef_.perp().real(), rflcoef_.perp().imag());
918  fprintf(of, "Rij^2 (perp): (%.14e, %.14e)\n",
919  r2_perp_.real(), r2_perp_.imag());
920  fprintf(of, "Tij Tji (perp): (%.14e, %.14e)\n",
921  tij_tji_perp_.real(), tij_tji_perp_.imag());
922  double tprpi = (fabs(identperp.imag()) >= 1e-15)
923  ? identperp.imag() : 0.0;
924  fprintf(of, "Tij_perp-Rij_perp: (%.14e, %.14e)\n",
925  identperp.real(), tprpi);
926  fprintf(of, "Rij^2+Tij Tji (perp): (%.14e, %.14e)\n",
927  r2_tij_tji_perp_.real(), r2_tij_tji_perp_.imag());
928  fprintf(of, "\n");
929 
930  fprintf(of, "Tji_para: (%.14e, %.14e)\n",
931  t_ji_.para().real(), t_ji_.para().imag());
932  fprintf(of, "Tij_para: (%.14e, %.14e)\n",
933  t_ij_.para().real(), t_ij_.para().imag());
934  fprintf(of, "Rij_para: (%.14e, %.14e)\n",
935  rflcoef_.para().real(), rflcoef_.para().imag());
936  fprintf(of, "Rij^2 (para): (%.14e, %.14e)\n",
937  r2_para_.real(), r2_para_.imag());
938  fprintf(of, "Tij Tji (para): (%.14e, %.14e)\n",
939  tij_tji_para_.real(), tij_tji_para_.imag());
940  fprintf(of, "Tij_para-Rij_para: (%.14e, %.14e)\n",
941  identpara.real(), identpara.imag());
942  fprintf(of, "Rij^2+Tij Tji (para): (%.14e, %.14e)\n",
943  r2_tij_tji_para_.real(), r2_tij_tji_para_.imag());
944  fprintf(of, "\n");
945  }
946  fprintf(of, "is_vacuum: %d\n", is_vacuum());
947  fprintf(of, "is_substrate: %d\n", is_substrate_);
948 
949  if ( strlen(pst) )
950  { fprintf(of, "%s", pst); }
951 }
ERoughType roughness_type() const
Returns the roughness type of the upper surface of this layer.
void init(rl_Traits::rl_DielectricPOD const *diel, std::size_t ndielpts, double layer_thickness, double roughness, rl_Traits::ERoughType roughness_type, rl_Traits::EInterpMode interp_mode, double bulkdensity, char const *layer_name, rl_Traits::Bool is_substrate=rl_Traits::False)
Initializer.
void init(rl_Traits::rl_DielectricPOD const *diel, size_t num_pts, rl_Traits::EInterpMode interp_mode, double bulk_density=1.0)
Initialization function.
Nevot-Croce factor.
Definition: rl_Traits.h:87
std::complex< double > complex
Typedef for the complex type.
Definition: rl_Traits.h:61
int setup_for(double energy, double sinphi)
Set up layer state for given energy and graze angle.
rl_Traits::complex para() const
Modified Debye-Waller factor.
Definition: rl_Traits.h:86
double bulk_density_factor() const
Return the maximum energy covered by this dataset.
Debye-Waller factor.
Definition: rl_Traits.h:84
The exception thrown by the rl_RayLib and rl_RaySupLib libraries.
Definition: rl_Exception.h:36
void reflect_nlayer(rl_DielectricLayer layer[], int num)
Compute reflectivity for a stack of num layers.
rl_Traits::Bool is_substrate() const
int alpha_gamma(double energy, double &alpha, double &gamma)
Evaluate the dielectric decrements, alpha and gamma, at the given energy.
no interlayer diffusion
Definition: rl_Traits.h:82
void cdump_on(std::FILE *of, char const pre[]="", char const pst[]="") const
Dumps layer information to a C-style FILE* stream.
std::ostream & dump_on(std::ostream &os, char const pre[]="", char const pst[]="") const
Dumps layer information to a stream.
rl_Traits::complex complex
complex type
rl_DielectricLayer(char const layer_name[]=0)
Constructor.
rl_Traits::complex perp() const
void cprint_constraints_on(std::FILE *of, char const pre[]="", char const pst[]="") const
Dumps layer information and constraints to a C-style FILE* stream.
double energy_min() const
Return the minimum energy covered by this dataset.
char const * layer_name() const
rl_Traits::Bool is_vacuum() const
EInterpMode
Enumeration specifying the interpolation of the optical constants.
Definition: rl_Traits.h:69
~rl_DielectricLayer()
Destructor.
ERoughType
Enumeration specifying the type of interlayer diffusion treatment.
Definition: rl_Traits.h:80
complex const & propagator() const
The propagator for this layer.
rl_Traits is a `‘traits’' class for the rl_RayLib library.
Definition: rl_Traits.h:55
double energy_max() const
Return the maximum energy covered by this dataset.
Debye-Waller factor.
Definition: rl_Traits.h:83
void reflect_amp(rl_DielectricLayer const &layer, double sinphi)
Compute reflection amplitude for the interface between this layer and the layer immediately above it.
rl_Traits::complex para() const
rl_Traits::complex perp() const
void cprint_on(std::FILE *of, char const pre[]="", char const pst[]="") const
Print reflectivity information to output FILE* stream.
A class encapsulating the multilayer reflection of a ray.
Bool
Typedef for the Boolean type.
Definition: rl_Traits.h:64
double roughness() const
Returns the roughness parameter of the upper surface of this layer.