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;
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
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()
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()}
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)))
# 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 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=', ')