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()
#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'])
# 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?
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)
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]$')