#include "pol_montecarlo.h" #include "netcdfcpp.h" #include #include #include // Remember all the length and time units are in mfp=lsa. const double n_water=1.33; const double n_sct=1.59; const double lambda=0.515; // micro const double dia=0.46; // micro const double xx=pi*dia/lambda*n_water; // size parameter of the Mie sphere const double mr=n_sct/n_water, mi=0.0; // m=mr-i*mi is the refractive index const double L=40; // slab thickness in lsa const double HW=10; // the half width of the window in lsa const int NN=100; // NN grids on the backscattering window const double KK=45; // the wavenumber in lsa const int MAXSCT=1000; double S[NN][NN][4]; double EE[NN][NN][4]; static long prephotons=0; // number of photons used in previous simulations static long photons=1000000000; // number of photons to use in the current simulation // 45mins in the mode 2 // convert parallel E1 and perpendicular E2 to Stokes vector static inline void EtoS(dcmplx E1, dcmplx E2, double S[4]) { // we comment this out if we only collect Ex and Ey in the detector // assert( fabs(norm(E1) + norm(E2) - 1) < 1e-8 ); S[0] = norm(E1) + norm(E2); S[1] = norm(E1) - norm(E2); S[2] = 2*(conj(E1)*E2).real(); S[3] = 2*(conj(E1)*E2).imag(); } static int write_results(const char* fname) { NcFile nc (fname, NcFile::Replace); // Create and leave in define mode // Check if the file was opened if (! nc.is_valid()) { std::cerr << "can't create netCDF file " << fname << "\n"; return 0; } // Create dimensions NcDim* nn = nc.add_dim("NN", NN); NcDim* four = nc.add_dim("FOUR", 4); // Create variables and their attributes NcVar* c = nc.add_var("S", ncDouble, nn, nn, four); c->add_att("long_name", "Stokes vector"); NcVar* c1 = nc.add_var("EE", ncDouble, nn, nn, four); c1->add_att("long_name", "ExRe ExIm EyRe EyIm"); // Global attributes nc.add_att("NN", NN); nc.add_att("HW", HW); nc.add_att("xx", xx); nc.add_att("mr", mr); nc.add_att("mi", mi); nc.add_att("L", L); nc.add_att("photons", photons); // Start writing dcata, implictly leaves define mode c->put(&S[0][0][0], c->edges()); c1->put(&EE[0][0][0], c1->edges()); // close of nc takes place in destructor return 1; } static int load_results(const char* fname) { NcFile nc (fname, NcFile::ReadOnly); // Create and leave in define mode // Check if the file was opened if (! nc.is_valid()) { std::cerr << "can't open netCDF file " << fname << "\n"; return 0; } // Get attribute NcAtt* a=nc.get_att("photons"); prephotons = a->values()->as_long(0); // Get dimensions NcDim* nn = nc.get_dim("NN"); long n = nn->size(); long four = 4; // Get variables NcVar* c = nc.get_var("S"); NcVar* c1 = nc.get_var("EE"); // Push values c->get(&EE[0][0][0], n, n, four); c1->get(&S[0][0][0], n, n, four); // display the current state printf("Previous simulations used %ld photons.\n", prephotons); nc.close(); return 1; } int main (int argc, char** argv) { dcmplx Ei1, Ei2; // incident E field double Si[4]; dcmplx Ex, Ey; // outgoing E field double So[4]; dcmplx Ed1, Ed2, phase; // used by pointEstimator double td, deposit, Q[3][3]; int ix, iy; double T, R, Lost; // total transmission, reflection and lost photons char *seedfname=new char[50]; char *ncfname=new char[50]; dcmplx m(mr, mi); scatterer sct(xx, m); photonPacket *ph; if (argc == 1) sprintf(seedfname, "speckle.seed"); else sprintf(seedfname, "speckle%s.seed", argv[1]); if ( access(seedfname, R_OK) == 0 ) ph = new photonPacket(&sct, seedfname); else ph = new photonPacket(&sct); for (int cno = 0; cno < 1; cno++) { T = R = Lost = 0; // reset counters for (ix=0; ixlaunch (Ei1, Ei2); if (i % 10000 == 0) fprintf(stderr, "%d\n", i); while (1) { ph->move (); if (ph->nsct > MAXSCT) { Lost += ph->weight; break; } if (ph->z > L) { T += ph->weight; break; } if (ph->z < 0) { R += ph->weight; break; } // find when and where light crosses the boundary ph->pointestimator(&td, &deposit, Q, &Ed1, &Ed2, 0, 0, 0, -1); ix = (int)floor((ph->x+HW)/HW*NN/2); iy = (int)floor((ph->y+HW)/HW*NN/2); if (ix < 0) ix = 0; if (ix >= NN) ix = NN - 1; if (iy < 0) iy = 0; if (iy >= NN) iy = NN - 1; // compute Ex and Ey from Ed phase = dcmplx(cos(KK*td), sin(KK*td)); Ex = (Ed1*Q[0][0] + Ed2*Q[1][0])*phase; Ey = (Ed1*Q[0][1] + Ed2*Q[1][1])*phase; // accumulate Ex and Ey EE[iy][ix][0] += Ex.real()*sqrt(deposit); EE[iy][ix][1] += Ex.imag()*sqrt(deposit); EE[iy][ix][2] += Ey.real()*sqrt(deposit); EE[iy][ix][3] += Ey.imag()*sqrt(deposit); // // IMPORTANT: the Stokes vector of the outgoing light refers to a local coordinate system (-x, y, -z) in reflection // The field (Ex, Ey, Ez) in the global system must be transformed to (-Ex, Ey, -Ez) EtoS(-Ex, Ey, So); // We use [iy][ix] agreeing with the convention in Jessica's iquv S[iy][ix][0] += So[0]*deposit; S[iy][ix][1] += So[1]*deposit; S[iy][ix][2] += So[2]*deposit; S[iy][ix][3] += So[3]*deposit; ph->scatter(); } } printf("Case#, T, R, Lost=%d %f %f %f\n", cno, T, R, Lost); photons += prephotons; write_results(ncfname); photons -= prephotons; // revert photons to the inital value for the next case } ph->saveRand(seedfname); delete ph; delete seedfname; delete ncfname; }