Example #1
0
def mieMonteCarlo(wavelength=450 * 10**-9,
                  r=300 * 10**-9,
                  Vs=0.1,
                  nParticle=1.46,
                  nMedium=1.36):
    """
    Calculate the scattering parameters relevant for monte carlo simulation.

    Needs pymiecoated: https://code.google.com/p/pymiecoated/
    These are calculate scattering coefficient [1/cm] and anisotropy factor for given:

    Args
    ____
    wavelength:
        wavelength of the incident light [m]
    r:
        radius of the particle [m]
    Vs:
        volume fraction of scattering particles
    nParticle:
        refractive index of the particle that the light wave is scattered on
        (default value is the refractive index of collagen)
    nMedium:
        refractive index of the surronding medium (default is that of colonic
        mucosal tissue)

    Returns:
    ____
    {'us', 'g'}:
        scattering coefficient us [1/m] and anisotropy factor g

    TODO:
    _____
        Additional input parameter specifying a FWHM for the wavelength to simulate the
        scattering for a broad filter
    """

    # create derived parameters
    sizeParamter = 2 * math.pi * r / wavelength
    nRelative = nParticle / nMedium

    #%% execute mie and create derived parameters

    mie = Mie(x=sizeParamter, m=complex(nRelative,
                                        0.0))  # 0.0 complex for no attenuation

    A = math.pi * r**2  # geometrical cross sectional area
    cs = mie.qsca() * A  # scattering cross section

    us = Vs / (4 / 3 * r**3 * math.pi) * cs  # scattering coefficient [m⁻1]

    return {'us': us, 'g': mie.asy()}
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()
    
Example #3
0
def calc_Q_ext(
    x,
    m,
    type,
    y=[],
    m2=[],
):
    """
    Calculate Q_ext. Can be dry, coated in water, or deliquescent with water

    :param x: dry particle size parameter
    :param m: complex index of refraction for particle
    :param y: wet particle size parameter
    :param m2: complex index of refraction for water
    :return: Q_ext
    :return: calc_type: how was particle treated? (e.g. dry, coated)
    """

    from pymiecoated import Mie
    import numpy as np

    # Coated aerosol (insoluble aerosol that gets coated as it takes on water)
    if type == 'coated':

        if (y != []) & (m2 != []):

            all_particles_coat = [
                Mie(x=x[i], m=m, y=y[i], m2=m2) for i in np.arange(len(x))
            ]
            Q = np.array([particle.qext() for particle in all_particles_coat])

        else:
            raise ValueError("type = coated, but y or m2 is empty []")

    # Calc extinction efficiency for dry aerosol (using r_md!!!! NOT r_m)
    # if singular, then type == complex, else type == array
    elif type == 'dry':

        all_particles_dry = [Mie(x=x, m=m) for x_i in x]
        Q = np.array([particle.qext() for particle in all_particles_dry])

    # deliquescent aerosol (solute disolves as it takes on water)
    elif type == 'deliquescent':

        all_particles_del = [Mie(x=x[i], m=m[i]) for i in np.arange(len(x))]
        Q = np.array([particle.qext() for particle in all_particles_del])

    return Q
Example #4
0
def mie_analytical(radii,
                   vacuum_wavelength,
                   out_param='qsca',
                   cross_section=False,
                   **mie_params):
    """Returns the analytical values for the efficiencies using the 
    `pymiecoated`-package. Pass additional parameters to the `Mie`-class
    using the `mie_params`, e.g. by writing `m=1.52` to pass the refractive
    index of the sphere. `out_param` can be each method of the `Mie`-class,
    e.g. 'qext', 'qsca' or 'qabs'. Use `cross_section=True` to return the
    related cross section instead of the efficiency."""
    from pymiecoated import Mie
    import collections
    _is_iter = True
    if not isinstance(radii, collections.Iterable):
        _is_iter = False
        radii = np.array([radii])

    out_vals = []
    for radius in radii:
        x = 2 * np.pi * radius / vacuum_wavelength
        mie = Mie(x=x, **mie_params)
        out_func = getattr(mie, out_param)
        out_val = out_func()
        if cross_section:
            out_val = np.pi * np.square(radius) * out_val
        out_vals.append(out_val)
    if not _is_iter:
        return out_vals[0]
    return np.array(out_vals)
Example #5
0
def mieMonteCarlo(wavelength = 450*10**-9, r = 300*10**-9, Vs = 0.1, nParticle = 1.46, nMedium = 1.36):
    """
    Calculate the scattering parameters relevant for monte carlo simulation.

    Needs pymiecoated: https://code.google.com/p/pymiecoated/
    These are calculate scattering coefficient [1/cm] and anisotropy factor for given:

    Args
    ____
    wavelength:
        wavelength of the incident light [m]
    r:
        radius of the particle [m]
    Vs:
        volume fraction of scattering particles
    nParticle:
        refractive index of the particle that the light wave is scattered on
        (default value is the refractive index of collagen)
    nMedium:
        refractive index of the surronding medium (default is that of colonic
        mucosal tissue)

    Returns:
    ____
    {'us', 'g'}:
        scattering coefficient us [1/m] and anisotropy factor g

    TODO:
    _____
        Additional input parameter specifying a FWHM for the wavelength to simulate the
        scattering for a broad filter
    """

    # create derived parameters
    sizeParamter = 2 * math.pi * r / wavelength
    nRelative    = nParticle / nMedium

    #%% execute mie and create derived parameters

    mie = Mie(x=sizeParamter, m=complex(nRelative,0.0))  # 0.0 complex for no attenuation

    A  = math.pi * r**2 # geometrical cross sectional area
    cs = mie.qsca() * A # scattering cross section

    us = Vs / (4/3 * r**3 * math.pi) * cs # scattering coefficient [m⁻1]

    return {'us': us, 'g': mie.asy()}
Example #6
0
    def mie(self, a=0.3):
        qsca = []
        qabs = []
        qext = []
        mie = Mie()

        wl = np.arange(0.21, 1.2, .001)

        n_cu, k_cu, n_w, k_w = self.intp_data.intpdata(wl)

        for i in range(len(wl)):
            mie.x = a * 2 * np.pi / wl[i]
            temp_n = n_cu[i] / n_w[i]
            temp_k = k_cu[i] + k_w[i]
            'print temp_n, temp_k'
            mie.m = complex(temp_n, temp_k)
            '''
      mie.y = 3 * a * 2*np.pi/wl[i];
      mie.m2 = complex(n_w[i], k_w[i]);
      '''
            qsca.append(mie.qsca())
            qabs.append(mie.qabs())
            qext.append(mie.qb())

        return wl, qsca, qabs, qext
Example #7
0
File: mie.py Project: mjonyh/mie
  def mie(self, a = 0.3):
    qsca = [];
    qabs = [];
    qext = [];
    mie = Mie();

    wl = np.arange(0.21, 1.2, .001);

    n_cu, k_cu, n_w, k_w = self.intp_data.intpdata(wl);

    for i in range(len(wl)):
      mie.x = a * 2*np.pi/wl[i];
      temp_n = n_cu[i]/n_w[i];
      temp_k = k_cu[i]+k_w[i];
      'print temp_n, temp_k'
      mie.m = complex(temp_n, temp_k);
      '''
      mie.y = 3 * a * 2*np.pi/wl[i];
      mie.m2 = complex(n_w[i], k_w[i]);
      '''
      qsca.append(mie.qsca());
      qabs.append(mie.qabs());
      qext.append(mie.qb());

    return wl, qsca, qabs, qext;
Example #8
0
if (1 == 1):
    extb = np.zeros((len(sbin) - 1, len(wavmin)))
    ssab = np.zeros((len(sbin) - 1, len(wavmin)))
    asyb = np.zeros((len(sbin) - 1, len(wavmin)))
    for nband in range(len(wavmin)):
        specbin = np.linspace(wavmin[nband], wavmax[nband], 50)
        for db in range(len(Deff)):
            qext = 0.
            ssa = 0.
            asy = 0.

            for wl in range(len(specbin)):
                sp = np.pi * Deff[db] / specbin[wl]
                k = kint(specbin[wl])
                nd = ndint(specbin[wl])
                mie = Mie(x=sp, m=complex(nd, k))
                qext = qext + mie.qsca() + mie.qabs()
                qabs = mie.qabs()
                ssa = ssa + mie.qsca() / (mie.qsca() + mie.qabs())
                asy = asy + mie.asy()
            extb[db, nband] = extb[db, nband] + (qext / len(specbin)) / (
                2. / 3. * rhop * Deff[db] * 1E-6)
            #cross section in m2/g
            ssab[db, nband] = ssab[db, nband] + (ssa / len(specbin))
            asyb[db, nband] = asyb[db, nband] + (asy / len(specbin))

if (1 == 2):
    #method 2(slower) double integration  /more precise prblem mie return nan for extrem coarse particles
    # calculate the mie parameter for every diameter of the range, averaged on spectral band

    extb = np.zeros((len(sbin) - 1, len(wavmin)))
Example #9
0
        # n_murk = complex(1.53, 0.007) - this is for 550 nm
        # n_store += [n_murk]

        # complex indices of refraction (n = n(bar) - ik) at ceilometer wavelength (910 nm) Hesse et al 1998
        # n_water, _ = linear_interpolate_n('water', lam)

        # calculate size parameter for dry and wet
        x_dry = (2.0 * np.pi * r_md) / lam
        # x_store += [x_dry]

        # calculate swollen index of refraction using MURK
        # n_swoll = CIR_Hanel(n_water, n_murk, r_md, r_m)

        # Calc extinction efficiency for dry aerosol (using r_md!!!! NOT r_m)
        for aer_i, n_i in n_aerosol.iteritems():
            all_particles_dry = [Mie(x=x_i, m=n_i) for x_i in x_dry]
            Q_dry[aer_i][lam_str] = np.array(
                [particle.qext() for particle in all_particles_dry])

    # once 905 has been calcualted
    for aer_i, value in Q_dry.iteritems():
        for lam_str_i in ceil_lambda_str:
            Q_diff[aer_i][
                lam_str_i] = Q_dry[aer_i][lam_str_i] - Q_dry[aer_i]['905']
            Q_ratio[aer_i][
                lam_str_i] = Q_dry[aer_i][lam_str_i] / Q_dry[aer_i]['905']

    # qsca, qabs are alternatives to qext

    # -----------------------------------------------
    # Post processing, saving and plotting
def main():

    import numpy as np
    from pymiecoated import Mie
    import matplotlib.pyplot as plt

    # -------------------------------------------------------------------
    # Setup

    # setup
    ceil_lambda = [0.905e-06]  # [m]
    # ceil_lambda = np.arange(0.69e-06, 1.19e-06, 0.05e-06) # [m]
    # ceil_lambda = np.arange(0.90e-06, 0.91e-06, 0.05e-08) # [m]
    # ceil_lambda = np.array(([0.90e-06, 0.91e-06, 0.92e-06])) # [m]
    B = 0.14
    RH_crit = 0.38

    # directories
    savedir = '/home/nerc/Documents/MieScatt/figures/'
    datadir = '/home/nerc/Documents/MieScatt/data/'

    # aerosol with relative volume - average from the 4 Haywood et al 2008 flights
    rel_vol = {
        'Ammonium sulphate': 0.295,
        'Ammonium nitrate': 0.325,
        'Organic carbon': 0.38
    }

    # all the aerosol types
    all_aer_order = [
        'Ammonium sulphate', 'Ammonium nitrate', 'Organic carbon', 'Biogenic',
        'Generic NaCl', 'Soot', 'MURK'
    ]
    # all_aer = ['ammonium_sulphate', 'ammonium_nitrate', 'organic_carbon', 'biogenic', 'NaCl', 'soot']
    all_aer = {
        'Ammonium sulphate': 'red',
        'Ammonium nitrate': 'orange',
        'Organic carbon': [0.05, 0.9, 0.4],
        'Biogenic': [0.05, 0.56, 0.85],
        'Generic NaCl': 'magenta',
        'Soot': 'brown'
    }
    # all_aer = ['soot']

    # create dry size distribution [m]
    # r_md_microm = np.arange(0.03, 5.001, 0.001) # .shape() = 4971
    # r_md_microm = np.arange(0.000 + step, 1.000 + step, step), when step = 0.005, .shape() = 200
    step = 0.005
    r_md_microm = np.arange(0.000 + step, 5.000 + step, step)
    r_md = r_md_microm * 1.0e-06

    # RH array [fraction]
    # This gets fixed for each Q iteration (Q needs to be recalculated for each RH used)
    RH = 0.8

    # densities of MURK constituents # [kg m-3]
    # range of densities of org carb is massive (0.625 - 2 g cm-3)
    # Haywood et al 2003 use 1.35 g cm-3 but Schkolnik et al., 2006 lit review this and claim 1.1 g cm-3
    dens_amm_sulph = 1770
    dens_amm_nit = 1720
    dens_org_carb = 1100  # NOTE ABOVE

    # define array to store Q for each wavelength
    Q_dry = []

    x_store = []
    n_store = []

    # save the Q(dry) curve for MURK?
    savedata = True

    # -----------------------------------------------
    # Calculate Q for each lambda
    # -----------------------------------------------

    # -------------------------------------------------------------------
    # Process

    # calculate complex index of refraction for MURK species
    # output n is complex index of refraction (n + ik)
    n_aerosol = calc_n_aerosol(all_aer, ceil_lambda)

    # NOTE: Able to use volume in MURK equation instead of mass because, if mass is evenly distributed within a volume
    # then taking x of the mass = taking x of the volume.
    # after calculating volumes used in MURK, can find relative % and do volume mixing.

    # bulk complex index of refraction (CIR) for the MURK species using volume mixing method
    n_murk = calc_n_murk(rel_vol, n_aerosol)
    n_aerosol['MURK'] = n_murk
    all_aer['MURK'] = 'black'  # add color for plotting
    # n_murk = complex(1.53, 0.007) - this is for 550 nm
    n_store += [n_murk]

    # complex indices of refraction (n = n(bar) - ik) at ceilometer wavelength (905 nm) Hesse et al 1998
    # n_water, _ = linear_interpolate_n('water', lam)

    # swell particles using FO method
    # rm = np.ma.ones(RH.shape) - (B / np.ma.log(RH_ge_RHcrit))
    r_m = 1 - (B / np.log(RH))
    r_m2 = np.ma.power(r_m, 1. / 3.)
    r_m = np.ma.array(r_md) * r_m2
    r_m_microm = r_m * 1.0e06

    # calculate size parameter for dry and wet
    x_dry = (2.0 * np.pi * r_md) / ceil_lambda
    x_store += [x_dry]
    x_wet = (2.0 * np.pi * r_m) / ceil_lambda

    # calculate swollen index of refraction using MURK
    # n_swoll = CIR_Hanel(n_water, n_murk, r_md, r_m)

    # Calc extinction efficiency for dry aerosol (using r_md!!!! NOT r_m)
    # all_particles_dry = [Mie(x=x_i, m=n_murk) for x_i in x_dry]
    # Q_dry += [np.array([particle.qext() for particle in all_particles_dry])]

    Q_dry = {}
    for key, n_i in n_aerosol.iteritems():
        all_particles_dry = [Mie(x=x_i, m=n_i) for x_i in x_dry]
        Q_dry[key] = np.array(
            [particle.qext() for particle in all_particles_dry])
    # qsca, qabs
    # -----------------------------------------------
    # Post processing, saving and plotting
    # -----------------------------------------------

    # if running for single 905 nm wavelength, save the calculated Q
    if savedata == True:
        if type(ceil_lambda) == list:
            if ceil_lambda[0] == 0.905e-06:
                # save Q curve and radius [m]
                np.savetxt(datadir + 'calculated_Q_ext_905nm.csv',
                           np.transpose(np.vstack((r_md, Q_dry['MURK']))),
                           delimiter=',',
                           header='radius,Q_ext')

    # plot
    fig = plt.figure(figsize=(6, 4))

    for aer_i in all_aer_order:

        # plot it
        plt.semilogx(r_md_microm,
                     Q_dry[aer_i],
                     label=aer_i,
                     color=all_aer[aer_i])
        # plt.semilogx(r_md_microm, Q_dry, label='dry murk', color=[0,0,0])
        # plt.semilogx(r_m_microm, Q_del, label='deliquescent murk (RH = ' + str(RH) + ')')
        # plt.semilogx(r_m_microm, Q_coat, label='coated murk (RH = ' + str(RH) + ')')

    # for aer_i, Q_dry_i in Q_dry.iteritems():
    #
    #     # plot it
    #     plt.semilogx(r_md_microm, Q_dry_i, label=aer_i, color=all_aer[aer_i])
    #     # plt.semilogx(r_md_microm, Q_dry, label='dry murk', color=[0,0,0])
    #     # plt.semilogx(r_m_microm, Q_del, label='deliquescent murk (RH = ' + str(RH) + ')')
    #     # plt.semilogx(r_m_microm, Q_coat, label='coated murk (RH = ' + str(RH) + ')')

    # plt.title('lambda = ' + str(ceil_lambda[0]) + 'nm')
    plt.xlabel(r'$r_{md} \/\mathrm{[\mu m]}$', labelpad=-10, fontsize=13)
    plt.xlim([0.05, 5.0])
    plt.ylim([0.0, 5.0])
    #plt.xlim([0.01, 0.2])
    #plt.ylim([0.0, 0.1])
    plt.ylabel(r'$Q_{ext,dry}$', fontsize=13)
    plt.legend(fontsize=8, loc='best')
    plt.tick_params(axis='both', labelsize=10)
    plt.grid(b=True, which='major', color='grey', linestyle='--')
    plt.grid(b=True, which='minor', color=[0.85, 0.85, 0.85], linestyle='--')
    plt.savefig(savedir + 'Q_ext_manyAer2_' + str(ceil_lambda[0]) + 'nm.png')
    print 'data dir is... ' + savedir + 'Q_ext_manyAer_' + str(
        ceil_lambda[0]) + 'nm.png'
    plt.tight_layout(h_pad=10.0)
    plt.close()

    # plot the radius
    # plot_radius(savedir, r_md, r_m)

    print 'END PROGRAM'
Example #11
0
    d_new = pow1d3(4 / 3 * np.pi / N) * a_eff
    #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")
Example #12
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.empty(len(r_range_m))
    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])
Example #15
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')
Example #16
0
def main():



    import numpy as np
    from pymiecoated import Mie
    import matplotlib.pyplot as plt

    # -------------------------------------------------------------------
    # Setup

    # setup
    ceil_lambda = [0.91e-06] # [m]
    # ceil_lambda = np.arange(0.69e-06, 1.19e-06, 0.05e-06) # [m]

    # directories
    savedir = '/home/nerc/Documents/MieScatt/figures/'
    datadir = '/home/nerc/Documents/MieScatt/data/'

    # aerosol with relative volume - average from the 4 Haywood et al 2008 flights
    rel_vol = {'ammonium_sulphate': 0.295,
               'ammonium_nitrate': 0.325,
                'organic_carbon': 0.38}


    # create dry size distribution [m]
    # r_md_microm = np.arange(0.03, 5.001, 0.001) # .shape() = 4971
    # r_md_microm = np.arange(0.000 + step, 1.000 + step, step), when step = 0.005, .shape() = 200
    step = 0.0005
    r_md_microm = np.arange(0.000 + step, 2.000 + step, step)
    r_md = r_md_microm * 1.0e-06

    # RH array [fraction]
    # This gets fixed for each Q iteration (Q needs to be recalculated for each RH used)
    RH = 0.8

    # densities of MURK constituents # [kg m-3]
    # range of densities of org carb is massive (0.625 - 2 g cm-3)
    # Haywood et al 2003 use 1.35 g cm-3 but Schkolnik et al., 2006 lit review this and claim 1.1 g cm-3
    dens_amm_sulph = 1770
    dens_amm_nit = 1720
    dens_org_carb = 1100 # NOTE ABOVE

    # define array to store Q for each wavelength
    Q_dry = []

    x_store =[]
    n_store=[]

    # -----------------------------------------------
    # Calculate Q for each lambda
    # -----------------------------------------------

    for lam in ceil_lambda:

        # -------------------------------------------------------------------
        # Process

        # calculate complex index of refraction for MURK species
        # output n is complex index of refraction (n + ik)
        n_aerosol = calc_n_aerosol(rel_vol, lam)

        # NOTE: Able to use volume in MURK equation instead of mass because, if mass is evenly distributed within a volume
        # then taking x of the mass = taking x of the volume.
        # after calculating volumes used in MURK, can find relative % and do volume mixing.

        # bulk complex index of refraction (CIR) for the MURK species using volume mixing method
        n_murk = calc_n_murk(rel_vol, n_aerosol)
        # n_murk = complex(1.53, 0.007) - makes no sense as this is for 550 nm
        # n_store += [n_murk]

        # complex indices of refraction (n = n(bar) - ik) at ceilometer wavelength (910 nm) Hesse et al 1998
        # n_water, _ = linear_interpolate_n('water', lam)

        # swell particles using FO method
        # rm = np.ma.ones(RH.shape) - (B / np.ma.log(RH_ge_RHcrit))
        # r_m = 1 - (B / np.log(RH))
        # r_m2 = np.ma.power(r_m, 1. / 3.)
        # r_m = np.ma.array(r_md) * r_m2
        # r_m_microm = r_m * 1.0e06

        # calculate size parameter for dry and wet
        x_dry = (2.0 * np.pi * r_md)/lam
        x_store += [x_dry]
        # x_wet = (2.0 * np.pi * r_m)/lam


        # calculate swollen index of refraction using MURK
        # n_swoll = CIR_Hanel(n_water, n_murk, r_md, r_m)


        # Calc extinction efficiency for dry aerosol (using r_md!!!! NOT r_m)
        all_particles_dry = [Mie(x=x_i, m=n_murk) for x_i in x_dry]
        Q_dry += [np.array([particle.qext() for particle in all_particles_dry])]

    # -----------------------------------------------
    # Post processing, saving and plotting
    # -----------------------------------------------


    # if running for single 910 nm wavelength, save the calculated Q
    if type(ceil_lambda) == list:
        if ceil_lambda[0] == 9.1e-07:
            # save Q curve and radius [m]
            np.savetxt(datadir + 'calculated_Q_ext_910nm.csv', np.transpose(np.vstack((r_md, Q_dry))), delimiter=',', header='radius,Q_ext')


    # plot
    fig = plt.figure(figsize=(7, 4.5))

    for Q_i, lam in zip(Q_dry, ceil_lambda):

        # plot it
        plt.semilogx(r_md_microm, Q_i, label=str(lam) + 'm')
        # plt.semilogx(r_md_microm, Q_dry, label='dry murk', color=[0,0,0])
        # plt.semilogx(r_m_microm, Q_del, label='deliquescent murk (RH = ' + str(RH) + ')')
        # plt.semilogx(r_m_microm, Q_coat, label='coated murk (RH = ' + str(RH) + ')')

    # # average Q_dry if multiple Q_drys were calculated
    # if Q_dry.__len__() != 1:
    #     q = np.array(Q_dry)
    #     Q_dry_avg = np.mean(q, axis=0)
    #     ax = plt.semilogx(r_md_microm, Q_dry_avg, label='average', color='black', linewidth=2)

    plt.title('lambda = ' + str(ceil_lambda[0]) + '-' + str(ceil_lambda[-1]) + 'm, n = murk')
    plt.xlabel('radius [micrometer]', labelpad=-5)
    plt.xlim([0.05, 5.0])
    plt.ylim([0.0, 5.0])
    #plt.xlim([0.01, 0.2])
    #plt.ylim([0.0, 0.1])
    plt.ylabel('Q_ext')
    plt.legend(fontsize=8, loc='best')
    plt.grid(b=True, which='major', color='grey', linestyle='--')
    plt.grid(b=True, which='minor', color=[0.85, 0.85, 0.85], linestyle='--')
    plt.savefig(savedir + 'Q_ext_murk_' + str(ceil_lambda[0]) + '-' + str(ceil_lambda[-1]) + 'lam.png')
    plt.tight_layout()
    plt.close()

    # plot the radius
    # plot_radius(savedir, r_md, r_m)

    print 'END PROGRAM'
Example #17
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)
Example #18
0
def main():

    # -------------------------------------------------------------------
    # Setup

    # setup
    # ceil_lambda = [0.91e-06] # [m]
    # ceil_lambda = np.arange(0.69e-06, 1.19e-06, 0.05e-06) # [m]
    # ceil_lambda = np.arange(8.95e-07, 9.16e-07, 1.0e-09) # [m]
    ceil_lambda = np.array([905e-09, 1064e-09])

    ceil_lambda_str = ['%d' % i for i in ceil_lambda * 1.0e9]

    # extra =''
    extra = '_largelam'

    # directories
    savedir = '/home/nerc/Documents/MieScatt/figures/'
    datadir = '/home/nerc/Documents/MieScatt/data/'

    # aerosol with relative volume - average from the 4 Haywood et al 2008 flights
    rel_vol = {
        'ammonium_sulphate': 0.295,
        'ammonium_nitrate': 0.325,
        'organic_carbon': 0.38
    }

    # all the aerosol types
    # all_aer = ['ammonium_sulphate', 'ammonium_nitrate', 'organic_carbon', 'oceanic', 'biogenic', 'NaCl', 'soot']
    aer_names = {
        'ammonium_sulphate': 'Ammonium sulphate',
        'ammonium_nitrate': 'Ammonium nitrate',
        'organic_carbon': 'Organic carbon',
        'NaCl': 'Generic NaCl',
        'soot': 'Soot',
        'MURK': 'MURK'
    }
    # all_aer = {'ammonium_sulphate': 'red', 'ammonium_nitrate':'orange', 'organic_carbon': 'green',
    #            'biogenic': 'cyan', 'NaCl': 'magenta', 'soot': 'brown'}
    all_aer = {
        'ammonium_sulphate': 'red',
        'ammonium_nitrate': 'orange',
        'organic_carbon': 'green',
        'NaCl': 'magenta',
        'soot': 'brown',
        'MURK': 'black'
    }
    all_aer_constits = [
        'ammonium_sulphate', 'ammonium_nitrate', 'organic_carbon', 'NaCl',
        'soot'
    ]

    # create dry size distribution [m]
    # r_md_microm = np.arange(0.03, 5.001, 0.001) # .shape() = 4971
    # r_md_microm = np.arange(0.000 + step, 1.000 + step, step), when step = 0.005, .shape() = 200
    step = 0.005
    r_md_microm = np.arange(0.000 + step, 10.000 + step, step)
    r_md = r_md_microm * 1.0e-06

    # define array to store Q for each wavelength
    Q_dry = {}
    Q_diff = {}
    Q_ratio = {}

    # make each, first level key (i.e. Q_dry[firstkey]) the aerosol type, followed later by the wavelength [nm].
    for aer_i in all_aer.iterkeys():

        Q_dry[aer_i] = {}
        Q_diff[aer_i] = {}
        Q_ratio[aer_i] = {}

        for lam_i in ceil_lambda_str:

            Q_dry[aer_i][lam_i] = []
            Q_diff[aer_i][lam_i] = []
            Q_ratio[aer_i][lam_i] = []

    # save the Q(dry) curve for MURK?
    savedata = False

    # -----------------------------------------------
    # Calculate Q for each lambda
    # -----------------------------------------------

    for lam, lam_str in zip(ceil_lambda, ceil_lambda_str):

        print '\n lam_i = ' + lam_str + ' nm'
        # -------------------------------------------------------------------
        # Process

        # calculate complex index of refraction for MURK species
        # output n is complex index of refraction (n + ik)
        n_aerosol = calc_n_aerosol(all_aer_constits, lam)

        # NOTE: Able to use volume in MURK equation instead of mass because, if mass is evenly distributed within a volume
        # then taking x of the mass = taking x of the volume.
        # after calculating volumes used in MURK, can find relative % and do volume mixing.

        # bulk complex index of refraction (CIR) for the MURK species using volume mixing method
        n_murk = calc_n_murk(rel_vol, n_aerosol)
        n_aerosol['MURK'] = n_murk
        # n_murk = complex(1.53, 0.007) - this is for 550 nm
        # n_store += [n_murk]

        # complex indices of refraction (n = n(bar) - ik) at ceilometer wavelength (910 nm) Hesse et al 1998
        # n_water, _ = linear_interpolate_n('water', lam)

        # calculate size parameter for dry and wet
        x_dry = (2.0 * np.pi * r_md) / lam
        # x_store += [x_dry]

        # calculate swollen index of refraction using MURK
        # n_swoll = CIR_Hanel(n_water, n_murk, r_md, r_m)

        # Calc extinction efficiency for dry aerosol (using r_md!!!! NOT r_m)
        for aer_i, n_i in n_aerosol.iteritems():
            all_particles_dry = [Mie(x=x_i, m=n_i) for x_i in x_dry]
            Q_dry[aer_i][lam_str] = np.array(
                [particle.qext() for particle in all_particles_dry])

    # once 910 has been calcualted
    for aer_i, value in Q_dry.iteritems():
        for lam_str_i in ceil_lambda_str:
            Q_diff[aer_i][
                lam_str_i] = Q_dry[aer_i][lam_str_i] - Q_dry[aer_i]['905']
            Q_ratio[aer_i][
                lam_str_i] = Q_dry[aer_i][lam_str_i] / Q_dry[aer_i]['905']

    # qsca, qabs are alternatives to qext

    # -----------------------------------------------
    # Post processing, saving and plotting
    # -----------------------------------------------

    # plot
    # plot_one_aer_i

    plot_absolute(r_md_microm, Q_dry, ceil_lambda, ceil_lambda_str,
                  all_aer_constits, aer_names, savedir, extra)

    plot_diff(r_md_microm, Q_diff, ceil_lambda, ceil_lambda_str,
              all_aer_constits, aer_names, savedir, extra)

    plot_ratio(r_md_microm, Q_ratio, ceil_lambda, ceil_lambda_str,
               all_aer_constits, aer_names, savedir, extra)

    # plot the radius
    # plot_radius(savedir, r_md, r_m)

    print 'END PROGRAM'
frac_lambert	= 1 - frac_mie

# 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
       
Example #20
0
def main():
    """
    Carry out a sensitivity analysis on the Mie scattering code

    :return: plots Mie scattering curve of murk, deliquecent and coated spheres at 80 % RH.
    """

    import numpy as np
    from pymiecoated import Mie
    import matplotlib.pyplot as plt

    # -------------------------------------------------------------------
    # Setup

    # setup
    ceil_lambda = 0.91e-06  # [m]
    B = 0.14
    RH_crit = 0.38

    # directories
    savedir = '/home/nerc/Documents/MieScatt/figures/sensitivity/'

    # aerosol with relative volume - varying manually - first one is average from haywood et al., 2008
    rel_vol = {
        'ammonium_sulphate': [0.295, 0.80, 0.10, 0.10],
        'ammonium_nitrate': [0.325, 0.10, 0.80, 0.10],
        'organic_carbon': [0.38, 0.10, 0.10, 0.80]
    }

    # create dry size distribution [m]
    r_md_microm = np.arange(0.03, 5.001, 0.001)
    r_md = r_md_microm * 1.0e-06

    # RH array [fraction]
    # This gets fixed for each Q iteration (Q needs to be recalculated for each RH used)
    RH = 0.8

    # densities of MURK constituents # [kg m-3]
    # range of densities of org carb is massive (0.625 - 2 g cm-3)
    # Haywood et al 2003 use 1.35 g cm-3 but Schkolnik et al., 2006 lit review this and claim 1.1 g cm-3
    dens_amm_sulph = 1770
    dens_amm_nit = 1720
    dens_org_carb = 1100  # NOTE ABOVE

    # -------------------------------------------------------------------
    # Process

    # calculate complex index of refraction for each particle
    # output n is complex index of refraction (n + ik)
    n_aerosol = calc_n_aerosol(rel_vol, ceil_lambda)

    # NOTE: Able to use volume in MURK equation instead of mass because, if mass is evenly distributed within a volume
    # then taking x of the mass = taking x of the volume.
    # after calculating volumes used in MURK, can find relative % and do volume mixing.

    n_mixed = []
    for i in range(len(rel_vol['ammonium_sulphate'])):

        # extract out just this one set of relative amounts
        rel_vol_i = {}
        for key in rel_vol.keys():
            rel_vol_i[key] = rel_vol[key][i]

        # uses relative amounts in the MURK equation!
        n_mixed += [calc_n_murk(rel_vol_i, n_aerosol)]

    # complex indices of refraction (n = n(bar) - ik) at ceilometer wavelength (910 nm) Hesse et al 1998
    n_water, _ = linear_interpolate_n('water', ceil_lambda)

    # swell particles using FO method
    # rm = np.ma.ones(RH.shape) - (B / np.ma.log(RH_ge_RHcrit))
    r_m = 1 - (B / np.log(RH))
    r_m2 = np.ma.power(r_m, 1. / 3.)
    r_m = np.ma.array(r_md) * r_m2
    r_m_microm = r_m * 1.0e06

    # calculate size parameter for dry and wet
    x_dry = (2.0 * np.pi * r_md) / ceil_lambda
    x_wet = (2.0 * np.pi * r_m) / ceil_lambda

    # # calculate swollen index of refraction using MURK
    # n_swoll = CIR_Hanel(n_water, n_murk, r_md, r_m)

    for j in range(len(n_mixed)):

        # Calc extinction efficiency for dry aerosol (using r_md!!!! NOT r_m)
        all_particles_dry = [Mie(x=x_i, m=n_mixed[j]) for x_i in x_dry]
        Q_dry = np.array([particle.qext() for particle in all_particles_dry])

        # use proportions of each to scale the colours on the plot
        colours = [
            rel_vol['ammonium_sulphate'][j], rel_vol['ammonium_nitrate'][j],
            rel_vol['organic_carbon'][j]
        ]

        lab = 'AS=' + str(rel_vol['ammonium_sulphate'][j]) + '; ' +\
            'AN=' + str(rel_vol['ammonium_nitrate'][j]) + '; ' +\
            'OC=' + str(rel_vol['organic_carbon'][j])

        # plot it
        plt.semilogx(r_md_microm, Q_dry, color=colours, label=lab)

    plt.title('lambda = interpolated to ' + str(ceil_lambda) + 'm')
    plt.xlabel('radius [micrometer]')
    plt.xlim([0.03, 5.0])
    plt.ylim([0.0, 5.0])
    plt.ylabel('Q')
    plt.legend(fontsize=9)
    plt.savefig(savedir + 'Q_ext_murk_sensitivity_' + str(ceil_lambda) +
                'lam.png')
    # plt.close()

    print 'END PROGRAM'
Example #21
0
def get_optical_properties(rhop, filename):

    # user defined parameter
    #define the number (or mass) distribution (e.g from Kok et al).
    #diameter micron
    D = np.arange(0.001, 20, 0.005)

    if (1 == 2):
        D = np.arange(0.01, 65, 0.05)
    if (1 == 1):
        cN = 0.9539
        Ds = 3.4
        sigs = 3.0
        lamb = 12
        A = np.log(D / Ds) / (np.sqrt(2) * np.log(sigs))
        #care dND/dD or dND/d(lnD) !!
        dND = (1 / D) * (1 /
                         (cN * D * D)) * (1 + erf(A)) * np.exp(-1. *
                                                               (D / lamb)**3)
        #dND = (D/12.62) * (1 + erf(A)) * np.exp(-1.*(D/lamb)**3)

    # here use a 3 log distribution
    # e.g. alfaro Gomez
    if (1 == 2):
        sig = [1.75, 1.75, 1.75]
        Dm = [0.64, 3.45, 8.67]
        Nf = [0.74, 0.20, 0.06]
        dND = ddlogn(D, Dm, sig, Nf)

    if (1 == 1):
        #define 2 size bins for each SOA category
        sbin = np.array([0.001, 0.03, 0.70])

    if (1 == 2):
        #define the 12 new size bin cut of diam from LISA optimised distribution
        #you can take also one big bin encompassing the whole distrib (that 's what
        #we do for BC/OC, in this case it is equivalent to integrate over the full
        #distrib mode).

        #here is LISA optimal distrib for dust
        sbin =  np.array([0.09,0.18, 0.6, 1.55, 2.50, 3.75, 4.70, 5.70, 7.50,\
                           14.50, 26.0, 41.0, 63.0])
        #sbin = [0.01 ,1.,2.5,5.,20. ]
        #sbin =[0.98,1.2,2.5,5.,20.]

    ## Uncomment the following line for testing
    # rhop, ndbib, wbib, kbib = return_test_variables()

    wbib, ndbib, kbib = np.loadtxt(soa_ri_path + filename,
                                   skiprows=0,
                                   unpack=True)

    #kbib = [0.04, 0.027866667,     0.020111111,    0.014933333,    0.001,    0.001,    0.001,    0.001,    0.003177778,    0.003033333,    0.003011111,    0.002911111,    0.003111111,    0.003111111,    0.003066667 , 0.0028,0.0025,0.002, 0.00195, 0.0019]

    #with this function we can simply interpolate kbib for every value of wavelenght !
    kint = interp1d(wbib, kbib, kind='linear')
    ndint = interp1d(wbib, ndbib, kind='linear')

    #########
    # define the spectral band ( wavmin and wavemax) of the radiation model
    # here from radiation RegCM standard regcm code

    wavmin = [
        0.2000, 0.2450, 0.2650, 0.2750, 0.2850, 0.2950, 0.3050, 0.3500, 0.6400,
        0.7000, 0.7010, 0.7010, 0.7010, 0.7010, 0.7020, 0.7020, 2.6300, 4.1600,
        4.1600
    ]

    wavmax = [
        0.2450, 0.2650, 0.2750, 0.2850, 0.2950, 0.3050, 0.3500, 0.6400, 0.7000,
        5.0000, 5.0000, 5.0000, 5.0000, 5.0000, 5.0000, 5.0000, 2.8600, 4.5500,
        4.5500
    ]
    #num = 7 for visible band standard scheme
    num = 7
    ## si RRTM set 1 == 1 to overwrite
    #if(1==2):
    #    # RRTM Shortwave spectral band limits (wavenumbers)
    #    #wavenum are in cm-1 / take the inverse for wavelenght
    #    wavenum1 =  np.array([2600., 3250., 4000., 4650., 5150., 6150., 7700., \
    #                          8050.,12850.,16000.,22650.,29000.,38000.,  820.])
    #    wavenum2 =  np.array([3250., 4000., 4650., 5150., 6150., 7700., 8050., \
    #                         12850.,16000.,22650.,29000.,38000.,50000., 2600.])
    #
    ## Longwave spectral band limits (wavenumbers)
    #    if(1==2):
    #       wavenum1 =  np.array([ 10., 350., 500., 630., 700., 820., \
    #                      980. ,1080. ,1180. ,1390. ,1480. ,1800. , \
    #                     2080. ,2250. ,2380. ,2600. ])
    #       wavenum2 =  np.array([350. , 500. , 630. , 700. , 820. , 980. , \
    #                     1080. ,1180. ,1390. ,1480. ,1800. ,2080. , \
    #                     2250. ,2380. ,2600. ,3250. ])
    ## determined from indica marc for the longwave
    #       wbib=  [3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 20, 30, 1100]
    #       kbib = [7.54E-2, 5.14E-2, 5.94E-2, 1.41E-1, 1.46E-1, 2.18E-1, \
    #                    5.35E-1, 3.70E-1, 1.18E-1,  2.28E-1, 2.79E-1, 6.12E-1,\
    #                    4.95E-1, 6.50E-1 ]
    #       nbib =   [1.49,  1.51,  1.58, 1.45,  1.46, 1.19,  1.86, 1.84, 1.78, \
    #                    1.65,  1.55,  2.25, 2.40, 2. ]
    #       kint = interp1d(wbib,kbib,kind='linear')
    #       ndint = interp1d(wbib,nbib,kind='linear')
    #    #convert to wavelenght in micron
    #    # visible is index
    #    wavmin  = np.power(wavenum2*1.E-4,-1.)
    #    wavmax  = np.power(wavenum1*1.E-4,-1.)
    #
    #    if (1==1):
    #       num = 7 # for visible band standard scheme
    #    if (1==2):
    #       num = 9 # for vis RRTM

    #print num

    #print wavmin
    #print wavmax

    # end of user deined parameter
    ##################################################################
    ####################################################################3

    # 1) calculate the effective radius of each bin (used in regcm )
    Sv = np.zeros(len(sbin) - 1)
    Ss = np.zeros(len(sbin) - 1)
    normb = np.zeros(len(sbin) - 1)

    for b in range(len(sbin) - 1):
        for dd in range(len(D)):
            if (D[dd] >= sbin[b] and D[dd] < sbin[b + 1]):
                Sv[b] = Sv[b] + D[dd]**3 * dND[dd]
                Ss[b] = Ss[b] + D[dd]**2 * dND[dd]
                normb[b] = normb[b] + dND[dd]
    Deff = Sv / Ss
    print Deff

    ## visu
    #
    #fig = plt.figure()
    #ax = fig.add_subplot(1,3,1)
    ##here plot dN/d(logD) !!
    #ax.plot(D,dND *D , color='blue')
    #ax.set_yscale('log')
    #ax.set_xscale('log')
    #ax.set_xlim([0.08, 65])
    #ax.set_ylim([1.E-4, 1])
    #ax.set_title("distribution and bins, dot= Deff")
    #ax.set_xlabel('D in micrometer')
    #plot also bin end effrad
    #for x in sbin:
    # ax.plot([x, x],[1.E-4, 1], color='black')
    #for x in Deff:
    # ax.scatter(x,2E-4, color='green')
    #
    #
    ##visu also the ref index spectral variation interp + values
    #ax2 = fig.add_subplot(1,3,2)
    ##xx = np.linspace(0.2,13,500)
    #xx = np.linspace(3,40,500)
    #ax2.plot(xx, ndint(xx), color='green')
    ##ax2.scatter(wbib,kbib)
    #ax2.set_title(" im ref index, dot = data, line = interp used for oppt calc. ")
    #ax2.set_xlabel('wavelenght in micrometer')

    #2  mie calculation
    ######################################
    #calculate optical properties per bin
    #######################################3
    # methode 1 considering only bin effective diam calculated before
    if (1 == 1):
        extb = np.zeros((len(sbin) - 1, len(wavmin)))
        ssab = np.zeros((len(sbin) - 1, len(wavmin)))
        asyb = np.zeros((len(sbin) - 1, len(wavmin)))
        for nband in range(len(wavmin)):
            specbin = np.linspace(wavmin[nband], wavmax[nband], 50)
            for db in range(len(Deff)):
                qext = 0.
                ssa = 0.
                asy = 0.

                for wl in range(len(specbin)):
                    sp = np.pi * Deff[db] / specbin[wl]
                    k = kint(specbin[wl])
                    nd = ndint(specbin[wl])
                    mie = Mie(x=sp, m=complex(nd, k))
                    qext = qext + mie.qsca() + mie.qabs()
                    qabs = mie.qabs()
                    ssa = ssa + mie.qsca() / (mie.qsca() + mie.qabs())
                    asy = asy + mie.asy()
                extb[db, nband] = extb[db, nband] + (qext / len(specbin)) / (
                    2. / 3. * rhop * Deff[db] * 1E-6)
                #cross section in m2/g
                ssab[db, nband] = ssab[db, nband] + (ssa / len(specbin))
                asyb[db, nband] = asyb[db, nband] + (asy / len(specbin))

    if (1 == 2):
        #method 2(slower) double integration  /more precise prblem mie return nan for extrem coarse particles
        # calculate the mie parameter for every diameter of the range, averaged on spectral band

        extb = np.zeros((len(sbin) - 1, len(wavmin)))
        ssab = np.zeros((len(sbin) - 1, len(wavmin)))
        asyb = np.zeros((len(sbin) - 1, len(wavmin)))

        for nband in range(len(wavmin)):
            specbin = np.linspace(wavmin[nband], wavmax[nband], 10)
            extd = np.zeros(len(D))
            ssad = np.zeros(len(D))
            asyd = np.zeros(len(D))
            for db in range(len(D)):
                qext = 0.
                ssa = 0.
                asy = 0.
                for wl in range(len(specbin)):
                    sp = np.pi * D[db] / specbin[wl]
                    k = kint(specbin[wl])
                    nd = ndint(specbin[wl])
                    mie = Mie(x=sp, m=complex(nd, k))
                    qext = qext + mie.qsca() + mie.qabs()
                    ssa = ssa + mie.qsca() / (mie.qsca() + mie.qabs())
                    asy = asy + mie.asy()
                extd[db] = qext / len(specbin) / (2. / 3. * rhop * D[db] *
                                                  1E-6)
                ssad[db] = ssa / len(specbin)
                asyd[db] = asy / len(specbin)
            # perform the bin wighting av according to distibution
            for b in range(len(sbin) - 1):
                if (D[db] >= sbin[b] and D[db] < sbin[b + 1]):
                    extb[b,
                         nband] = extb[b,
                                       nband] + extd[db] * dND[db] / normb[b]
                    ssab[b,
                         nband] = ssab[b,
                                       nband] + ssad[db] * dND[db] / normb[b]
                    asyb[b,
                         nband] = asyb[b,
                                       nband] + asyd[db] * dND[db] / normb[b]

    # 3  nan out for the big bin which can have nan values ....
    # the kext is set  very low which means that the bin won't matter much in the rad
    extb[np.isnan(extb)] = 1.E-20
    asyb[np.isnan(asyb)] = 0.99
    ssab[np.isnan(ssab)] = 0.5

    print "extb vis", extb[:, num]
    print "ssab vis", ssab[:, num]
    print "asyb vis", asyb[:, num]
    #print "absb vis", extb[:,num] * ssab[:,num]

    ##4 visu  oppt / bin
    #
    #ax3 = fig.add_subplot(1,3,3)
    #xx = np.linspace(0.2,4,500)
    #ax3.set_xlim([0.08,65 ])
    #ax3.set_ylim([0, 5])
    #for n in range(len(sbin)-1):
    # ax3.plot([sbin[n], sbin[n+1]],[extb[n,num],extb[n,num]], color='black')
    # ax3.plot([sbin[n], sbin[n+1]],[ssab[n,num],ssab[n,num]], color='blue')
    # ax3.plot([sbin[n], sbin[n+1]],[asyb[n,num],asyb[n,num]], color='red')
    #
    #ax3.set_title(" bin oppt vis: blk:kext, blue:ssa, red:asy ")
    #ax3.set_xscale('log')
    #ax3.set_xlabel('D in micrometer')

    # finally  save in afile in a format close to mod_rad_aerosol block data
    # will just need copy paste + a few edit for fortan
    # file = open("aeroppt_blocl.txt", "w")
    compound = os.path.splitext(os.path.basename(filename))[0]
    np.savetxt(compound + '_Deff.txt', Deff, fmt='%7.5E', delimiter=', ')
    np.savetxt(compound + '_extb.txt', extb, fmt='%7.5E', delimiter=', ')
    np.savetxt(compound + '_ssab.txt', ssab, fmt='%7.5E', delimiter=', ')
    np.savetxt(compound + '_asyb.txt', asyb, fmt='%7.5E', delimiter=', ')