def test_p11():
    '''
    Test to plot a phase function, and make sure it is normalized properly
    '''
    
    alam = 500*u.nm
    r = 10*u.micron
    x = (2*math.pi * r / alam).to('1').value
    

    num_theta = 1000
    theta = hbt.frange(0,math.pi, num_theta)
    p11 = np.zeros(num_theta)
    
    phase = math.pi - theta      # Theta is scattering angle
    
    nm_refract = complex(1.5, 0.1)
    mie = Mie(x=x, m=nm_refract)  # This is only for one x value, not an ensemble

    qext = mie.qext()
    qsca = mie.qsca()
    qbak = mie.qb()

    for i,theta_i in enumerate(theta):
        (S1, S2)  = mie.S12(np.cos(theta_i)) # Looking at code, S12 returns tuple (S1, S2). S3, S4 are zero for sphere.
        k = 2*pi / alam
        sigma = pi * r**2 * qsca             # For (S1,S2) -> P11: p. 2 of http://nit.colorado.edu/atoc5560/week8.pdf
                                             # qsca = scattering efficiency. sigma = scattering cross-section 
        p11[i]  = 4 * pi / (k**2 * sigma) * ( (np.abs(S1))**2 + (np.abs(S2))**2) / 2
                   
    # Check the normalization of the resulting phase function.

    dtheta = theta[1] - theta[0]
    
    norm = np.sum(p11 * np.sin(theta) * dtheta)  # This should be 2, as per TPW04 eq. 4
    
    print('Normalized integral = {:.2f}'.format(norm))
    
    plt.plot(phase*hbt.r2d, p11)
    plt.yscale('log')
    plt.title('X = {:.1f}'.format(x))
    plt.xlabel('Phase angle')
    plt.ylabel('$P_{11}$')
    plt.show()
    
    p = plt.plot([0,10], [0,10])
    currentAxis = plt.gca()
    currentAxis.add_patch(Rectangle((0.5, 0.5), 0.7, 0.7,alpha=0.1, color='red'))
    plt.text(1, 1, 'Danger')
    plt.show()
    
Exemple #2
0
    #d_new = a_eff / 10
    r *= (d_new / d_old)
    d_old = d_new

    # incident plane wave
    Ei = E_inc(E0, kvec, r)  # direct incident field at dipoles

    alph = polarizability_LDR(d_new, m, kvec)  # polarizability of dipoles

    A = interaction_A(k, r, alph)
    P = scipy.sparse.linalg.gmres(A, Ei)[0]

    Cext[ix] = C_ext(k, E0, Ei, P) * (lam / 100)**2 / 100  # Convert to um**2

    mie = Mie(x=2 * np.pi * a_eff, m=n)
    Cext_mie[ix] = mie.qext() * np.pi * (a_eff / 2)**2  # Convert cross section
    del (A)

evlukhin = spec.Spec.loadSpecFromASCII("./reference/sphere_r63nm.txt", ',')

#Cext = numpy.divide(Cext, numpy.max(Cext))
#Cext_mie = numpy.divide(Cext_mie, numpy.max(Cext_mie))
#evlukhin.data = numpy.divide(evlukhin.data, numpy.max(evlukhin.data))

plt.figure(1)
plt.plot(lambda_range, Cext)
plt.plot(evlukhin.wavelengths, evlukhin.data)
plt.plot(lambda_range, Cext_mie)
plt.ylabel("$\sigma_{ext}$,  $\mu$m$^2$")
plt.xlabel("wavelength,  nm")
plt.legend(['PyDDA', 'Evlukhin', 'Mie theory'])
Exemple #3
0
# create excitation   
polarisation = np.array([1,0,0])
direction = np.array([0,0,1])
import mnpbempp.simulation.planewave.excitation
exc = mnpbempp.simulation.planewave.excitation.exc( polarisation, direction) 

# loop over energies
for j in range(0,n):
  j  
  # solve with given excitation and wavelength
  sig = bem.solve( enei[j], exc( p, enei[j] ) )
  # compute extinction
  ext[j] = exc.ext( sig )
## plot solution and compare with mie solution  
from pymiecoated import Mie
#radius of sphere
R = 75
xs = 2*np.pi*R/enei

ext_mie = np.array(ene, float)
for imie in range(n):

    mie = Mie(x=xs[imie],eps=epstab[1](enei[imie]))
    ext_mie[imie]=mie.qext()
#from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
#%matplotlib qt
#plt.plot( ene, ext,'ro', ene, ext_mie , 'b' )
plt.plot(ene,ext/(1239.8*8*np.pi),'ro',ene,ext_mie,'b')
# Calc Q_ext *or* Q_sca, based on whether it's reflected or transmitted light
 
n_refract = 1.33
m_refract = -0.001
nm_refract = complex(n_refract,m_refract)
x = (2*pi * r/alam).to('1').value
   
print('Doing Mie code')

# Mie code doesn't compute the phase function unless we ask it to, by passing dqv.
 
if DO_MIE:
    for i,x_i in enumerate(x):  # Loop over particle size X, and get Q and P_11 for each size
        mie = Mie(x=x_i, m=nm_refract)  # This is only for one x value, not an ensemble
        qext[i] = mie.qext()
        qsca[i] = mie.qsca()
        qbak[i] = mie.qb()  
      
        (S1, S2)  = mie.S12(np.cos(pi*u.rad - phase)) # Looking at code, S12 returns tuple (S1, S2).
                                                             # For a sphere, S3 and S4 are zero.
                                                             # Argument to S12() is scattering angle theta, not phase
        k = 2*pi / alam
      
        sigma = pi * r[i]**2 * qsca[i] # Just a guess here
      
# Now convert from S1 and S2, to P11: Use p. 2 of http://nit.colorado.edu/atoc5560/week8.pdf
      
        p11_mie[i]  = 4 * pi / (k**2 * sigma) * ( (np.abs(S1))**2 + (np.abs(S2))**2) / 2
       
# Now assume a I/F = 1. For the current size dist, if I/F = 1, then what # of impacts will we have?
Exemple #5
0
def scatter_mie_ensemble(nm_refract, n, r, ang_phase, alam, do_plot=False):
    
    """ 
    Return the Mie scattering properties of an ensemble of particles.
    
    The size distribution may be any arbitrary n(r).
    
    The returned phase function is properly normalized s.t. \\int(0 .. pi) {P sin(alpha) d_alpha} = 2.
    
    Calculated using pymiecoated library. That library supports coated grains, but my functions do not.
    
    Parameters
    ------

    nm_refract:
        Index of refraction. Complex. Imaginary component is typically positive, not negative.
    n:
        Particle number distribution.
    r: 
        Particle size distribution. Astropy units.
    ang_phase: 
        Scattering phase angle (array).
    alam: 
        Wavelength. Astropy units.
        
    Return values
    ----
    phase:
        Summed phase curve -- ie, P11 * n * pi * r^2 * qsca, summed. Array [num_angles]
    qsca:
        Scattering matrix. Array [num_radii]. Usually not needed.        
    p11_out:
        Phase curve. Not summed. Array [num_angles, num_radii]. Usually not needed.
        
    """
    
    num_r = len(n)
    num_ang = len(ang_phase)
    
    pi = math.pi
        
    k = 2*pi / alam
    
    qmie = np.zeros(num_r)
    qsca = np.zeros(num_r)
    qext = np.zeros(num_r)
    qbak = np.zeros(num_r)
    qabs = np.zeros(num_r)
    
    p11_mie  = np.zeros((num_r, num_ang))
    
    # Calc Q_ext *or* Q_sca, based on whether it's reflected or transmitted light
     
    x = (2*pi * r/alam).to('1').value
       
    print('Doing Mie code')
    
    # Mie code doesn't compute the phase function unless we ask it to, by passing dqv.
     
    for i,x_i in enumerate(x):
        mie = Mie(x=x_i, m=nm_refract)  # This is only for one x value, not an ensemble
        qext[i] = mie.qext()
        qsca[i] = mie.qsca()
        qbak[i] = mie.qb()  
    
        for j, ang_j in enumerate(ang_phase):
      
            (S1, S2)  = mie.S12(np.cos(pi*u.rad - ang_j)) # Looking at code, S12 returns tuple (S1, S2).
                                                             # For a sphere, S3 and S4 are zero.
                                                             # Argument to S12() is scattering angle theta, not phase
      
            sigma = pi * r[i]**2 * qsca[i]
      
       # Now convert from S1 and S2, to P11: Use p. 2 of http://nit.colorado.edu/atoc5560/week8.pdf
      
            p11_mie[i, j]  = 4 * pi / (k**2 * sigma) * ( (np.abs(S1))**2 + (np.abs(S2))**2) / 2
       
    if (do_plot):
        for i, x_i in enumerate(x):
            plt.plot(ang_phase.to('deg'), p11_mie[i, :], label = 'X = {:.1f}'.format(x_i))
        plt.title("P11, nm = {}".format(nm_refract))
        plt.yscale('log')
#        plt.legend(loc='upper left')
        plt.xlabel('Phase Angle [deg]')
        plt.title('P11')
        plt.show()

        for i, x_i in enumerate(x):
            plt.plot(ang_phase.to('deg'), p11_mie[i, :] * n[i] * r[i]**2, label = 'X = {:.1f}'.format(x_i))
        plt.title("P11 * n(r) * r^2, nm = {}".format(nm_refract))
        plt.yscale('log')
#        plt.legend(loc='upper left')
        plt.xlabel('Phase Angle [deg]')

        plt.show()
    
    
    # Multiply by the size dist, and flatten the array and return just showing the angular dependence.
    #      I(theta) = n(r) pi r^2 Q_sca P_11(theta)

    terms = np.transpose(np.tile(pi * n * r**2 * qsca, (num_ang,1)))
    
    phase_out = np.sum(p11_mie * terms, axis=0)
    
    # Remove any units from this
    
    phase_out = phase_out.value

    # Now normalize it. We want \int (0 .. pi) {P(alpha) sin(alpha) d_alpha} = 2
    # The accuracy of the normalized result will depend on how many angular bins are used.
    # This normalization is 
    
    d_ang = ang_phase - np.roll(ang_phase,1)
    d_ang[0] = 0
    tot = np.sum(phase_out * np.sin(ang_phase) * d_ang.value)
                                                
    phase_out = phase_out * 2 / tot
    
    # Return everything
    
    return(phase_out, p11_mie, qsca)
Exemple #6
0
def main():

    # Read in the mass data for 2016
    # Read in RH data for 2016
    # convert gases and such into the aerosol particles
    # swell the particles based on the CLASSIC scheme stuff
    # use Mie code to calculate the backscatter and extinction
    # calculate lidar ratio
    # plot lidar ratio

    # ==============================================================================
    # Setup
    # ==============================================================================

    # which modelled data to read in
    model_type = 'UKV'

    # directories
    maindir = '/home/nerc/Documents/MieScatt/'
    datadir = '/home/nerc/Documents/MieScatt/data/'

    savedir = maindir + 'figures/LidarRatio/'

    # data
    wxtdatadir = datadir
    massdatadir = datadir
    ffoc_gfdir = datadir

    # RH data
    wxt_inst_site = 'WXT_KSSW'

    # data year
    year = '2016'

    # aerosol particles to calculate (OC = Organic carbon, CBLK = black carbon, both already measured)
    # match dictionary keys further down
    aer_particles = ['(NH4)2SO4', 'NH4NO3', 'NaCl', 'CORG', 'CBLK']

    all_species = ['(NH4)2SO4', 'NH4NO3', 'NaCl', 'CORG', 'CBLK', 'H2O']
    # aer names in the complex index of refraction files
    aer_names = {
        '(NH4)2SO4': 'Ammonium sulphate',
        'NH4NO3': 'Ammonium nitrate',
        'CORG': 'Organic carbon',
        'NaCl': 'Generic NaCl',
        'CBLK': 'Soot',
        'MURK': 'MURK'
    }

    # density of molecules [kg m-3]
    # CBLK: # Zhang et al., (2016) Measuring the morphology and density of internally mixed black carbon
    #           with SP2 and VTDMA: New insight into the absorption enhancement of black carbon in the atmosphere
    # ORG: Range of densities for organic carbon is mass (0.625 - 2 g cm-3)
    #  Haywood et al 2003 used 1.35 g cm-3 but Schkolink et al., 2006 claim the average is 1.1 g cm-3 after a lit review
    aer_density = {
        '(NH4)2SO4': 1770.0,
        'NH4NO3': 1720.0,
        'NaCl': 2160.0,
        'CORG': 1100.0,
        'CBLK': 1200.0
    }

    # Organic carbon growth curve (Assumed to be the same as aged fossil fuel organic carbon

    # pure water density
    water_density = 1000.0  # kg m-3

    # wavelength to aim for
    ceil_lambda = [0.905e-06]

    # ==============================================================================
    # Read data
    # ==============================================================================

    # read in the complex index of refraction data for the aerosol species (can include water)
    n_species = read_n_data(aer_particles, aer_names, ceil_lambda, getH2O=True)

    # Read in physical growth factors (GF) for organic carbon (assumed to be the same as aged fossil fuel OC)
    gf_ffoc_raw = eu.csv_read(ffoc_gfdir + 'GF_fossilFuelOC_calcS.csv')
    gf_ffoc_raw = np.array(gf_ffoc_raw)[1:, :]  # skip header

    gf_ffoc = {
        'RH_frac': np.array(gf_ffoc_raw[:, 0], dtype=float),
        'GF': np.array(gf_ffoc_raw[:, 1], dtype=float)
    }

    # Read in species by mass data
    # Units are grams m-3
    mass_in = read_mass_data(massdatadir, year)

    # Read WXT data
    wxtfilepath = wxtdatadir + wxt_inst_site + '_' + year + '_15min.nc'
    WXT_in = eu.netCDF_read(wxtfilepath, vars=['RH', 'Tair', 'press', 'time'])
    WXT_in['RH_frac'] = WXT_in['RH'] * 0.01
    WXT_in['time'] -= dt.timedelta(
        minutes=15
    )  # change time from 'obs end' to 'start of obs', same as the other datasets

    # Trim times
    # as WXT and mass data are 15 mins and both line up exactly already
    #   therefore trim WXT to match mass time
    mass_in, WXT_in = trim_mass_wxt_times(mass_in, WXT_in)

    # Time match so mass and WXT times line up INTERNALLY as well
    date_range = eu.date_range(WXT_in['time'][0], WXT_in['time'][-1], 15,
                               'minutes')

    # make sure there are no time stamp gaps in the data so mass and WXT will match up perfectly, timewise.
    print 'beginning time matching for WXT...'
    WXT = internal_time_completion(WXT_in, date_range)
    print 'end time matching for WXT...'

    # same but for mass data
    print 'beginning time matching for mass...'
    mass = internal_time_completion(mass_in, date_range)
    print 'end time matching for mass...'

    # Create idealised number distribution for now... (dry distribution)
    # idealised dist is equal for all particle types for now.
    step = 0.005
    r_range_um = np.arange(0.000 + step, 5.000 + step, step)
    r_range_m = r_range_um * 1.0e-06

    r_mean = 0.11e-06
    sigma = 0

    # ==============================================================================
    # Process data
    # ==============================================================================

    # molecular mass of each molecule
    mol_mass_amm_sulp = 132
    mol_mass_amm_nit = 80
    mol_mass_nh4 = 18
    mol_mass_n03 = 62
    mol_mass_s04 = 96

    # Convert into moles
    # calculate number of moles (mass [g] / molar mass)
    # 1e-06 converts from micrograms to grams.
    moles = {
        'SO4': mass['SO4'] / mol_mass_s04,
        'NO3': mass['NO3'] / mol_mass_n03,
        'NH4': mass['NH4'] / mol_mass_nh4
    }

    # calculate ammonium sulphate and ammonium nitrate from gases
    # adds entries to the existing dictionary
    mass = calc_amm_sulph_and_amm_nit_from_gases(moles, mass)

    # convert chlorine into sea salt assuming all chlorine is sea salt, and enough sodium is present.
    #      potentially weak assumption for the chlorine bit due to chlorine depletion!
    mass['NaCl'] = mass['CL'] * 1.65

    # convert masses from g m-3 to kg kg-1_air for swelling.
    # Also creates the air density and is stored in WXT
    mass_kg_kg, WXT = convert_mass_to_kg_kg(mass, WXT, aer_particles)

    # start with just 0.11 microns as the radius - can make it more fancy later...
    r_d_microns = 0.11  # [microns]
    r_d_m = r_d_microns * 1.0e-6  # [m]

    # calculate the number of particles for each species using radius_m and the mass
    # Hopefull not needed!
    num_part = {}
    for aer_i in aer_particles:
        num_part[aer_i] = mass_kg_kg[aer_i] / (
            (4.0 / 3.0) * np.pi * (aer_density[aer_i] / WXT['dryair_rho']) *
            (r_d_m**3.0))

    # calculate dry volume
    V_dry_from_mass = {}
    for aer_i in aer_particles:
        # V_dry[aer_i] = (4.0/3.0) * np.pi * (r_d_m ** 3.0)
        V_dry_from_mass[aer_i] = mass_kg_kg[aer_i] / aer_density[aer_i]  # [m3]

        # if np.nan (i.e. there was no mass therefore no volume) make it 0.0
        bin = np.isnan(V_dry_from_mass[aer_i])
        V_dry_from_mass[aer_i][bin] = 0.0

    # ---------------------------------------------------------
    # Swell the particles (r_md,aer_i) [microns]

    # set up dictionary
    r_md = {}

    # calculate the swollen particle size for these three aerosol types
    # Follows CLASSIC guidence, based off of Fitzgerald (1975)
    for aer_i in ['(NH4)2SO4', 'NH4NO3', 'NaCl']:
        r_md[aer_i] = calc_r_md_species(r_d_microns, WXT, aer_i)

    # set r_md for black carbon as r_d, assuming black carbon is completely hydrophobic
    r_md['CBLK'] = np.empty(len(date_range))
    r_md['CBLK'][:] = r_d_microns

    # calculate r_md for organic carbon using the MO empirically fitted g(RH) curves
    r_md['CORG'] = np.empty(len(date_range))
    r_md['CORG'][:] = np.nan
    for t, time_t in enumerate(date_range):

        _, idx, _ = eu.nearest(gf_ffoc['RH_frac'], WXT['RH_frac'][t])
        r_md['CORG'][t] = r_d_microns * gf_ffoc['GF'][idx]

    # -----------------------------------------------------------

    # calculate abs volume of wetted particles (V_abs,wet,aer_i)
    # use the growth factors calculated based on r_d to calc V_wet from V_dry(mass, density)

    # calculate the physical growth factor, wetted particle density, wetted particle volume, ...
    #   and water volume (V_wet - Vdry)

    GF = {}
    # aer_wet_density = {}
    V_wet_from_mass = {}
    V_water_i = {}
    for aer_i in aer_particles:  # aer_particles:

        # physical growth factor
        GF[aer_i] = r_md[aer_i] / r_d_microns

        # # wet aerosol density
        # aer_wet_density[aer_i] = (aer_density[aer_i] / (GF[aer_i]**3.0)) + \
        #                          (water_density * (1.0 - (1.0 / (GF[aer_i]**3.0))))

        # wet volume, using the growth rate from r_d to r_md
        # if np.nan (i.e. there was no mass therefore no volume) make it 0.0
        V_wet_from_mass[aer_i] = V_dry_from_mass[aer_i] * (GF[aer_i]**3.0)
        bin = np.isnan(V_wet_from_mass[aer_i])
        V_wet_from_mass[aer_i][bin] = 0.0

        # water volume contribution from just this aer_i
        V_water_i[aer_i] = V_wet_from_mass[aer_i] - V_dry_from_mass[aer_i]

    # ---------------------------
    # Calculate relative volume of all aerosol AND WATER (to help calculate n_mixed)

    # calculate total water volume
    V_water_2d = np.array(V_water_i.values(
    ))  # turn into a 2D array (does not matter column order)
    V_water_tot = np.nansum(V_water_2d, axis=0)

    # combine volumes of the DRY aerosol and the water into a single 2d array shape=(time, substance)
    # V_abs = np.transpose(np.vstack([np.array(V_dry_from_mass.values()),V_water_tot]))
    # shape = (time, species)
    V_abs = np.transpose(
        np.vstack([
            np.array([V_dry_from_mass[i] for i in aer_particles]), V_water_tot
        ]))

    # now calculate the relative volume of each of these (V_rel)
    # scale absolute volume to find relative volume of each (such that sum(all substances for time t = 1))
    vol_sum = np.nansum(V_abs, axis=1)
    vol_sum[vol_sum == 0.0] = np.nan
    scaler = 1.0 / (vol_sum)  # a value for each time step

    # if there is no mass data for time t, and therefore no volume data, then set scaler to np.nan
    bin = np.isinf(scaler)
    scaler[bin] = np.nan

    # Relative volumes
    V_rel = {'H2O': scaler * V_water_tot}
    for aer_i in aer_particles:
        V_rel[aer_i] = scaler * V_dry_from_mass[aer_i]

    # --------------------------------------------------------------
    # Calculate relative volume of the swollen aerosol (to weight and calculate r_md)

    # V_wet_from_mass
    V_abs_aer_only = np.transpose(
        np.array([V_wet_from_mass[aer_i] for aer_i in aer_particles]))

    # now calculate the relative volume of each of these (V_rel_Aer_only)
    # scale absolute volume to find relative volume of each (such that sum(all substances for time t = 1))
    vol_sum_aer_only = np.nansum(V_abs_aer_only, axis=1)
    vol_sum_aer_only[vol_sum_aer_only == 0.0] = np.nan
    scaler = 1.0 / (vol_sum_aer_only)  # a value for each time step

    # if there is no mass data for time t, and therefore no volume data, then set scaler to np.nan
    bin = np.isinf(scaler)
    scaler[bin] = np.nan

    # Relative volumes
    V_rel_aer_only = {}
    for aer_i in aer_particles:
        V_rel_aer_only[aer_i] = scaler * V_wet_from_mass[aer_i]

    # for aer_i in aer_particles:
    #      print aer_i
    #      print V_rel[aer_i][-1]

    # --------------------------------------------------------------

    # calculate n_mixed using volume mixing method
    # volume mixing for CIR (eq. 12, Liu and Daum 2008)

    n_mixed = np.array([V_rel[i] * n_species[i] for i in V_rel.iterkeys()])
    n_mixed = np.sum(n_mixed, axis=0)

    # calculate volume mean radii from r_md,aer_i (weighted by V_rel,wet,aer_i)
    r_md_avg = np.array(
        [V_rel_aer_only[aer_i] * r_md[aer_i] for aer_i in aer_particles])
    r_md_avg = np.nansum(r_md_avg, axis=0)
    r_md_avg[r_md_avg == 0.0] = np.nan

    # convert from microns to m
    r_md_avg_m = r_md_avg * 1e-6

    # calculate the size parameter for the average aerosol size
    x_wet_mixed = (2.0 * np.pi * r_md_avg_m) / ceil_lambda[0]

    # --------------------------

    # calculate Q_back and Q_ext from the avergae r_md and n_mixed
    S = np.empty(len(date_range))
    S[:] = np.nan
    for t, time_t in enumerate(date_range):

        x_i = x_wet_mixed[t]  # size parameter_i
        n_i = n_mixed[t]  # complex index of refraction i

        if t in np.arange(0, 35000, 500):
            print t

        if np.logical_and(~np.isnan(x_i), ~np.isnan(n_i)):

            particle = Mie(x=x_i, m=n_i)
            Q_ext = particle.qext()
            Q_back = particle.qb()

            # calculate the lidar ratio
            S_t = Q_ext / Q_back
            S[t] = Q_ext / Q_back

    # ---------------------

    # simple plot of S
    fig, ax = plt.subplots(1, 1, figsize=(6, 6))
    plt.plot_date(date_range, S)
    plt.savefig(savedir + 'quickplot.png')
    plt.close(fig)

    # --------------------------

    # Testing lidar ratio computation

    # read in Franco's computation of the lidar ratio CIR=1.47 + 0.099i, lambda=905nm
    lr_f = eu.netCDF_read(
        '/home/nerc/Documents/MieScatt/testing/lr_1.47_0.099_0.905.nc',
        ['DIAMETER', 'LIDAR_RATIO'])

    step = 0.005
    r_range_um = np.arange(0.000 + step, 10.000 + step, step)
    r_range_m = r_range_um * 1.0e-06
    x_range = (2.0 * np.pi * r_range_m) / ceil_lambda[0]

    # calculate Q_back and Q_ext from the avergae r_md and n_mixed
    #S_r = lidar ratio
    S_r = np.empty(len(r_range_m))
    S_r[:] = np.nan
    for r_idx, r_i in enumerate(r_range_m):

        x_i = x_range[r_idx]  # size parameter_i
        n_i = complex(1.47 + 0.099j)  # fixed complex index of refraction i

        # print loop progress
        if r_idx in np.arange(0, 2100, 100):
            print r_idx

        particle = Mie(x=x_i, m=n_i)
        Q_ext = particle.qext()
        Q_back = particle.qb()
        Q_back_alt = Q_back / (4.0 * np.pi)

        # #Q_back = particle.qb()
        # S12 = particle.S12(-1)
        # S11 = S12[0].imag
        # S22 = S12[1].imag
        # Q_back_fancy = ((np.abs(S11)**2) + (np.abs(S22)**2))/(2 * np.pi * (x_i**2))

        # calculate the lidar ratio
        # S_t = Q_ext / Q_back
        S_r[r_idx] = Q_ext / Q_back_alt

    # simple plot of S
    fig, ax = plt.subplots(1, 1, figsize=(6, 5))
    plt.loglog(r_range_um * 2, S_r, label='mine')  # diameter [microns]
    plt.loglog(lr_f['DIAMETER'], lr_f['LIDAR_RATIO'], label='Franco' 's')
    plt.xlim([0.01, 100.0])
    plt.ylim([1.0, 10.0e7])
    plt.ylabel('Lidar Ratio')
    plt.xlabel('Diameter [microns]')
    plt.legend()
    plt.tight_layout()
    plt.savefig(savedir + 'quickplot_S_vs_r.png')
    plt.close(fig)

    # -----------------------------------------------

    d_test = 0.001e-06
    r_test = d_test / 2.0
    r_test_microns = r_test * 1.0e6

    x_i = (2.0 * np.pi * r_test) / ceil_lambda[0]  # size parameter_i
    n_i = complex(1.47 + 0.099j)  # fixed complex index of refraction i

    particle = Mie(x=x_i, m=n_i)
    Q_ext = particle.qext()
    Q_back = particle.qb()
    Q_back_alt = Q_back / (4.0 * np.pi)

    # calculate extinction and scattering cross section
    C_ext = Q_ext * np.pi * (r_test_microns**2.0)
    C_back = Q_back * np.pi * (r_test_microns**2.0)
    C_back_alt = Q_back_alt * np.pi * (r_test_microns**2.0)

    S12 = particle.S12(-1)

    S11 = S12[0].imag
    S22 = S12[1].imag

    Q_back_fancy = ((np.abs(S11)**2) + (np.abs(S22)**2)) / (2 * np.pi *
                                                            (x_i**2))

    # calculate the lidar ratio
    S_t = Q_ext / Q_back
    S_test = Q_ext / Q_back_alt
    S_c_test = C_ext / C_back
    S_c_alt = C_ext / C_back_alt

    return
def test_lidar_computation(ceil_lambda, r_md_m):
    """
    Test my computation of the lidar ratio against Franco's. Done for a monodisperse, soot(like?) aerosol
    :param ceil_lambda:
    :param r_md_m:
    :return:
    """

    import ellUtils as eu

    # Testing lidar ratio computation

    # read in Franco's computation of the lidar ratio CIR=1.47 + 0.099i, lambda=905nm
    lr_f = eu.netCDF_read(
        '/home/nerc/Documents/MieScatt/testing/lr_1.47_0.099_0.905.nc',
        ['DIAMETER', 'LIDAR_RATIO'])

    step = 0.005
    r_range_um = np.arange(0.000 + step, 10.000 + step, step)
    r_range_m = r_range_um * 1.0e-06
    x_range = (2.0 * np.pi * r_range_m) / ceil_lambda[0]

    # calculate Q_back and Q_ext from the avergae r_md and n_mixed
    #S_r = lidar ratio
    S_r = np.empty(len(r_range_m))
    S_r[:] = np.nan
    for r_idx, r_i in enumerate(r_range_m):

        x_i = x_range[r_idx]  # size parameter_i
        n_i = complex(1.47 + 0.0j)  # fixed complex index of refraction i
        # n_i = complex(1.47 + 0.099j)  # fixed complex index of refraction i for soot

        # print loop progress
        if r_idx in np.arange(0, 2100, 100):
            print r_idx

        particle = Mie(x=x_i, m=n_i)
        Q_ext = particle.qext()
        Q_back = particle.qb()
        Q_back_alt = Q_back / (4.0 * np.pi)

        # #Q_back = particle.qb()
        # S12 = particle.S12(-1)
        # S11 = S12[0].imag
        # S22 = S12[1].imag
        # Q_back_fancy = ((np.abs(S11)**2) + (np.abs(S22)**2))/(2 * np.pi * (x_i**2))

        # calculate the lidar ratio
        # S_t = Q_ext / Q_back
        S_r[r_idx] = Q_ext / Q_back_alt

    # simple plot of S
    fig, ax = plt.subplots(1, 1, figsize=(8, 7))
    plt.loglog(r_range_um * 2, S_r, label='mine')  # diameter [microns]
    plt.loglog(lr_f['DIAMETER'], lr_f['LIDAR_RATIO'], label='Franco' 's')

    for aer_i, r_md_m_aer_i in r_md_m.iteritems():
        for r_i in r_md_m_aer_i:
            plt.vlines(r_i, 1, 1e6, linestyle='--', alpha=0.5)

    plt.xlim([0.01, 100.0])
    plt.ylim([1.0, 10.0e7])
    plt.ylabel('Lidar Ratio')
    plt.xlabel('Diameter [microns]')
    plt.legend()
    plt.tight_layout()
    plt.savefig(maindir + 'figures/LidarRatio/' +
                'quickplot_S_vs_r_with_rbin_lines.png')
    plt.close(fig)

    return
    S_r[aer_i][:] = np.nan

    # n_i = complex(1.47 + 0.099j)  # fixed complex index of refraction i
    n_i = n_species[aer_i]

    for r_idx, r_i in enumerate(r_range_m):

        x_i = x_range[r_idx]  # size parameter_i

        # print loop progress
        if r_idx in np.arange(0, 2100, 100):
            print r_idx

        # calculate Q_back and Q_ext efficiency for current size parameter and complex index of refraction
        particle = Mie(x=x_i, m=n_i)
        Q_ext = particle.qext()
        Q_back = particle.qb()
        Q_back_alt = Q_back / (4.0 * np.pi)

        # calculate the lidar ratio
        S_r[aer_i][r_idx] = Q_ext / Q_back_alt

# simple plot of S
fig, ax = plt.subplots(1, 1, figsize=(7, 4))
for key, data in S_r.iteritems():
    plt.loglog(r_range_um * 2.0, data,
               label=aer_labels[key])  # diameter [microns]
# plt.xlim([0.01, 100.0])
plt.ylim([1.0, 10.0e5])
plt.xlim([0.01, 20])
plt.ylabel(r'$Lidar \/Ratio \/[sr]$')