File indexing completed on 2026-04-09 07:49:52
0001 #pragma once
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 #ifdef WITH_THRUST
0062 #include <thrust/complex.h>
0063 #else
0064 #include <complex>
0065 #include <cmath>
0066 #endif
0067
0068 #if defined(__CUDACC__) || defined(__CUDABE__)
0069 #else
0070 #include <iostream>
0071 #include <iomanip>
0072 #include <sstream>
0073 #include <string>
0074 #include <cassert>
0075 #include <cstdlib>
0076 #include <vector>
0077 #endif
0078
0079 #if defined(__CUDACC__) || defined(__CUDABE__)
0080 # define LAYR_METHOD __host__ __device__ __forceinline__
0081 #else
0082 # define LAYR_METHOD inline
0083 #endif
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097 namespace Const
0098 {
0099 template<typename T>
0100 LAYR_METHOD constexpr T zero(){ return T(0.0) ; }
0101
0102 template<typename T>
0103 LAYR_METHOD constexpr T one() { return T(1.0) ; }
0104
0105 template<typename T>
0106 LAYR_METHOD constexpr T two() { return T(2.0) ; }
0107
0108 template<typename T>
0109 LAYR_METHOD constexpr T pi() { return T(M_PI) ; }
0110
0111 template<typename T>
0112 LAYR_METHOD constexpr T twopi() { return T(2.0*M_PI) ; }
0113 }
0114
0115
0116 #if defined(__CUDACC__) || defined(__CUDABE__)
0117 #else
0118 #ifdef WITH_THRUST
0119 template<typename T>
0120 inline std::ostream& operator<<(std::ostream& os, const thrust::complex<T>& z)
0121 {
0122 os << "(" << std::setw(10) << std::fixed << std::setprecision(4) << z.real()
0123 << " " << std::setw(10) << std::fixed << std::setprecision(4) << z.imag() << ")t" ;
0124 return os;
0125 }
0126 #else
0127 template<typename T>
0128 inline std::ostream& operator<<(std::ostream& os, const std::complex<T>& z)
0129 {
0130 os << "(" << std::setw(10) << std::fixed << std::setprecision(4) << z.real()
0131 << " " << std::setw(10) << std::fixed << std::setprecision(4) << z.imag() << ")s" ;
0132 return os;
0133 }
0134 #endif
0135 #endif
0136
0137 template<typename T>
0138 struct Matx
0139 {
0140 #ifdef WITH_THRUST
0141 thrust::complex<T> M00, M01, M10, M11 ;
0142 #else
0143 std::complex<T> M00, M01, M10, M11 ;
0144 #endif
0145 LAYR_METHOD void reset();
0146 LAYR_METHOD void dot(const Matx<T>& other);
0147 };
0148
0149 template<typename T>
0150 LAYR_METHOD void Matx<T>::reset()
0151 {
0152 M00.real(1) ; M00.imag(0) ;
0153 M01.real(0) ; M01.imag(0) ;
0154 M10.real(0) ; M10.imag(0) ;
0155 M11.real(1) ; M11.imag(0) ;
0156 }
0157
0158
0159
0160
0161
0162
0163
0164 template<typename T>
0165 LAYR_METHOD void Matx<T>::dot(const Matx<T>& other)
0166 {
0167 #ifdef WITH_THRUST
0168 using thrust::complex ;
0169 #else
0170 using std::complex ;
0171 #endif
0172 complex<T> T00(M00) ;
0173 complex<T> T01(M01) ;
0174 complex<T> T10(M10) ;
0175 complex<T> T11(M11) ;
0176
0177 M00 = T00*other.M00 + T01*other.M10;
0178 M01 = T00*other.M01 + T01*other.M11;
0179 M10 = T10*other.M00 + T11*other.M10;
0180 M11 = T10*other.M01 + T11*other.M11;
0181 }
0182
0183 #if defined(__CUDACC__) || defined(__CUDABE__)
0184 #else
0185 template<typename T>
0186 inline std::ostream& operator<<(std::ostream& os, const Matx<T>& m)
0187 {
0188 os
0189 << "| " << m.M00 << " " << m.M01 << " |" << std::endl
0190 << "| " << m.M10 << " " << m.M11 << " |" << std::endl
0191 ;
0192 return os;
0193 }
0194 #endif
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 template<typename T>
0208 struct Layr
0209 {
0210
0211 T d ;
0212 T pad=0 ;
0213 #ifdef WITH_THRUST
0214 thrust::complex<T> n, st, ct ;
0215 #else
0216 std::complex<T> n, st, ct ;
0217 #endif
0218
0219
0220 #ifdef WITH_THRUST
0221 thrust::complex<T> rs, rp, ts, tp ;
0222 #else
0223 std::complex<T> rs, rp, ts, tp ;
0224 #endif
0225
0226 Matx<T> S ;
0227
0228 Matx<T> P ;
0229
0230
0231 LAYR_METHOD void reset();
0232 LAYR_METHOD void load4( const T* vals );
0233 };
0234
0235 template<typename T>
0236 LAYR_METHOD void Layr<T>::reset()
0237 {
0238 S.reset();
0239 P.reset();
0240 }
0241
0242 template<typename T>
0243 LAYR_METHOD void Layr<T>::load4(const T* vals)
0244 {
0245 d = vals[0] ;
0246 pad = vals[1] ;
0247 n.real(vals[2]) ;
0248 n.imag(vals[3]) ;
0249 }
0250
0251
0252
0253 #if defined(__CUDACC__) || defined(__CUDABE__)
0254 #else
0255 template<typename T>
0256 inline std::ostream& operator<<(std::ostream& os, const Layr<T>& l)
0257 {
0258 os
0259 << "Layr"
0260 << std::endl
0261 << std::setw(4) << "n:" << l.n
0262 << std::setw(4) << "d:" << std::fixed << std::setw(10) << std::setprecision(4) << l.d
0263 << std::endl
0264 << std::setw(4) << "st:" << l.st
0265 << std::setw(4) << "ct:" << l.ct
0266 << std::endl
0267 << std::setw(4) << "rs:" << l.rs
0268 << std::setw(4) << "rp:" << l.rp
0269 << std::endl
0270 << std::setw(4) << "ts:" << l.ts
0271 << std::setw(4) << "tp:" << l.tp
0272 << std::endl
0273 << "S"
0274 << std::endl
0275 << l.S
0276 << std::endl
0277 << "P"
0278 << std::endl
0279 << l.P
0280 << std::endl
0281 ;
0282 return os;
0283 }
0284 #endif
0285
0286 template<typename F>
0287 struct ART_
0288 {
0289 F R_s;
0290 F R_p;
0291 F T_s;
0292 F T_p;
0293
0294 F A_s;
0295 F A_p;
0296 F R;
0297 F T;
0298
0299 F A;
0300 F A_R_T ;
0301 F wl ;
0302 F mct ;
0303
0304
0305 };
0306
0307 #if defined(__CUDACC__) || defined(__CUDABE__)
0308 #else
0309 template<typename T>
0310 inline std::ostream& operator<<(std::ostream& os, const ART_<T>& art )
0311 {
0312 os
0313 << "ART_" << std::endl
0314 << " R_s " << std::fixed << std::setw(10) << std::setprecision(4) << art.R_s
0315 << " R_p " << std::fixed << std::setw(10) << std::setprecision(4) << art.R_p
0316 << std::endl
0317 << " T_s " << std::fixed << std::setw(10) << std::setprecision(4) << art.T_s
0318 << " T_p " << std::fixed << std::setw(10) << std::setprecision(4) << art.T_p
0319 << std::endl
0320 << " A_s " << std::fixed << std::setw(10) << std::setprecision(4) << art.A_s
0321 << " A_p " << std::fixed << std::setw(10) << std::setprecision(4) << art.A_p
0322 << std::endl
0323 << " R " << std::fixed << std::setw(10) << std::setprecision(4) << art.R
0324 << " T " << std::fixed << std::setw(10) << std::setprecision(4) << art.T
0325 << " A " << std::fixed << std::setw(10) << std::setprecision(4) << art.A
0326 << " A_R_T " << std::fixed << std::setw(10) << std::setprecision(4) << art.A_R_T
0327 << std::endl
0328 << " wl " << std::fixed << std::setw(10) << std::setprecision(4) << art.wl << std::endl
0329 << " mct " << std::fixed << std::setw(10) << std::setprecision(4) << art.mct << std::endl
0330 ;
0331 return os;
0332 }
0333 #endif
0334
0335
0336 #if defined(__CUDACC__) || defined(__CUDABE__)
0337 #else
0338 namespace sys
0339 {
0340 template<typename T>
0341 inline std::vector<T>* getenvvec(const char* ekey, const char* fallback = nullptr, char delim=',')
0342 {
0343 char* _line = getenv(ekey);
0344 const char* line = _line ? _line : fallback ;
0345 if(line == nullptr) return nullptr ;
0346
0347 std::stringstream ss;
0348 ss.str(line);
0349 std::string s;
0350
0351 std::vector<T>* vec = new std::vector<T>() ;
0352
0353 while (std::getline(ss, s, delim))
0354 {
0355 std::istringstream iss(s);
0356 T t ;
0357 iss >> t ;
0358 vec->push_back(t) ;
0359 }
0360 return vec ;
0361 }
0362 }
0363 #endif
0364
0365
0366 template<typename T>
0367 struct LayrSpec
0368 {
0369 T nr, ni, d ;
0370 #if defined(__CUDACC__) || defined(__CUDABE__)
0371 #else
0372 static int EGet(LayrSpec<T>& ls, int idx);
0373 #endif
0374 };
0375
0376 #if defined(__CUDACC__) || defined(__CUDABE__)
0377 #else
0378 template<typename T>
0379 LAYR_METHOD int LayrSpec<T>::EGet(LayrSpec<T>& ls, int idx)
0380 {
0381 std::stringstream ss ;
0382 ss << "L" << idx ;
0383 std::string ekey = ss.str();
0384 std::vector<T>* vls = sys::getenvvec<T>(ekey.c_str()) ;
0385 if(vls == nullptr) return 0 ;
0386 const T zero(0) ;
0387 ls.nr = vls->size() > 0u ? (*vls)[0] : zero ;
0388 ls.ni = vls->size() > 1u ? (*vls)[1] : zero ;
0389 ls.d = vls->size() > 2u ? (*vls)[2] : zero ;
0390 return 1 ;
0391 }
0392
0393 template<typename T>
0394 LAYR_METHOD std::ostream& operator<<(std::ostream& os, const LayrSpec<T>& ls )
0395 {
0396 os
0397 << "LayrSpec<" << ( sizeof(T) == 8 ? "double" : "float" ) << "> "
0398 << std::fixed << std::setw(10) << std::setprecision(4) << ls.nr << " "
0399 << std::fixed << std::setw(10) << std::setprecision(4) << ls.ni << " ; "
0400 << std::fixed << std::setw(10) << std::setprecision(4) << ls.d << ")"
0401 << std::endl
0402 ;
0403 return os ;
0404 }
0405 #endif
0406
0407
0408 template<typename T, int N>
0409 struct StackSpec
0410 {
0411 LayrSpec<T> ls[N] ;
0412
0413 #if defined(__CUDACC__) || defined(__CUDABE__)
0414 #else
0415 LAYR_METHOD static StackSpec<T,N> Create2(float n1, float n2) ;
0416 LAYR_METHOD void eget() ;
0417 #endif
0418
0419 };
0420
0421 #if defined(__CUDACC__) || defined(__CUDABE__)
0422 #else
0423
0424 template<typename T, int N>
0425 LAYR_METHOD StackSpec<T,N> StackSpec<T,N>::Create2(float n1, float n2)
0426 {
0427 assert( N == 2 );
0428 StackSpec<T,N> ss ;
0429
0430 ss.ls[0].nr = n1 ;
0431 ss.ls[0].ni = 0. ;
0432 ss.ls[0].d = 0. ;
0433
0434 ss.ls[1].nr = n2 ;
0435 ss.ls[1].ni = 0. ;
0436 ss.ls[1].d = 0. ;
0437
0438 return ss ;
0439 }
0440
0441
0442 template<typename T, int N>
0443 LAYR_METHOD void StackSpec<T,N>::eget()
0444 {
0445 int count = 0 ;
0446 for(int i=0 ; i < N ; i++) count += LayrSpec<T>::EGet(ls[i], i);
0447 assert( count == N ) ;
0448 }
0449
0450 template<typename T, int N>
0451 LAYR_METHOD std::ostream& operator<<(std::ostream& os, const StackSpec<T,N>& ss )
0452 {
0453 os
0454 << "StackSpec<"
0455 << ( sizeof(T) == 8 ? "double" : "float" )
0456 << "," << N
0457 << ">"
0458 << std::endl ;
0459
0460 for(int i=0 ; i < N ; i++) os << ss.ls[i] ;
0461 return os ;
0462 }
0463
0464 #endif
0465
0466
0467
0468
0469
0470
0471
0472
0473 template <typename T, int N>
0474 struct Stack
0475 {
0476 Layr<T> ll[N] ;
0477 Layr<T> comp ;
0478 ART_<T> art ;
0479
0480 LAYR_METHOD void zero();
0481 LAYR_METHOD Stack();
0482 LAYR_METHOD Stack(T wl, T minus_cos_theta, const StackSpec<T,N>& ss);
0483 };
0484
0485 template<typename T, int N>
0486 LAYR_METHOD void Stack<T,N>::zero()
0487 {
0488 art = {} ;
0489 comp = {} ;
0490 for(int i=0 ; i < N ; i++) ll[i] = {} ;
0491 }
0492
0493
0494
0495
0496
0497
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526 template<typename T, int N>
0527 LAYR_METHOD Stack<T,N>::Stack()
0528 {
0529 zero();
0530 }
0531
0532 template<typename T, int N>
0533 LAYR_METHOD Stack<T,N>::Stack(T wl, T minus_cos_theta, const StackSpec<T,N>& ss )
0534 {
0535
0536 #ifdef WITH_THRUST
0537 using thrust::complex ;
0538 using thrust::norm ;
0539 using thrust::conj ;
0540 using thrust::exp ;
0541 using thrust::sqrt ;
0542 using thrust::sin ;
0543 using thrust::cos ;
0544 #else
0545 using std::complex ;
0546 using std::norm ;
0547 using std::conj ;
0548 using std::exp ;
0549 using std::sqrt ;
0550 using std::sin ;
0551 using std::cos ;
0552 #endif
0553
0554 #if defined(__CUDACC__) || defined(__CUDABE__)
0555 #else
0556 assert( N >= 2);
0557 #endif
0558
0559 const T zero(Const::zero<T>()) ;
0560 const T one(Const::one<T>()) ;
0561 const T two(Const::two<T>()) ;
0562 const T twopi(Const::twopi<T>()) ;
0563
0564 for(int i=0 ; i < N ; i++)
0565 {
0566 int j = minus_cos_theta < zero ? i : N - 1 - i ;
0567
0568
0569
0570 ll[j].n.real(ss.ls[i].nr) ;
0571 ll[j].n.imag(ss.ls[i].ni) ;
0572 ll[j].d = ss.ls[i].d ;
0573 }
0574
0575
0576
0577
0578
0579 art.wl = wl ;
0580 art.mct = minus_cos_theta ;
0581
0582 const complex<T> zOne(one,zero);
0583 const complex<T> zI(zero,one);
0584 const complex<T> mct(minus_cos_theta);
0585
0586
0587 Layr<T>& l0 = ll[0] ;
0588 l0.ct = minus_cos_theta < zero ? -mct : mct ;
0589
0590
0591
0592
0593
0594
0595 l0.st = sqrt( zOne - mct*mct ) ;
0596
0597 for(int idx=1 ; idx < N ; idx++)
0598 {
0599 Layr<T>& l = ll[idx] ;
0600 l.st = l0.n * l0.st / l.n ;
0601 l.ct = sqrt( zOne - l.st*l.st );
0602 }
0603
0604
0605
0606
0607 for(int idx=0 ; idx < N-1 ; idx++)
0608 {
0609
0610
0611 Layr<T>& i = ll[idx] ;
0612 const Layr<T>& j = ll[idx+1] ;
0613
0614 i.rs = (i.n*i.ct - j.n*j.ct)/(i.n*i.ct+j.n*j.ct) ;
0615 i.rp = (j.n*i.ct - i.n*j.ct)/(j.n*i.ct+i.n*j.ct) ;
0616 i.ts = (two*i.n*i.ct)/(i.n*i.ct + j.n*j.ct) ;
0617 i.tp = (two*i.n*i.ct)/(j.n*i.ct + i.n*j.ct) ;
0618 }
0619
0620
0621
0622
0623 ll[0].reset();
0624
0625 for(int idx=1 ; idx < N ; idx++)
0626 {
0627 const Layr<T>& i = ll[idx-1] ;
0628 Layr<T>& j = ll[idx] ;
0629
0630
0631 complex<T> tmp_s = one/i.ts ;
0632 complex<T> tmp_p = one/i.tp ;
0633
0634
0635
0636
0637
0638 complex<T> delta = j.d == zero ? zero : twopi*j.n*j.d*j.ct/art.wl ;
0639 complex<T> exp_neg_delta = j.d == zero ? one : exp(-zI*delta) ;
0640 complex<T> exp_pos_delta = j.d == zero ? one : exp( zI*delta) ;
0641
0642 j.S.M00 = tmp_s*exp_neg_delta ; j.S.M01 = tmp_s*i.rs*exp_pos_delta ;
0643 j.S.M10 = tmp_s*i.rs*exp_neg_delta ; j.S.M11 = tmp_s*exp_pos_delta ;
0644
0645 j.P.M00 = tmp_p*exp_neg_delta ; j.P.M01 = tmp_p*i.rp*exp_pos_delta ;
0646 j.P.M10 = tmp_p*i.rp*exp_neg_delta ; j.P.M11 = tmp_p*exp_pos_delta ;
0647
0648
0649 }
0650
0651
0652
0653
0654
0655
0656
0657
0658
0659
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669 comp.d = zero ;
0670 comp.st = zero ;
0671 comp.ct = zero ;
0672 comp.S.reset();
0673 comp.P.reset();
0674
0675 for(int idx=0 ; idx < N ; idx++)
0676 {
0677 const Layr<T>& l = ll[idx] ;
0678 comp.S.dot(l.S) ;
0679 comp.P.dot(l.P) ;
0680 }
0681
0682
0683
0684
0685
0686
0687 comp.rs = comp.S.M10/comp.S.M00 ;
0688 comp.rp = comp.P.M10/comp.P.M00 ;
0689 comp.ts = one/comp.S.M00 ;
0690 comp.tp = one/comp.P.M00 ;
0691
0692 Layr<T>& t = ll[0] ;
0693 Layr<T>& b = ll[N-1] ;
0694
0695
0696
0697
0698 complex<T> _T_s = (b.n*b.ct)/(t.n*t.ct)*norm(comp.ts) ;
0699 complex<T> _T_p = (b.n*b.ct)/(t.n*t.ct)*norm(comp.tp) ;
0700
0701 art.T_s = _T_s.real() ;
0702 art.T_p = _T_p.real() ;
0703 art.R_s = norm(comp.rs) ;
0704 art.R_p = norm(comp.rp) ;
0705
0706 art.A_s = one-art.R_s-art.T_s;
0707 art.A_p = one-art.R_p-art.T_p;
0708
0709
0710
0711
0712
0713
0714
0715 art.R = (art.R_s+art.R_p)/two ;
0716 art.T = (art.T_s+art.T_p)/two ;
0717 art.A = (art.A_s+art.A_p)/two ;
0718 art.A_R_T = art.A + art.R + art.T ;
0719 }
0720
0721 #if defined(__CUDACC__) || defined(__CUDABE__)
0722 #else
0723 template <typename T, int N>
0724 inline std::ostream& operator<<(std::ostream& os, const Stack<T,N>& stk )
0725 {
0726 os << "Stack"
0727 << "<"
0728 << ( sizeof(T) == 8 ? "double" : "float" )
0729 << ","
0730 << N
0731 << ">"
0732 << std::endl
0733 ;
0734 for(int idx=0 ; idx < N ; idx++) os << "idx " << idx << std::endl << stk.ll[idx] ;
0735 os << "comp"
0736 << std::endl
0737 << stk.comp
0738 << std::endl
0739 << stk.art
0740 << std::endl
0741 ;
0742 return os;
0743 }
0744 #endif
0745