#ifndef TIRA_BEAM #define TIRA_BEAM #include "../math/vec3.h" #include "../math/function.h" #include "../optics/planewave.h" #include #include #include namespace tira{ namespace optics{ template class beam { vec3 m_direction; vec3 m_focus; cvec3 m_E; T m_k; public: /// /// Beam constructor /// /// Propagation direction of the beam (automatically normalized). /// Focal point for the beam. /// Beam polarization (automatically normalized and orthogonalized). Only works for linear polarization, though. /// Complex beam amplitude (applied to the polarization to create a linearly polarized beam). /// Wavelength beam( vec3 d = vec3(0, 0, 1), vec3 f = vec3(0, 0, 0), vec3 pol = vec3(1, 0, 0), std::complex E = std::complex(1.0, 0.0), T lambda = 1.0 ) { m_direction = d.direction(); //normalize and set the plane wave direction pol = (pol - d.dot(pol)).direction(); //orthogonalize and normalize the polarization vector m_focus = f; //set the focal point m_E[0] = pol[0] * E; //convert the polarization and complex amplitude to a linearly-polarized E vector m_E[1] = pol[1] * E; m_E[2] = pol[2] * E; m_k = 2.0 * std::numbers::pi * lambda; //calculate and store the wavenumber } /// /// Generate a focal spot for the beam using Monte-Carlo sampling. /// /// Numerical aperture of the focusing optics. /// Number of Monte-Carlo samples. /// NA of the internal obscuration. /// std::vector< planewave > mcfocus(T NA, size_t samples, T NA_in = 0) { //create a rotation matrix to orient the beam along the specified direction vector tira::matrix_sq R;// = tira::matrix_sq::identity(); //initialize the rotation matrix to the identity matrix tira::vec3 Z(0, 0, 1); //create a vector along the Z direction tira::quaternion q; q.CreateRotation(Z, m_direction); R = q.toMatrix3(); std::vector< planewave > result(samples); //generate an array of N plane waves double alpha = std::asin(NA); //calculate the angle of the band-pass double alpha_in = std::asin(NA_in); //calculate the angle of the central obscuration double cos_alpha = std::cos(alpha); //calculate the cosine of the band-pass and central obscuration double cos_alpha_in = std::cos(alpha_in); //random sampling is done using Archimede's method - uniform samples are taken in cylindrical space and projected onto a sphere std::random_device rd; //create a random number generator std::default_random_engine eng(rd()); std::uniform_real_distribution<> theta_dist(0.0, 2.0 * std::numbers::pi); //create a distribution for theta (in cylindrical coordinates) std::uniform_real_distribution<> z_dist(cos_alpha, cos_alpha_in); //create a uniform distribution for sampling the z-axis //generate a guide plane wave planewave pw(m_direction[0] * m_k, m_direction[1] * m_k, m_direction[2] * m_k, m_E[0], m_E[1], m_E[2]); double theta, phi; //variables to store the coordinates for theta/phi on a sphere tira::vec3 dir; T w = 1.0 / samples; //integration weight for (size_t n = 0; n < samples; n++) { theta = theta_dist(eng); //randomly generate a theta coordinate between 0 and 2pi phi = std::acos(z_dist(eng)); //randomly generate a z coordinate based on the NA and project to phi dir = R * tira::vec3(1.0, theta, phi).sph2cart(); //convert the value to Cartesian coordinates and store the sample vector result[n] = pw.refract(dir); //refract the plane wave to align with the sample direction result[n] = result[n].translate(m_focus[0], m_focus[1], m_focus[2]); //refocus the plane wave to the focal position result[n] = result[n] * w; //apply the integration weight (1/N) } return result; //return the sample array } }; } //end namespace optics } //end namespace tira #endif