Ejemplo n.º 1
0
def test_goniometer_detector():
    # test
    z_pos = np.array([[0, 0, 0, 0], [1, 1, 1, 1], [-1, -1, 2, 2],
                      [-2, -2, 20, -0.0000001]])
    ntrajectories = z_pos.shape[1]
    nevents = z_pos.shape[0]
    x_pos = np.zeros((nevents, ntrajectories))
    y_pos = np.zeros((nevents, ntrajectories))
    ky = np.zeros((nevents, ntrajectories))
    kx = np.array([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1 / np.sqrt(2)]])
    kz = np.array([[1, 1, 1, 1], [-1, -1, 1, 1], [-1, -1, 1, -1 / np.sqrt(2)]])
    weights = np.ones((nevents, ntrajectories))
    trajectories = mc.Trajectory([x_pos, y_pos, z_pos], [kx, ky, kz], weights)
    thickness = 10
    n_medium = 1
    n_sample = 1
    R, T = det.calc_refl_trans(trajectories,
                               thickness,
                               n_medium,
                               n_sample,
                               'film',
                               detector=True,
                               det_theta=sc.Quantity('45 degrees'),
                               det_len=sc.Quantity('1 um'),
                               det_dist=sc.Quantity('10 cm'),
                               plot_detector=True)

    assert_almost_equal(R, 0.25)
Ejemplo n.º 2
0
def test_throw_valueerror_for_polydisperse_unspecified_parameters(): 
# test that a valueerror is raised when the system is polydisperse and radius2
# concentration or pdi are not specified                 
    with pytest.raises(ValueError):
        seed = 1
        nevents = 10
        ntrajectories = 5
        
        radius_cs = sc.Quantity(np.array([100, 150]), 'nm')  # specify the radii from innermost to outermost layer
        n_particle_cs = sc.Quantity(np.array([1.5,1.5]), '')  # specify the index from innermost to outermost layer           
        concentration = sc.Quantity(np.array([0.9,0.1]), '')
        pdi = sc.Quantity(np.array([1e-7, 1e-7]), '')  # monodisperse limit
    
        # calculate the volume fractions of each layer
        vf_array = np.empty(len(radius_cs))
        r_array = np.array([0] + radius_cs.magnitude.tolist()) 
        for r in np.arange(len(r_array)-1):
            vf_array[r] = (r_array[r+1]**3-r_array[r]**3) / (r_array[-1:]**3) * volume_fraction
            
        n_sample_cs = ri.n_eff(n_particle_cs, n_matrix, vf_array) 
        R_cs, T_cs = calc_montecarlo(nevents, ntrajectories, radius_cs, 
                                     n_particle_cs, n_sample_cs, n_medium, 
                                     volume_fraction, wavelen, seed,
                                     concentration=concentration, pdi=pdi, 
                                     polydisperse=True)  # unspecified radius2
Ejemplo n.º 3
0
def test_trajectories():
    # Initialize runs
    nevents = 2
    ntrajectories = 3
    r0, k0, W0 = mc.initialize(nevents, ntrajectories, n_matrix, n_sample, 'sphere', seed=1, sample_diameter=sc.Quantity('1 um'))
    r0 = sc.Quantity(r0, 'um')
    k0 = sc.Quantity(k0, '')
    W0 = sc.Quantity(W0, '')

    # Create a Trajectory object
    trajectories = mc.Trajectory(r0, k0, W0)
Ejemplo n.º 4
0
def test_index_match():
    ntrajectories = 2
    nevents = 3
    wavelen = sc.Quantity('600 nm')
    radius = sc.Quantity('0.140 um')
    microsphere_radius = sc.Quantity('10 um')
    volume_fraction = sc.Quantity(0.55,'')
    n_particle = sc.Quantity(1.6,'')
    n_matrix = sc.Quantity(1.6,'')
    n_sample = n_matrix
    n_medium = sc.Quantity(1,'')
    
    p, mu_scat, mu_abs = mc.calc_scat(radius, n_particle, n_sample, volume_fraction, wavelen)
    
    # initialize all at center top edge of the sphere going down
    r0_sphere = np.zeros((3,nevents+1,ntrajectories))
    k0_sphere = np.zeros((3,nevents,ntrajectories))
    k0_sphere[2,0,:] = 1
    W0_sphere = np.ones((nevents, ntrajectories))
    
    # make into quantities with units
    r0_sphere = sc.Quantity(r0_sphere, 'um')
    k0_sphere = sc.Quantity(k0_sphere, '')
    W0_sphere = sc.Quantity(W0_sphere, '')
    
    # 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)
    
    # make trajectories object
    trajectories_sphere = mc.Trajectory(r0_sphere, k0_sphere, W0_sphere)
    trajectories_sphere.absorb(mu_abs, step)                         
    trajectories_sphere.scatter(sintheta, costheta, sinphi, cosphi)         
    trajectories_sphere.move(step)
    
    # calculate reflectance
    refl_sphere, trans = det.calc_refl_trans(trajectories_sphere, microsphere_radius,
                                                   n_medium, n_sample, 'sphere',
                                                   p=p, mu_abs=mu_abs, mu_scat=mu_scat, 
                                                   run_fresnel_traj = True,
                                                   max_stuck = 0.0001)    
    
    # calculated by hand from fresnel infinite sum
    refl_fresnel_int = 0.053 # calculated by hand
    refl_exact = refl_fresnel_int + (1-refl_fresnel_int)**2*refl_fresnel_int/(1-refl_fresnel_int**2)
    assert_almost_equal(refl_sphere, refl_exact, decimal=3) 
    
    
    
    
    
Ejemplo n.º 5
0
def calc_montecarlo(nevents, ntrajectories, radius, n_particle, n_sample, 
                    n_medium, volume_fraction, wavelen, seed, radius2=None, 
                    concentration=None, pdi=None, polydisperse=False, 
                    fine_roughness=0., coarse_roughness=0.):
                        
    # Function to run montecarlo for the tests
    p, mu_scat, mu_abs = mc.calc_scat(radius, n_particle, n_sample, 
                                      volume_fraction, wavelen, radius2=radius2, 
                                      concentration=concentration, pdi=pdi, 
                                      polydisperse=polydisperse,
                                      fine_roughness=fine_roughness)

    if coarse_roughness > 0.:
        r0, k0, W0, kz0_rotated, kz0_reflected = mc.initialize(nevents, 
                                                               ntrajectories, 
                                                               n_medium, 
                                                               n_sample, 
                                                               'film',
                                                               seed=seed, 
                                                               coarse_roughness=coarse_roughness)
    else:                                                                    
        r0, k0, W0 = mc.initialize(nevents, ntrajectories, n_medium, n_sample,
                                   'film', seed=seed)
        kz0_rotated = None
        kz0_reflected = None
        
    r0 = sc.Quantity(r0, 'um')
    k0 = sc.Quantity(k0, '')
    W0 = sc.Quantity(W0, '')
    
    sintheta, costheta, sinphi, cosphi, _, _= mc.sample_angles(nevents, 
                                                               ntrajectories,p)

    step = mc.sample_step(nevents, ntrajectories, mu_scat, 
                          fine_roughness=fine_roughness)
                    
    trajectories = mc.Trajectory(r0, k0, W0)
    trajectories.absorb(mu_abs, step)                         
    trajectories.scatter(sintheta, costheta, sinphi, cosphi)         
    trajectories.move(step)
    cutoff = sc.Quantity('50 um')

    # calculate R, T
    R, T = det.calc_refl_trans(trajectories, cutoff, n_medium, n_sample, 'film',
                               kz0_rot=kz0_rotated, kz0_refl=kz0_reflected,
                              fine_roughness=fine_roughness, n_matrix=n_matrix)

    return R, T
Ejemplo n.º 6
0
def calc_path_length(step, exit_indices):
    '''
    Returns reflectance and transmittance as a function of event number
    
    Parameters
    ----------
    step: 2d array (shape: nevents, ntrajectories)
        Sampled step sizes for all events and trajectories in Monte 
        Carlo model
    exit_indices: 1d array (length: ntrajectories)
        event number at exit for each trajectory. Input refl_indices if you want
        to only consider reflectance and trans_indices if you want to only
        consider transmittance. Input refl_indices + trans_indices if you
        want to consider both
    Returns
    -------
    path_length_traj: 1d array (length: ntrajectories)
        path length travelled before exit for each trajectory. 
    
    '''
    ntraj = len(exit_indices)
    path_length_traj = sc.Quantity(np.zeros(ntraj), 'um')

    for i in range(0, ntraj):
        path_length_traj[i] = np.sum(step[:exit_indices[i], i])

    return path_length_traj
Ejemplo n.º 7
0
def test_calc_refl_trans():
    small_n = sc.Quantity(1,'')
    large_n = sc.Quantity(2,'')

    # test absoprtion and stuck without fresnel
    z_pos = np.array([[0,0,0,0],[1,1,1,1],[-1,11,2,11],[-2,12,4,12]])
    x_pos = np.array([[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]])
    y_pos = np.array([[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]])
    ntrajectories = z_pos.shape[1]
    kx = np.zeros((3,4))
    ky = np.zeros((3,4))
    kz = np.array([[1,1,1,1],[-1,1,1,1],[-1,1,1,1]])
    weights = np.array([[.8, .8, .9, .8],[.7, .3, .7, 0],[.1, .1, .5, 0]])
    trajectories = mc.Trajectory([x_pos, y_pos, z_pos],[kx, ky, kz], weights) 
    p, mu_scat, mu_abs = mc.calc_scat(radius, n_particle, small_n, volume_fraction, wavelen) 
    refl, trans = det.calc_refl_trans(trajectories, assembly_radius, small_n, small_n, 'sphere')
    expected_trans_array = np.array([0., .3, 0.25, 0])/ntrajectories #calculated manually
    expected_refl_array = np.array([.7, 0., .25, 0.])/ntrajectories #calculated manually
    assert_almost_equal(refl, np.sum(expected_refl_array))
    assert_almost_equal(trans, np.sum(expected_trans_array))

    # test fresnel as well
    refl, trans = det.calc_refl_trans(trajectories, assembly_radius, small_n, large_n, 'sphere')
    expected_trans_array = np.array([0.0345679, .25185185, 0.22222222, 0.])/ntrajectories #calculated manually
    expected_refl_array = np.array([.69876543, 0.12592593, 0.33333333, 0.11111111])/ntrajectories #calculated manually
    assert_almost_equal(refl, np.sum(expected_refl_array))
    assert_almost_equal(trans, np.sum(expected_trans_array))

    # test steps in z longer than sample thickness
    z_pos = np.array([[0,0,0,0],[1,1,14,12],[-1,11,2,11],[-2,12,4,12]])
    trajectories = mc.Trajectory([x_pos, y_pos, z_pos],[kx, ky, kz], weights) 
    refl, trans= det.calc_refl_trans(trajectories, assembly_radius, small_n, small_n, 'sphere')
    expected_trans_array = np.array([0., .3, .9, .8])/ntrajectories #calculated manually
    expected_refl_array = np.array([.7, 0., 0., 0.])/ntrajectories #calculated manually
    assert_almost_equal(refl, np.sum(expected_refl_array))
    assert_almost_equal(trans, np.sum(expected_trans_array))

    # test tir
    z_pos = np.array([[0,0,0,0],[1,1,1,1],[-1,11,2,11],[-2,12,4,12]])
    weights = np.ones((3,4))
    trajectories = mc.Trajectory([x_pos, y_pos, z_pos],[kx, ky, kz], weights) 
    refl, trans = det.calc_refl_trans(trajectories, assembly_radius, small_n, small_n, 'sphere',
                                     p=p, mu_abs=mu_abs, mu_scat=mu_scat, run_fresnel_traj=True)
    # since the tir=True reruns the stuck trajectory, we don't know whether it will end up reflected or transmitted
    # all we can know is that the end refl + trans > 0.99
    assert_almost_equal(refl + trans, 1.) 
Ejemplo n.º 8
0
def test_polarization_absorption():
    n_particle = sc.Quantity(1.5 + 0.01j, '')
    n_matrix = sc.Quantity(1.0 + 0.01j, '')
    n_medium = sc.Quantity(1.0 + 0.01j, '')
    n_sample = ri.n_eff(n_particle, n_matrix, volume_fraction)

    # run mc trajectories with polarization
    p, mu_scat, mu_abs = mc.calc_scat(radius,
                                      n_particle,
                                      n_sample,
                                      volume_fraction,
                                      wavelen,
                                      polarization=True)
    #print(p)

    r0, k0, W0, p0 = mc.initialize(nevents,
                                   ntrajectories,
                                   n_medium,
                                   n_sample,
                                   'film',
                                   polarization=True)
    r0 = sc.Quantity(r0, 'um')
    k0 = sc.Quantity(k0, '')
    W0 = sc.Quantity(W0, '')
    p0 = sc.Quantity(p0, '')
    sintheta, costheta, sinphi, cosphi, theta, phi = mc.sample_angles(
        nevents, ntrajectories, p)

    trajectories = mc.Trajectory(r0, k0, W0, p0)
    trajectories.scatter(sintheta, costheta, sinphi, cosphi)
    trajectories.polarize(theta, phi, sintheta, costheta, sinphi, cosphi,
                          n_particle, n_sample, radius, wavelen,
                          volume_fraction)

    #################### check polarization magnitude is always 1
    pol_mag = np.sqrt(trajectories.polarization[0, :, :] *
                      np.conj(trajectories.polarization[0, :, :]) +
                      trajectories.polarization[1, :, :] *
                      np.conj(trajectories.polarization[1, :, :]) +
                      trajectories.polarization[2, :, :] *
                      np.conj(trajectories.polarization[2, :, :]))
    pol_mag_sum = np.sum(np.abs(pol_mag.magnitude))

    assert_equal(pol_mag_sum, nevents * ntrajectories)

    ############ check that polarization vector is perpendicular to direction
    # dot product is a dot conj(b), but b is real, so can just do a dot b
    dot = (
        trajectories.polarization[0, :, :] * trajectories.direction[0, :, :] +
        trajectories.polarization[1, :, :] * trajectories.direction[1, :, :] +
        trajectories.polarization[2, :, :] * trajectories.direction[2, :, :])

    dot_sum = np.sum(np.abs(dot.magnitude))

    assert_almost_equal(dot_sum, 0.0, decimal=12)
def test_find_max_like():
    wavelength = [450, 500, 550, 600]
    wavelength_ind = find_close_indices(wavelength_sigma,
                                        sc.Quantity(wavelength, 'nm'))
    sigma_test = sigma[np.array(wavelength_ind)]

    sample = Sample(wavelength, particle_index=1.59, matrix_index=1)
    theta = (0.55, 120, 120, 0.02, 0, 0.02, 0
             )  #these are the default starting values for lmfit calculation
    spect = calc_model_spect(sample,
                             theta, (sigma_test, sigma_test),
                             ntrajectories,
                             nevents,
                             seed=2)

    theta_range = {
        'min_phi': 0.34,
        'max_phi': 0.74,
        'min_radius': 70,
        'max_radius': 160,
        'min_thickness': 1,
        'max_thickness': 1000,
        'min_l0_r': 0,
        'max_l0_r': 1,
        'min_l1_r': -1,
        'max_l1_r': 1,
        'min_l0_t': 0,
        'max_l0_t': 1,
        'min_l1_t': -1,
        'max_l1_t': 1
    }
    theta_guess = {
        'phi': 0.55,
        'radius': 120,
        'thickness': 120,
        'l0_r': 0.02,
        'l1_r': 0,
        'l0_t': 0.02,
        'l1_t': 0
    }

    max_like_vals = find_max_like(spect,
                                  sample,
                                  theta_guess=theta_guess,
                                  theta_range=theta_range,
                                  sigma=(sigma_test, sigma_test),
                                  ntrajectories=ntrajectories,
                                  nevents=nevents,
                                  seed=2)
    assert_almost_equal(max_like_vals, theta)
Ejemplo n.º 10
0
def test_trajectories():
    # Initialize runs
    nevents = 2
    ntrajectories = 3
    r0, k0, W0 = mc.initialize(nevents,
                               ntrajectories,
                               n_medium,
                               n_sample,
                               'film',
                               seed=1)
    r0 = sc.Quantity(r0, 'um')
    k0 = sc.Quantity(k0, '')
    W0 = sc.Quantity(W0, '')

    # Create a Trajectory object
    trajectories = mc.Trajectory(r0, k0, W0)

    # Test the absorb function
    mu_abs = 1 / sc.Quantity(10, 'um')
    step = sc.Quantity(np.array([[1, 1, 1], [1, 1, 1]]), 'um')
    trajectories.absorb(mu_abs, step)
    assert_almost_equal(
        trajectories.weight,
        np.array([[0.90483742, 0.90483742, 0.90483742],
                  [0.81873075, 0.81873075, 0.81873075]]))

    # Make up some test theta and phi
    sintheta = np.array([[0., 0., 0.], [0., 0., 0.]])
    costheta = np.array([[-1., -1., -1.], [1., 1., 1.]])
    sinphi = np.array([[0., 0., 0.], [0., 0., 0.]])
    cosphi = np.array([[0., 0., 0.], [0., 0., 0.]])
    trajectories.scatter(sintheta, costheta, sinphi, cosphi)

    # Expected propagation directions
    kx = sc.Quantity(np.array([[0., 0., 0.], [0., 0., 0.]]), '')
    ky = sc.Quantity(np.array([[0., 0., 0.], [0., 0., 0.]]), '')
    kz = sc.Quantity(np.array([[1., 1., 1.], [-1., -1., -1.]]), '')

    # Test the scatter function
    assert_almost_equal(trajectories.direction[0], kx.magnitude)
    assert_almost_equal(trajectories.direction[1], ky.magnitude)
    assert_almost_equal(trajectories.direction[2], kz.magnitude)

    # Test the move function
    trajectories.move(step)
    assert_equal(trajectories.position[2],
                 np.array([[0, 0, 0], [1, 1, 1], [0, 0, 0]]))
Ejemplo n.º 11
0
def test_calc_model_spect():
    wavelength = [500]
    sample = Sample(wavelength, 1.5, 1)
    theta = (0.5, 100, 200, 0, 0, 0, 0)

    wavelength_ind = find_close_indices(wavelength_sigma,
                                        sc.Quantity(wavelength, 'nm'))
    sigma_test = sigma[np.array(wavelength_ind)]
    assert_frame_equal(
        calc_model_spect(sample, theta, (sigma_test, sigma_test),
                         ntrajectories, nevents, 2),
        Spectrum(500,
                 reflectance=0.828595524325,
                 sigma_r=0.0193369922424,
                 transmittance=0.171404475675,
                 sigma_t=0.0193369922424))
Ejemplo n.º 12
0
def test_log_posterior():
    wavelength = [500]
    spectrum = Spectrum(wavelength, reflectance=0.5, sigma_r=0.1)
    sample = Sample(wavelength, 1.5, 1)
    theta_range = {
        'min_phi': 0.35,
        'max_phi': 0.74,
        'min_radius': 70,
        'max_radius': 201,
        'min_thickness': 1,
        'max_thickness': 1000
    }
    wavelength_ind = find_close_indices(wavelength_sigma,
                                        sc.Quantity(wavelength, 'nm'))
    sigma_test = sigma[np.array(wavelength_ind)]

    # When parameters are within prior range
    theta1 = (0.5, 200, 200, 0, 0)
    post1 = log_posterior(theta1,
                          spectrum,
                          sample,
                          theta_range=theta_range,
                          sigma=(sigma_test, sigma_test),
                          ntrajectories=ntrajectories,
                          nevents=nevents,
                          seed=2)
    assert_approx_equal(post1, -6.0413752765269875)

    # When parameters are not within prior range
    theta2 = (0.3, 200, 200, 0, 0)
    post2 = log_posterior(theta2,
                          spectrum,
                          sample,
                          theta_range=theta_range,
                          sigma=(sigma_test, sigma_test),
                          ntrajectories=ntrajectories,
                          nevents=nevents,
                          seed=2)
    assert_approx_equal(post2, -1e100)
Ejemplo n.º 13
0
def test_run_structcol():
    # Test that structcol package is imported and reflectance calculation is correct
    import structcol as sc

    wavelength = np.array([400., 500.])
    particle_radius = 150.
    thickness = 100.
    particle_index = np.array([1.40, 1.41])
    matrix_index = np.array([1.0, 1.0])
    volume_fraction = 0.5
    incident_angle = 0.0
    medium_index = np.array([1.0, 1.0])
    front_index = np.array([1.0, 1.0])
    back_index = np.array([1.0, 1.0])

    wavelength_ind = find_close_indices(wavelength_sigma,
                                        sc.Quantity(wavelength, 'nm'))
    sigma_test = sigma[np.array(wavelength_ind)]

    refl, trans = calc_refl_trans(volume_fraction,
                                  particle_radius,
                                  thickness,
                                  Sample(wavelength, particle_index,
                                         matrix_index, medium_index,
                                         front_index, back_index,
                                         incident_angle),
                                  ntrajectories,
                                  nevents,
                                  seed=1)
    spectrum = Spectrum(wavelength,
                        reflectance=refl,
                        transmittance=trans,
                        sigma_r=sigma_test,
                        sigma_t=sigma_test)

    outarray = np.array([0.84576, 0.74796])
    assert_almost_equal(spectrum.reflectance, outarray, decimal=5)
Ejemplo n.º 14
0
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)
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)
Ejemplo n.º 16
0
def test_polarization():
    ntrajectories = 50
    nevents = 50
    n_particle = sc.Quantity(1.5, '')
    n_matrix = sc.Quantity(1.0, '')
    n_medium = sc.Quantity(1.0, '')
    n_sample = ri.n_eff(n_particle, n_matrix, volume_fraction)

    # run mc trajectories with polarization
    p, mu_scat, mu_abs = mc.calc_scat(radius,
                                      n_particle,
                                      n_sample,
                                      volume_fraction,
                                      wavelen,
                                      polarization=True)
    r0, k0, W0, p0 = mc.initialize(nevents,
                                   ntrajectories,
                                   n_medium,
                                   n_sample,
                                   'film',
                                   polarization=True)
    r0 = sc.Quantity(r0, 'um')
    k0 = sc.Quantity(k0, '')
    W0 = sc.Quantity(W0, '')
    p0 = sc.Quantity(p0, '')
    sintheta, costheta, sinphi, cosphi, theta, phi = mc.sample_angles(
        nevents, ntrajectories, p)
    trajectories = mc.Trajectory(r0, k0, W0, p0)
    trajectories.scatter(sintheta, costheta, sinphi, cosphi)
    trajectories.polarize(theta, phi, sintheta, costheta, sinphi, cosphi,
                          n_particle, n_sample, radius, wavelen,
                          volume_fraction)

    #################### check polarization magnitude is always 1
    pol_mag = np.sqrt(trajectories.polarization[0, :, :] *
                      np.conj(trajectories.polarization[0, :, :]) +
                      trajectories.polarization[1, :, :] *
                      np.conj(trajectories.polarization[1, :, :]) +
                      trajectories.polarization[2, :, :] *
                      np.conj(trajectories.polarization[2, :, :]))
    pol_mag_sum = np.sum(np.abs(pol_mag.magnitude))
    assert_almost_equal(pol_mag_sum, nevents * ntrajectories, decimal=10)

    ########### check that trajectories are becoming depolarized after many
    ########### scattering events

    # calculate polarization components at last events
    pol_x = np.mean(trajectories.polarization[0, -20:-1, :] *
                    np.conj(trajectories.polarization[0, -20:-1, :]))
    pol_y = np.mean(trajectories.polarization[1, -20:-1, :] *
                    np.conj(trajectories.polarization[1, -20:-1, :]))
    pol_z = np.mean(trajectories.polarization[2, -20:-1, :] *
                    np.conj(trajectories.polarization[2, -20:-1, :]))

    assert_almost_equal(pol_x.magnitude, 0.33, decimal=1)
    assert_almost_equal(pol_y.magnitude, 0.33, decimal=1)
    assert_almost_equal(pol_z.magnitude, 0.33, decimal=1)

    ############ check that polarization vector is perpendicular to direction
    # dot product is a dot conj(b), but b is real, so can just do a dot b
    dot = (
        trajectories.polarization[0, :, :] * trajectories.direction[0, :, :] +
        trajectories.polarization[1, :, :] * trajectories.direction[1, :, :] +
        trajectories.polarization[2, :, :] * trajectories.direction[2, :, :])

    dot_sum = np.sum(np.abs(dot.magnitude))

    assert_almost_equal(dot_sum, 0.0, decimal=10)
'''
This file tests functions from inference.py.
'''
import structcol as sc
from infer_structcol.inference import find_max_like, run_mcmc
from infer_structcol.main import Sample, Spectrum, find_close_indices
from infer_structcol.model import calc_model_spect
from numpy.testing import assert_equal, assert_almost_equal
import numpy as np

ntrajectories = 600
nevents = 200
wavelength_sigma = sc.Quantity(np.linspace(400, 1000, 61), 'nm')
sigma = np.array([
    1.860651421552072735e-02, 1.753980839818162357e-02,
    1.839622738704549398e-02, 1.596763386664768955e-02,
    1.894484659740078986e-02, 1.722962247665738716e-02,
    1.555134197251030123e-02, 1.763293909648367200e-02,
    2.027257609441594777e-02, 1.850550125238413501e-02,
    1.933699224240205058e-02, 1.873148138270526453e-02,
    1.908441182529240290e-02, 1.756355142274622708e-02,
    1.590192651066632198e-02, 1.596104976169695697e-02,
    2.024553310180053287e-02, 1.955488448380025140e-02,
    1.882008022078682577e-02, 1.796507064336797313e-02,
    2.004778422542081301e-02, 1.811040666898488388e-02,
    1.805909831464867776e-02, 1.810327867013098932e-02,
    1.516823124817042248e-02, 1.514314740128578328e-02,
    1.696441336804245872e-02, 1.677168419886158890e-02,
    1.132382672347467811e-02, 1.224676407793331805e-02,
    1.117690246951372202e-02, 1.241312684961146107e-02,
    1.326040920813134627e-02, 1.367716094293736952e-02,
Ejemplo n.º 18
0
def test_reflection_absorbing_particle_or_matrix():
    # test that the reflections with a real n_particle and with a complex
    # n_particle with a 0 imaginary component are the same
    seed = 1
    nevents = 60
    ntrajectories = 30

    # Reflection using non-absorbing particle
    R, T = calc_montecarlo(nevents, ntrajectories, radius, n_particle,
                           n_sample, n_medium, volume_fraction, wavelen, seed)

    # Reflection using particle with an imaginary component of 0
    n_particle_abs = sc.Quantity(1.5 + 0j, '')
    R_abs, T_abs = calc_montecarlo(nevents, ntrajectories, radius,
                                   n_particle_abs, n_sample, n_medium,
                                   volume_fraction, wavelen, seed)

    assert_equal(R, R_abs)
    assert_equal(T, T_abs)

    # Outputs before refactoring structcol
    R_before = 0.81382378303119451
    R_abs_before = 0.81382378303119451
    T_before = 0.1861762169688054
    T_abs_before = 0.1861762169688054

    assert_almost_equal(R_before, R, decimal=15)
    assert_almost_equal(R_abs_before, R_abs, decimal=15)
    assert_almost_equal(T_before, T, decimal=15)
    assert_almost_equal(T_abs_before, T_abs, decimal=15)

    # Same as previous test but with absorbing matrix
    # Reflection using matrix with an imaginary component of 0
    n_matrix_abs = sc.Quantity(1. + 0j, '')
    n_sample_abs = ri.n_eff(n_particle, n_matrix_abs, volume_fraction)
    R_abs, T_abs = calc_montecarlo(nevents, ntrajectories, radius, n_particle,
                                   n_sample_abs, n_medium, volume_fraction,
                                   wavelen, seed)

    assert_equal(R, R_abs)
    assert_equal(T, T_abs)

    # Outputs before refactoring structcol
    R_before = 0.81382378303119451
    R_abs_before = 0.81382378303119451
    T_before = 0.1861762169688054
    T_abs_before = 0.1861762169688054

    assert_almost_equal(R_before, R, decimal=15)
    assert_almost_equal(R_abs_before, R_abs, decimal=15)
    assert_almost_equal(T_before, T, decimal=15)
    assert_almost_equal(T_abs_before, T_abs, decimal=15)

    # test that the reflection is essentially the same when the imaginary
    # index is 0 or very close to 0
    n_matrix_abs = sc.Quantity(1. + 1e-10j, '')
    n_sample_abs = ri.n_eff(n_particle, n_matrix_abs, volume_fraction)
    R_abs, T_abs = calc_montecarlo(nevents, ntrajectories, radius, n_particle,
                                   n_sample_abs, n_medium, volume_fraction,
                                   wavelen, seed)
    assert_almost_equal(R, R_abs, decimal=6)
    assert_almost_equal(T, T_abs, decimal=6)
Ejemplo n.º 19
0
def test_reflection_polydispersity():
    seed = 1
    nevents = 60
    ntrajectories = 30

    radius2 = radius
    concentration = sc.Quantity(np.array([0.9, 0.1]), '')
    pdi = sc.Quantity(np.array([1e-7, 1e-7]), '')  # monodisperse limit

    # Without absorption: test that the reflectance using very small
    # polydispersity is the same as the monodisperse case
    R_mono, T_mono = calc_montecarlo(nevents,
                                     ntrajectories,
                                     radius,
                                     n_particle,
                                     n_sample,
                                     n_medium,
                                     volume_fraction,
                                     wavelen,
                                     seed,
                                     polydisperse=False)
    R_poly, T_poly = calc_montecarlo(nevents,
                                     ntrajectories,
                                     radius,
                                     n_particle,
                                     n_sample,
                                     n_medium,
                                     volume_fraction,
                                     wavelen,
                                     seed,
                                     radius2=radius2,
                                     concentration=concentration,
                                     pdi=pdi,
                                     polydisperse=True)

    assert_almost_equal(R_mono, R_poly)
    assert_almost_equal(T_mono, T_poly)

    # Outputs before refactoring structcol
    R_mono_before = 0.81382378303119451
    R_poly_before = 0.81382378303119451
    T_mono_before = 0.1861762169688054
    T_poly_before = 0.1861762169688054

    assert_almost_equal(R_mono_before, R_mono, decimal=15)
    assert_almost_equal(R_poly_before, R_poly, decimal=15)
    assert_almost_equal(T_mono_before, T_mono, decimal=15)
    assert_almost_equal(T_poly_before, T_poly, decimal=15)

    # With absorption: test that the reflectance using with very small
    # polydispersity is the same as the monodisperse case
    n_particle_abs = sc.Quantity(1.5 + 0.0001j, '')
    n_matrix_abs = sc.Quantity(1. + 0.0001j, '')
    n_sample_abs = ri.n_eff(n_particle_abs, n_matrix_abs, volume_fraction)

    R_mono_abs, T_mono_abs = calc_montecarlo(nevents,
                                             ntrajectories,
                                             radius,
                                             n_particle_abs,
                                             n_sample_abs,
                                             n_medium,
                                             volume_fraction,
                                             wavelen,
                                             seed,
                                             polydisperse=False)
    R_poly_abs, T_poly_abs = calc_montecarlo(nevents,
                                             ntrajectories,
                                             radius,
                                             n_particle_abs,
                                             n_sample_abs,
                                             n_medium,
                                             volume_fraction,
                                             wavelen,
                                             seed,
                                             radius2=radius2,
                                             concentration=concentration,
                                             pdi=pdi,
                                             polydisperse=True)

    assert_almost_equal(R_mono_abs, R_poly_abs, decimal=6)
    assert_almost_equal(T_mono_abs, T_poly_abs, decimal=6)

    # Outputs before refactoring structcol
    R_mono_abs_before = 0.6480185516058053  #A:0.6575973175344868 #A/V:0.74182070115289855
    R_poly_abs_before = 0.6476683654364985  #A:0.65723717422505701 #A/V:0.74153254583803685
    T_mono_abs_before = 0.09473841417422774  #A:0.080731949531112429 #A/V:0.083823525277616467
    T_poly_abs_before = 0.09456832138047852  #A:0.080574244683425236 #A/V:0.083720861809212316

    assert_almost_equal(R_mono_abs_before, R_mono_abs, decimal=3)
    assert_almost_equal(R_poly_abs_before, R_poly_abs, decimal=3)
    assert_almost_equal(T_mono_abs_before, T_mono_abs, decimal=3)
    assert_almost_equal(T_poly_abs_before, T_poly_abs, decimal=3)

    # test that the reflectance is the same for a polydisperse monospecies
    # and a bispecies with equal types of particles
    concentration_mono = sc.Quantity(np.array([0., 1.]), '')
    concentration_bi = sc.Quantity(np.array([0.3, 0.7]), '')
    pdi2 = sc.Quantity(np.array([1e-1, 1e-1]), '')

    R_mono2, T_mono2 = calc_montecarlo(nevents,
                                       ntrajectories,
                                       radius,
                                       n_particle,
                                       n_sample,
                                       n_medium,
                                       volume_fraction,
                                       wavelen,
                                       seed,
                                       radius2=radius2,
                                       concentration=concentration_mono,
                                       pdi=pdi2,
                                       polydisperse=True)
    R_bi, T_bi = calc_montecarlo(nevents,
                                 ntrajectories,
                                 radius,
                                 n_particle,
                                 n_sample,
                                 n_medium,
                                 volume_fraction,
                                 wavelen,
                                 seed,
                                 radius2=radius2,
                                 concentration=concentration_bi,
                                 pdi=pdi2,
                                 polydisperse=True)

    assert_equal(R_mono2, R_bi)
    assert_equal(T_mono2, T_bi)

    # test that the reflectance is the same regardless of the order in which
    # the radii are specified
    radius2 = sc.Quantity('70 nm')
    concentration2 = sc.Quantity(np.array([0.5, 0.5]), '')

    R, T = calc_montecarlo(nevents,
                           ntrajectories,
                           radius,
                           n_particle,
                           n_sample,
                           n_medium,
                           volume_fraction,
                           wavelen,
                           seed,
                           radius2=radius2,
                           concentration=concentration2,
                           pdi=pdi,
                           polydisperse=True)
    R2, T2 = calc_montecarlo(nevents,
                             ntrajectories,
                             radius2,
                             n_particle,
                             n_sample,
                             n_medium,
                             volume_fraction,
                             wavelen,
                             seed,
                             radius2=radius,
                             concentration=concentration2,
                             pdi=pdi,
                             polydisperse=True)

    assert_almost_equal(R, R2)
    assert_almost_equal(T, T2)

    # test that the second size is ignored when its concentration is set to 0
    radius1 = sc.Quantity('150 nm')
    radius2 = sc.Quantity('100 nm')
    concentration3 = sc.Quantity(np.array([1, 0]), '')
    pdi3 = sc.Quantity(np.array([0., 0.]), '')

    R3, T3 = calc_montecarlo(nevents,
                             ntrajectories,
                             radius1,
                             n_particle,
                             n_sample,
                             n_medium,
                             volume_fraction,
                             wavelen,
                             seed,
                             radius2=radius2,
                             concentration=concentration3,
                             pdi=pdi3,
                             polydisperse=True)

    assert_equal(R_mono, R3)
    assert_equal(T_mono, T3)
Ejemplo n.º 20
0
.. moduleauthor:: Anna B. Stephenson <*****@*****.**>
.. moduleauthor:: Vinothan N. Manoharan <*****@*****.**>
"""

import numpy as np
import structcol as sc
import structcol.refractive_index as ri
from structcol import montecarlo as mc
from structcol import detector as det
from structcol import phase_func_sphere as pfs
from numpy.testing import assert_equal, assert_almost_equal

### Set parameters ###

# Properties of source
wavelength = sc.Quantity(
    '600 nm')  # wavelengths at which to calculate reflectance

# Geometric properties of sample
particle_radius = sc.Quantity('0.130 um')  # radius of the sphere particles
volume_fraction_particles = sc.Quantity(
    0.6, '')  # volume fraction of the particles in the sphere boundary
volume_fraction_bulk = sc.Quantity(
    0.55, '')  # volume fraction of the spheres in the bulk film
sphere_boundary_diameter = sc.Quantity(10,
                                       'um')  # diameter of the sphere boundary
boundary = 'sphere'
boundary_bulk = 'film'

# Refractive indices
n_particle = ri.n('vacuum', wavelength)  # refractive index of particle
n_matrix = ri.n('polystyrene', wavelength)  # refractive index of matrix
Ejemplo n.º 21
0
def test_reflection_core_shell():
    # test that the reflection of a non-core-shell system is the same as that
    # of a core-shell with a shell index matched with the core
    seed = 1
    nevents = 60
    ntrajectories = 30

    # Reflection using a non-core-shell system
    R, T = calc_montecarlo(nevents, ntrajectories, radius, n_particle,
                           n_sample, n_medium, volume_fraction, wavelen, seed)

    # Reflection using core-shells with the shell index-matched to the core
    radius_cs = sc.Quantity(np.array(
        [100,
         150]), 'nm')  # specify the radii from innermost to outermost layer
    n_particle_cs = sc.Quantity(np.array(
        [1.5, 1.5]), '')  # specify the index from innermost to outermost layer

    # calculate the volume fractions of each layer
    vf_array = np.empty(len(radius_cs))
    r_array = np.array([0] + radius_cs.magnitude.tolist())
    for r in np.arange(len(r_array) - 1):
        vf_array[r] = (r_array[r + 1]**3 -
                       r_array[r]**3) / (r_array[-1:]**3) * volume_fraction

    n_sample_cs = ri.n_eff(n_particle_cs, n_matrix, vf_array)
    R_cs, T_cs = calc_montecarlo(nevents, ntrajectories, radius_cs,
                                 n_particle_cs, n_sample_cs, n_medium,
                                 volume_fraction, wavelen, seed)

    assert_almost_equal(R, R_cs)
    assert_almost_equal(T, T_cs)

    # Outputs before refactoring structcol
    R_before = 0.81382378303119451
    R_cs_before = 0.81382378303119451
    T_before = 0.1861762169688054
    T_cs_before = 0.1861762169688054

    assert_almost_equal(R_before, R, decimal=15)
    assert_almost_equal(R_cs_before, R_cs, decimal=15)
    assert_almost_equal(T_before, T, decimal=15)
    assert_almost_equal(T_cs_before, T_cs, decimal=15)

    # Test that the reflectance is the same for a core-shell that absorbs (with
    # the same refractive indices for all layers) and a non-core-shell that
    # absorbs with the same index
    # Reflection using a non-core-shell absorbing system
    n_particle_abs = sc.Quantity(1.5 + 0.001j, '')
    n_sample_abs = ri.n_eff(n_particle_abs, n_matrix, volume_fraction)

    R_abs, T_abs = calc_montecarlo(nevents, ntrajectories, radius,
                                   n_particle_abs, n_sample_abs, n_medium,
                                   volume_fraction, wavelen, seed)

    # Reflection using core-shells with the shell index-matched to the core
    n_particle_cs_abs = sc.Quantity(np.array([1.5 + 0.001j, 1.5 + 0.001j]), '')
    n_sample_cs_abs = ri.n_eff(n_particle_cs_abs, n_matrix, vf_array)

    R_cs_abs, T_cs_abs = calc_montecarlo(nevents, ntrajectories, radius_cs,
                                         n_particle_cs_abs, n_sample_cs_abs,
                                         n_medium, volume_fraction, wavelen,
                                         seed)

    assert_almost_equal(R_abs, R_cs_abs, decimal=6)
    assert_almost_equal(T_abs, T_cs_abs, decimal=6)

    # Outputs before refactoring structcol
    R_abs_before = 0.3956821177047554  #A:0.40749467236951037 #A/V:0.50534237684703909
    R_cs_abs_before = 0.39568211770416667  # A:0.4074946723689386 #A/V:0.50534237684642402
    T_abs_before = 0.009944245822685388  #A:0.0053095057615145302 #A/V:0.017215194324142709
    T_cs_abs_before = 0.009944245822595715  #A:0.0053095057614589471 #A/V:0.017215194324029608

    assert_almost_equal(R_abs_before, R_abs, decimal=3)
    assert_almost_equal(R_cs_abs_before, R_cs_abs, decimal=3)
    assert_almost_equal(T_abs_before, T_abs, decimal=3)
    assert_almost_equal(T_cs_abs_before, T_cs_abs, decimal=3)

    # Same as previous test but with absorbing matrix as well
    # Reflection using a non-core-shell absorbing system
    n_particle_abs = sc.Quantity(1.5 + 0.001j, '')
    n_matrix_abs = sc.Quantity(1. + 0.001j, '')
    n_sample_abs = ri.n_eff(n_particle_abs, n_matrix_abs, volume_fraction)

    R_abs, T_abs = calc_montecarlo(nevents, ntrajectories, radius,
                                   n_particle_abs, n_sample_abs, n_medium,
                                   volume_fraction, wavelen, seed)

    # Reflection using core-shells with the shell index-matched to the core
    n_particle_cs_abs = sc.Quantity(np.array([1.5 + 0.001j, 1.5 + 0.001j]), '')
    n_sample_cs_abs = ri.n_eff(n_particle_cs_abs, n_matrix_abs, vf_array)

    R_cs_abs, T_cs_abs = calc_montecarlo(nevents, ntrajectories, radius_cs,
                                         n_particle_cs_abs, n_sample_cs_abs,
                                         n_medium, volume_fraction, wavelen,
                                         seed)

    assert_almost_equal(R_abs, R_cs_abs, decimal=6)
    assert_almost_equal(T_abs, T_cs_abs, decimal=6)

    # Outputs before refactoring structcol
    R_abs_before = 0.27087005070007175  #A:0.29026980076407527 #A/V:0.37384878890851575
    R_cs_abs_before = 0.27087005070007175  #A:0.29026980076407527 #A/V:0.37384878890851575
    T_abs_before = 0.0006391960305096798  #A:0.0002140495990985143 #A/V:0.002180700021951509
    T_cs_abs_before = 0.0006391960305096798  #A:0.0002140495990985143 #A/V:0.002180700021951509

    assert_almost_equal(R_abs_before, R_abs, decimal=2)
    assert_almost_equal(R_cs_abs_before, R_cs_abs, decimal=2)
    assert_almost_equal(T_abs_before, T_abs, decimal=4)
    assert_almost_equal(T_cs_abs_before, T_cs_abs, decimal=4)
Ejemplo n.º 22
0
.. moduleauthor:: Victoria Hwang <*****@*****.**>
.. moduleauthor:: Vinothan N. Manoharan <*****@*****.**>
"""

import structcol as sc
from .. import montecarlo as mc
from .. import detector as det
from .. import refractive_index as ri
import numpy as np
from numpy.testing import assert_equal, assert_almost_equal
import pytest

# Define a system to be used for the tests
nevents = 3
ntrajectories = 4
radius = sc.Quantity('150 nm')
volume_fraction = 0.5
n_particle = sc.Quantity(1.5, '')
n_matrix = sc.Quantity(1.0, '')
n_medium = sc.Quantity(1.0, '')
n_sample = ri.n_eff(n_particle, n_matrix, volume_fraction)
angles = sc.Quantity(np.linspace(0.01, np.pi, 200), 'rad')
wavelen = sc.Quantity('400 nm')

# Index of the scattering event and trajectory corresponding to the reflected
# photons
refl_index = np.array([2, 0, 2])


def test_sampling():
    # Test that 'calc_scat' runs
Ejemplo n.º 23
0
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
Ejemplo n.º 24
0
def test_phase_function_absorbing_medium():
    # test that the phase function using the far-field Mie solutions
    # (mie.calc_ang_dist()) in an absorbing medium is the same as the phase
    # function using the Mie solutions with the asymptotic form of the spherical
    # Hankel functions but using a complex k (mie.diff_scat_intensity_complex_medium()
    # with near_fields=False)
    wavelen = sc.Quantity('550 nm')
    radius = sc.Quantity('105 nm')
    n_matrix = sc.Quantity(1.47 + 0.001j, '')
    n_particle = sc.Quantity(1.5 + 1e-1 * 1.0j, '')
    m = index_ratio(n_particle, n_matrix)
    x = size_parameter(wavelen, n_matrix, radius)
    k = 2 * np.pi * n_matrix / wavelen
    ksquared = np.abs(k)**2

    ## Integrating at the surface of the particle
    # with mie.calc_ang_dist() (this is how it's currently implemented in
    # monte carlo)
    diff_cscat_par_ff, diff_cscat_perp_ff = \
        model.differential_cross_section(m, x, angles, volume_fraction,
                                         structure_type='glass',
                                         form_type='sphere',
                                         diameters=radius, wavelen=wavelen,
                                         n_matrix=n_sample, k=None, distance=radius)
    cscat_total_par_ff = model._integrate_cross_section(
        diff_cscat_par_ff, 1.0 / ksquared, angles)
    cscat_total_perp_ff = model._integrate_cross_section(
        diff_cscat_perp_ff, 1.0 / ksquared, angles)
    cscat_total_ff = (cscat_total_par_ff + cscat_total_perp_ff) / 2.0

    p_ff = (diff_cscat_par_ff + diff_cscat_perp_ff) / (ksquared * 2 *
                                                       cscat_total_ff)
    p_par_ff = diff_cscat_par_ff / (ksquared * 2 * cscat_total_par_ff)
    p_perp_ff = diff_cscat_perp_ff / (ksquared * 2 * cscat_total_perp_ff)

    # with mie.diff_scat_intensity_complex_medium()
    diff_cscat_par, diff_cscat_perp = \
        model.differential_cross_section(m, x, angles, volume_fraction,
                                         structure_type='glass',
                                         form_type='sphere',
                                         diameters=radius, wavelen=wavelen,
                                         n_matrix=n_sample, k=k, distance=radius)
    cscat_total_par = model._integrate_cross_section(diff_cscat_par,
                                                     1.0 / ksquared, angles)
    cscat_total_perp = model._integrate_cross_section(diff_cscat_perp,
                                                      1.0 / ksquared, angles)
    cscat_total = (cscat_total_par + cscat_total_perp) / 2.0

    p = (diff_cscat_par + diff_cscat_perp) / (ksquared * 2 * cscat_total)
    p_par = diff_cscat_par / (ksquared * 2 * cscat_total_par)
    p_perp = diff_cscat_perp / (ksquared * 2 * cscat_total_perp)

    # test random values of the phase functions
    assert_almost_equal(p_ff[3], p[3], decimal=15)
    assert_almost_equal(p_par_ff[50], p_par[50], decimal=15)
    assert_almost_equal(p_perp[83], p_perp_ff[83], decimal=15)

    ### Same thing but with a binary and polydisperse mixture
    ## Integrating at the surface of the particle
    # with mie.calc_ang_dist() (this is how it's currently implemented in
    # monte carlo)
    radius2 = sc.Quantity('150 nm')
    concentration = sc.Quantity(np.array([0.2, 0.7]), '')
    pdi = sc.Quantity(np.array([0.1, 0.1]), '')
    diameters = sc.Quantity(
        np.array([radius.magnitude, radius2.magnitude]) * 2, radius.units)

    diff_cscat_par_ff, diff_cscat_perp_ff = \
        model.differential_cross_section(m, x, angles, volume_fraction,
                                         structure_type='polydisperse',
                                         form_type='polydisperse',
                                         diameters=diameters, pdi=pdi,
                                         concentration=concentration, wavelen=wavelen,
                                         n_matrix=n_sample, k=None, distance=diameters/2)
    cscat_total_par_ff = model._integrate_cross_section(
        diff_cscat_par_ff, 1.0 / ksquared, angles)
    cscat_total_perp_ff = model._integrate_cross_section(
        diff_cscat_perp_ff, 1.0 / ksquared, angles)
    cscat_total_ff = (cscat_total_par_ff + cscat_total_perp_ff) / 2.0

    p_ff2 = (diff_cscat_par_ff + diff_cscat_perp_ff) / (ksquared * 2 *
                                                        cscat_total_ff)
    p_par_ff2 = diff_cscat_par_ff / (ksquared * 2 * cscat_total_par_ff)
    p_perp_ff2 = diff_cscat_perp_ff / (ksquared * 2 * cscat_total_perp_ff)

    # with mie.diff_scat_intensity_complex_medium()
    diff_cscat_par, diff_cscat_perp = \
        model.differential_cross_section(m, x, angles, volume_fraction,
                                         structure_type='polydisperse',
                                         form_type='polydisperse',
                                         diameters=diameters, pdi=pdi,
                                         concentration=concentration, wavelen=wavelen,
                                         n_matrix=n_sample, k=k, distance=diameters/2)
    cscat_total_par = model._integrate_cross_section(diff_cscat_par,
                                                     1.0 / ksquared, angles)
    cscat_total_perp = model._integrate_cross_section(diff_cscat_perp,
                                                      1.0 / ksquared, angles)
    cscat_total = (cscat_total_par + cscat_total_perp) / 2.0

    p2 = (diff_cscat_par + diff_cscat_perp) / (ksquared * 2 * cscat_total)
    p_par2 = diff_cscat_par / (ksquared * 2 * cscat_total_par)
    p_perp2 = diff_cscat_perp / (ksquared * 2 * cscat_total_perp)

    # test random values of the phase functions
    assert_almost_equal(p_ff2[3], p2[3], decimal=15)
    assert_almost_equal(p_par_ff2[50], p_par2[50], decimal=15)
    assert_almost_equal(p_perp2[83], p_perp_ff2[83], decimal=15)
"""

import structcol as sc
from structcol import montecarlo as mc
from structcol import refractive_index as ri
from structcol import event_distribution as ed
from structcol import detector as det
import numpy as np
from numpy.testing import assert_equal, assert_almost_equal, assert_array_less

# Monte Carlo parameters
ntrajectories = 30  # number of trajectories
nevents = 300  # number of scattering events in each trajectory

# source/detector properties
wavelength = sc.Quantity(np.array(550),
                         'nm')  # wavelength at which to run simulation

# sample properties
particle_radius = sc.Quantity('140 nm')  # radius of the particles
volume_fraction = sc.Quantity(0.56, '')  # volume fraction of particles
thickness = sc.Quantity('10 um')
particle = 'ps'
matrix = 'air'
boundary = 'film'

# indices of refraction
n_particle = ri.n(
    'polystyrene',
    wavelength)  # refractive indices can be specified as pint quantities or
n_matrix = ri.n(
    'vacuum',
def calc_sigma(volume_fraction,
               radius,
               thickness,
               Sample,
               ntrajectories,
               nevents,
               run_num=100,
               plot=True,
               seed=None):
    """
    Calculates the standard deviation of the multiple scattering calculations
    by running the multiple scattering code run_num times.

    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
    run_num : int or 100
        number of runs from which to calculate the standard deviation
    plot : boolean 
        If True, plot of the theoretical reflectance and transmittance uncertainties
    seed : int or None
        If seed is int, the simulation results will be reproducible. If seed is
        None, the simulation results are  random.
    
    Returns
    ----------
    sigma_r : ndarray
        standard deviation of the reflectance calculation
    sigma_t : ndarray
        standard deviation of the transmittance calculation
        
    """
    wavelength = sc.Quantity(Sample.wavelength, 'nm')

    reflectance = np.zeros([run_num, len(wavelength)])
    transmittance = np.zeros([run_num, len(wavelength)])
    for n in np.arange(run_num):
        reflectance[n, :], transmittance[n, :] = calc_refl_trans(
            volume_fraction, radius, thickness, Sample, ntrajectories, nevents,
            seed)

    # Calculate mean and standard deviations of reflectance and transmittance
    sigma_r = np.std(reflectance, axis=0) * np.sqrt(
        len(wavelength) / (len(wavelength) - 1))
    sigma_t = np.std(transmittance, axis=0) * np.sqrt(
        len(wavelength) / (len(wavelength) - 1))
    mean_r = np.mean(reflectance, axis=0)
    mean_t = np.mean(transmittance, axis=0)

    #np.savetxt(os.path.join(os.getcwd(),'sigma.txt'), np.array([sigma_R, sigma_T]).T)

    if plot == True:
        # Plot the mean and standard deviations
        fig, (ax_r, ax_t) = plt.subplots(2, figsize=(8, 10))
        ax_r.set(ylabel='Reflectance')
        ax_t.set(ylabel='Transmittance')
        ax_t.set(xlabel='Wavelength (nm)')
        ax_r.errorbar(wavelength.magnitude, mean_r, yerr=sigma_r, fmt='.')
        ax_t.errorbar(wavelength.magnitude, mean_t, yerr=sigma_t, fmt='.')
        ax_r.set(
            title=
            'Theoretical reflectance and transmittance +/- 1 standard deviation'
        )

    return (sigma_r, sigma_t)