n_particle = ri.n( 'polystyrene', wavelength) # refractive indices can be specified as pint quantities or n_matrix = ri.n( 'vacuum', wavelength) # called from the refractive_index module. n_matrix is the n_medium = ri.n( 'vacuum', wavelength) # space within sample. n_medium is outside the sample. # Calculate the effective refractive index of the sample n_sample = ri.n_eff(n_particle, n_matrix, volume_fraction) # Calculate the phase function and scattering and absorption coefficients from the single scattering model # (this absorption coefficient is of the scatterer, not of an absorber added to the system) p, mu_scat, mu_abs = mc.calc_scat(particle_radius, n_particle, n_sample, volume_fraction, wavelength) lscat = 1 / mu_scat.magnitude # microns # Initialize the trajectories r0, k0, W0 = mc.initialize(nevents, ntrajectories, n_medium, n_sample, boundary) r0 = sc.Quantity(r0, 'um') k0 = sc.Quantity(k0, '') W0 = sc.Quantity(W0, '') # Generate a matrix of all the randomly sampled angles first sintheta, costheta, sinphi, cosphi, theta, _ = mc.sample_angles( nevents, ntrajectories, p) sintheta = np.sin(theta) costheta = np.cos(theta)
def calc_sphere_mc(): # caculate the effective index of the sample n_sample = ri.n_eff(n_particle, n_matrix, volume_fraction_particles) # Calculate the phase function and scattering and absorption coefficients #from the single scattering model # (this absorption coefficient is of the scatterer, not of an absorber #added to the system) p, mu_scat, mu_abs = mc.calc_scat(particle_radius, n_particle, n_sample, volume_fraction_particles, wavelength) # Initialize the trajectories r0, k0, W0 = mc.initialize(nevents, ntrajectories, n_matrix_bulk, n_sample, boundary, sample_diameter=sphere_boundary_diameter) r0 = sc.Quantity(r0, 'um') k0 = sc.Quantity(k0, '') W0 = sc.Quantity(W0, '') # Create trajectories object trajectories = mc.Trajectory(r0, k0, W0) # Generate a matrix of all the randomly sampled angles first sintheta, costheta, sinphi, cosphi, _, _ = mc.sample_angles( nevents, ntrajectories, p) # Create step size distribution step = mc.sample_step(nevents, ntrajectories, mu_scat) # Run photons trajectories.absorb(mu_abs, step) trajectories.scatter(sintheta, costheta, sinphi, cosphi) trajectories.move(step) # Calculate reflection and transmition (refl_indices, trans_indices, _, _, _, refl_per_traj, trans_per_traj, _, _, _, _, reflectance_sphere, _, _, norm_refl, norm_trans) = det.calc_refl_trans(trajectories, sphere_boundary_diameter, n_matrix_bulk, n_sample, boundary, p=p, mu_abs=mu_abs, mu_scat=mu_scat, run_fresnel_traj=False, return_extra=True) return (refl_indices, trans_indices, refl_per_traj, trans_per_traj, reflectance_sphere, norm_refl, norm_trans) ### Calculate phase function and lscat ### # use output of calc_refl_trans to calculate phase function, mu_scat, # and mu_abs for the bulk p_bulk, mu_scat_bulk, mu_abs_bulk = pfs.calc_scat_bulk( refl_per_traj, trans_per_traj, trans_indices, norm_refl, norm_trans, volume_fraction_bulk, sphere_boundary_diameter, n_matrix_bulk, wavelength) return p_bulk, mu_scat_bulk, mu_abs_bulk
def calc_refl_trans(volume_fraction, radius, thickness, Sample, ntrajectories, nevents, seed): """ Calculates a reflection spectrum using the structcol package. Parameters ---------- volume_fraction : float volume fraction of scatterer in the system radius : float (in nm) radius of scatterer thickness : float (in um) film thickness of sample Sample : Sample object contains information about the sample that produced data ntrajectories : int number of trajectories for the multiple scattering calculations nevents : int number of scattering events for the multiple scattering calculations seed : int or None If seed is int, the simulation results will be reproducible. If seed is None, the simulation results are random. Returns ---------- reflectance : ndarray fraction of reflected trajectories over the wavelength range transmittance : ndarray fraction of transmitted trajectories over the wavelength range """ # Read in system parameters from the Sample object particle_radius = sc.Quantity(radius, 'nm') thickness = sc.Quantity(thickness, 'um') particle_index = sc.Quantity(Sample.particle_index, '') matrix_index = sc.Quantity(Sample.matrix_index, '') medium_index = sc.Quantity(Sample.medium_index, '') front_index = sc.Quantity(Sample.front_index, '') back_index = sc.Quantity(Sample.back_index, '') incident_angle = Sample.incident_angle wavelength = sc.Quantity(Sample.wavelength, 'nm') reflectance = np.zeros(len(wavelength)) transmittance = np.zeros(len(wavelength)) for i in np.arange(len(wavelength)): # Calculate the effective index of the sample sample_index = ri.n_eff(particle_index[i], matrix_index[i], volume_fraction, maxwell_garnett=True) # Calculate the phase function and scattering and absorption lengths # from the single scattering model p, mu_scat, mu_abs = mc.calc_scat(particle_radius, particle_index[i], sample_index, volume_fraction, wavelength[i]) # Initialize the trajectories r0, k0, W0 = mc.initialize(nevents, ntrajectories, medium_index[i], sample_index, seed=seed, incidence_angle=incident_angle) r0 = sc.Quantity(r0, 'um') k0 = sc.Quantity(k0, '') W0 = sc.Quantity(W0, '') # Generate a matrix of all the randomly sampled angles first sintheta, costheta, sinphi, cosphi, _, _ = mc.sample_angles( nevents, ntrajectories, p) # Create step size distribution step = mc.sample_step(nevents, ntrajectories, mu_abs, mu_scat) # Create trajectories object trajectories = mc.Trajectory(r0, k0, W0) # Run photons trajectories.absorb(mu_abs, step) trajectories.scatter(sintheta, costheta, sinphi, cosphi) trajectories.move(step) # Calculate the reflection fraction reflectance[i], transmittance[i] = mc.calc_refl_trans( trajectories, sc.Quantity('0.0 um'), thickness, medium_index[i], sample_index, n_front=front_index[i], n_back=back_index[i], detection_angle=np.pi / 2) return (reflectance, transmittance)
def calc_refl_trans(volume_fraction, Sample, ntrajectories=300, nevents=200, seed=None): """ Calculates a reflection spectrum using the structcol package. Parameters ---------- volume_fraction : float volume fraction of scatterer in the system Sample : Sample object contains information about the sample that produced data ntrajectories : int number of trajectories nevents : int number of scattering events seed : int or None If seed is int, the simulation results will be reproducible. If seed is None, the simulation results are random. Returns ---------- reflection : ndarray fraction of reflected trajectories transmission : ndarray fraction of transmitted trajectories """ # Read in system parameters from the Sample object particle_radius = sc.Quantity(Sample.particle_radius, 'nm') thickness = sc.Quantity(Sample.thickness, 'um') particle_index = sc.Quantity(Sample.particle_index, '') matrix_index = sc.Quantity(Sample.matrix_index, '') medium_index = sc.Quantity(Sample.medium_index, '') incident_angle = Sample.incident_angle wavelength = sc.Quantity(Sample.wavelength, 'nm') # Calculate the effective index of the sample sample_index = ri.n_eff(particle_index, matrix_index, volume_fraction) reflectance = [] transmittance = [] for i in np.arange(len(wavelength)): # Calculate the phase function and scattering and absorption lengths # from the single scattering model p, mu_scat, mu_abs = mc.calc_scat(particle_radius, particle_index[i], sample_index[i], volume_fraction, wavelength[i], phase_mie=False, mu_scat_mie=False) # Initialize the trajectories r0, k0, W0 = mc.initialize(nevents, ntrajectories, medium_index[i], sample_index[i], seed=seed, incidence_angle=incident_angle) r0 = sc.Quantity(r0, 'um') k0 = sc.Quantity(k0, '') W0 = sc.Quantity(W0, '') # Generate a matrix of all the randomly sampled angles first sintheta, costheta, sinphi, cosphi, _, _ = mc.sample_angles( nevents, ntrajectories, p) # Create step size distribution step = mc.sample_step(nevents, ntrajectories, mu_abs, mu_scat) # Create trajectories object trajectories = mc.Trajectory(r0, k0, W0) # Run photons trajectories.absorb(mu_abs, step) trajectories.scatter(sintheta, costheta, sinphi, cosphi) trajectories.move(step) # Calculate the reflection fraction R_fraction, T_fraction = mc.calc_refl_trans(trajectories, sc.Quantity('0.0 um'), thickness, medium_index[i], sample_index[i], detection_angle=np.pi / 2) reflectance.append(R_fraction) transmittance.append(T_fraction) # Define an array for the visible wavelengths wavelength_sigma = sc.Quantity(np.arange(400, 1000, 61), 'nm') # The uncertainty for the reflection fraction is taken to be 1 standard # deviation from the mean, and was calculated using the results of 100 identical runs. sigma_measured = np.array([ 1.578339786806479475e-02, 1.814049675099610806e-02, 2.263508305348480368e-02, 2.280651893165159400e-02, 2.289441072296988580e-02, 2.475289930703982594e-02, 2.591244161256863951e-02, 2.432751507610093206e-02, 2.840212103614853448e-02, 2.464656608869982696e-02, 2.535837658100221007e-02, 2.352910256218017013e-02, 2.264365724262535837e-02, 2.574192164180175851e-02, 2.546192844771695551e-02, 2.767992948024671981e-02, 2.399941085043348632e-02, 2.767133759422578734e-02, 2.759793344858079908e-02, 2.581248267951743655e-02, 2.664000919072649631e-02, 2.914272756298553688e-02, 2.549173729396642454e-02, 2.722649681737301583e-02, 2.322297011391676741e-02, 2.409138186086920430e-02, 2.807311239866464025e-02, 3.018509924866123045e-02, 2.929772336148638717e-02, 2.866675231142475078e-02, 2.377896176281297722e-02, 2.532538972626817778e-02, 2.408458082494839558e-02, 2.823887112376391451e-02, 2.285680624758363796e-02, 2.834624619602043455e-02, 2.342167374818072967e-02, 2.896504983742856365e-02, 2.835463183413225105e-02, 2.981124596936481769e-02, 2.499991827718371987e-02, 2.697080309787770400e-02, 2.788310424558666095e-02, 2.819362357263776805e-02, 2.852537757990830647e-02, 2.651641629976883227e-02, 3.022850005391930842e-02, 2.772006618991802729e-02, 2.971671988748269405e-02, 3.219841220549832933e-02, 2.570752641741474998e-02, 2.352680291863861600e-02, 2.709648629442167056e-02, 2.524674214046034038e-02, 2.758045644043585765e-02, 2.607698592177773098e-02, 2.738258841523178236e-02, 2.868487596917410412e-02, 3.176931078488830218e-02, 2.729837088883461590e-02, 2.513728413028934808e-02 ]) # Find the uncertainties corresponding to each wavelength wavelength_ind = main.find_close_indices(wavelength_sigma, wavelength) sigma = sigma_measured[np.array(wavelength_ind)] return main.Spectrum(wavelength.magnitude, reflectance=np.array(reflectance), transmittance=np.array(transmittance), sigma_r=sigma, sigma_t=sigma)