PUFF MODEL Supplementary Material

Main model

This “main” program imported all the modules, and ran the total time for-loop.

import numpy
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.basemap import Basemap

from parameters import *
from variables import *
from initial import *
from advectionx import*
from advectiony import*
from advectionz import*
from dispersionx import *
from dispersiony import *
from dispersionz import *
from degree_conversion import *
from settling import *
from landed import *

#[height,lat,lon]; [z,y,x]
Rold = initial(sigma_lat,sigma_lon)

lon1 = 65.
lon2 = 155.
lat1 = -25.
lat2 = 25.

fig = plt.figure(1,facecolor = 'white')
ax = fig.add_subplot(111, projection='3d')
ax.set_xlabel('longitude [decimal degees]')
ax.set_ylabel('latitude [decimal degees]')
ax.set_zlabel('altitude [meters]')
ax.set_zlim(0,20000)
ax.set_ylim(lat1,lat2)
ax.set_xlim(lon1,lon2)
ax.scatter(Rold[:,2],Rold[:,1],Rold[:,0],c='r',s=10)
ax.set_title('Particle Trajectory')


plt.figure(2)
m = Basemap(llcrnrlon=lon1,llcrnrlat=lat1,urcrnrlon=lon2,urcrnrlat=lat2,
            projection='lcc',lon_0=start_lon,lat_0=start_lat,
            resolution ='l',area_thresh=1000.)
m.drawcoastlines(linewidth=0.25)
m.drawcountries(linewidth=0.25)
m.drawparallels(np.arange(lat1,lat2,10),labels=[1,1,0,0])
m.drawmeridians(np.arange(lon1,lon2,10),labels=[0,0,0,1])
x, y = m(Rold[:,2],Rold[:,1])
m.scatter(x,y,s=20,marker='o',color='r',zorder=10)
plt.title('Particle Trajectory')

j=3
for t in xrange(1,time_steps):
    t_index = int(float(t)/float(time_steps)*20.)
    t_time_1 = float(t)/float(time_steps)*20.
    t_time_2 = (float(t)+0.5)/float(time_steps)*20.
    t_time_3 = (float(t)+0.5)/float(time_steps)*20.
    t_time_4 = (float(t)+1.0)/float(time_steps)*20.    
    
    dx_lat, dx_lon = degree_to_dx(R)
    
    #RUNGA KUTTA 
    R_step1[:,:] = 0.0
    R_step2[:,:] = 0.0
    R_step3[:,:] = 0.0
    R_step4[:,:] = 0.0
    #dispersion
    dispz_temp = dispersionz(Active) * dt
    dispy_temp = dispersiony(Active) * dt / dx_lat
    dispx_temp = dispersionx(Active) * dt / dx_lon
    R_step1[:,0] += dispz_temp
    R_step2[:,0] += dispz_temp
    R_step3[:,0] += dispz_temp
    R_step4[:,0] += dispz_temp
    R_step1[:,1] += dispy_temp
    R_step2[:,1] += dispy_temp
    R_step3[:,1] += dispy_temp
    R_step4[:,1] += dispy_temp
    R_step1[:,2] += dispx_temp
    R_step2[:,2] += dispx_temp
    R_step3[:,2] += dispx_temp
    R_step4[:,2] += dispx_temp
    
    #settling
    R_step1[:,0] -= settling(D,Active) * dt
    R_step2[:,0] -= settling(D,Active) * dt
    R_step3[:,0] -= settling(D,Active) * dt
    R_step4[:,0] -= settling(D,Active) * dt
    
    R_step1[:,0] += advectionz(Rold,Active,t_index,t_time_1) * dt
    R_step1[:,1] += advectiony(Rold,Active,t_index,t_time_1) * dt / dx_lat
    R_step1[:,2] += advectionx(Rold,Active,t_index,t_time_1) * dt / dx_lon
    R_step2[:,0] += advectionz(Rold+R_step1/2.0,Active,t_index,t_time_2) * dt
    R_step2[:,1] += advectiony(Rold+R_step1/2.0,Active,t_index,t_time_2) * dt / dx_lat
    R_step2[:,2] += advectionx(Rold+R_step1/2.0,Active,t_index,t_time_2) * dt / dx_lon
    R_step3[:,0] += advectionz(Rold+R_step2/2.0,Active,t_index,t_time_3) * dt
    R_step3[:,1] += advectiony(Rold+R_step2/2.0,Active,t_index,t_time_3) * dt / dx_lat
    R_step3[:,2] += advectionx(Rold+R_step2/2.0,Active,t_index,t_time_3) * dt / dx_lon
    R_step4[:,0] += advectionz(Rold+R_step3,Active,t_index,t_time_4) * dt
    R_step4[:,1] += advectiony(Rold+R_step3,Active,t_index,t_time_4) * dt / dx_lat
    R_step4[:,2] += advectionx(Rold+R_step3,Active,t_index,t_time_4) * dt / dx_lon

    Rnew =  Rold + R_step1/6.0 + R_step2/3.0 + R_step3/3.0 + R_step4/6.0    
    Active, Rnew[:,0] = landed(Rnew[:,0],Active)
    
    if t%(time_steps/50)==0:
        ax.scatter(Rnew[:,2],Rnew[:,1],Rnew[:,0],c='k',s=1,alpha=float(t)/float(time_steps-1)*0.5)
        plt.figure(2,facecolor='white')
        x, y = m(Rnew[:,2],Rnew[:,1])
        m.scatter(x,y,s=1,marker='o',color='k',alpha=float(t)/float(time_steps-1)*0.5,zorder=10)
        print str(int(100.*float(t)/float(time_steps-1))) + '% done'
    if t%(time_steps/10)==0:
        plt.figure(j)
        m = Basemap(llcrnrlon=lon1,llcrnrlat=lat1,urcrnrlon=lon2,urcrnrlat=lat2,
            projection='lcc',lon_0=start_lon,lat_0=start_lat,
            resolution ='l',area_thresh=1000.)
        m.drawcoastlines(linewidth=0.25)
        m.drawcountries(linewidth=0.25)
        m.drawparallels(np.arange(lat1,lat2,10),labels=[1,1,0,0])
        m.drawmeridians(np.arange(lon1,lon2,10),labels=[0,0,0,1])
        x, y = m(start_lon,start_lat)
        m.scatter(x,y,s=20,marker='o',color='r',zorder=10)
        x, y = m(Rnew[:,2],Rnew[:,1])
        m.scatter(x,y,s=2,marker='o',color='k',zorder=10,alpha=0.5)
        plt.title('Plume after ' + str((j-2)*12) + ' hrs')

        fig = plt.figure(j+10,facecolor = 'white')
        axx = fig.add_subplot(111, projection='3d')
        axx.set_xlabel('longitude [decimal degees]')
        axx.set_ylabel('latitude [decimal degees]')
        axx.set_zlabel('altitude [meters]')
        axx.set_zlim(0,20000)
        axx.set_ylim(lat1,lat2)
        axx.set_xlim(lon1,lon2)
        axx.scatter(Rnew[:,2],Rnew[:,1],Rnew[:,0],c='k',s=1)
        axx.set_title('Plume after ' + str((j-2)*12) + ' hrs')
        j+=1
        
    Rold = Rnew

for i in xrange(0,num_particles):
    if Active[i] == 0:
        ax.scatter(Rnew[i,2],Rnew[i,1],Rnew[i,0],c='g',s=10)
        plt.figure(2,facecolor='white')
        x, y = m(Rnew[i,2],Rnew[i,1])
        m.scatter(x,y,s=2,marker='o',color='g',zorder=10)
    else:
        ax.scatter(Rnew[i,2],Rnew[i,1],Rnew[i,0],c='b',s=10)
        plt.figure(2,facecolor='white')
        x, y = m(Rnew[i,2],Rnew[i,1])
        m.scatter(x,y,s=10,marker='o',color='b',zorder=10)
plt.figure(1,facecolor='white')
plt.savefig('3D-final.png')
plt.figure(2,facecolor='white')
plt.savefig('2D-final.png')
plt.figure(3,facecolor='white')
plt.savefig('2D-12hr.png')
plt.figure(4,facecolor='white')
plt.savefig('2D-24hr.png')
plt.figure(5,facecolor='white')
plt.savefig('2D-36hr.png')
plt.figure(6,facecolor='white')
plt.savefig('2D-48hr.png')
plt.figure(7,facecolor='white')
plt.savefig('2D-60hr.png')
plt.figure(8,facecolor='white')
plt.savefig('2D-72hr.png')
plt.figure(9,facecolor='white')
plt.savefig('2D-84hr.png')
plt.figure(10,facecolor='white')
plt.savefig('2D-96hr.png')
plt.figure(11,facecolor='white')
plt.savefig('2D-108hr.png')
plt.figure(12,facecolor='white')
plt.savefig('2D-120hr.png')
plt.figure(13,facecolor='white')
plt.savefig('3D-12hr.png')
plt.figure(14,facecolor='white')
plt.savefig('3D-24hr.png')
plt.figure(15,facecolor='white')
plt.savefig('3D-36hr.png')
plt.figure(16,facecolor='white')
plt.savefig('3D-48hr.png')
plt.figure(17,facecolor='white')
plt.savefig('3D-60hr.png')
plt.figure(18,facecolor='white')
plt.savefig('3D-72hr.png')
plt.figure(19,facecolor='white')
plt.savefig('3D-84hr.png')
plt.figure(20,facecolor='white')
plt.savefig('3D-96hr.png')
plt.figure(21,facecolor='white')
plt.savefig('3D-108hr.png')
plt.figure(22,facecolor='white')
plt.savefig('3D-120hr.png')
    
#plt.show()

Modules

The following are modules that were imported into the main program, main.py.

advectionx.py

This module decided the U wind velocity at each particle.

#advection-x
import numpy as np
from parameters import *
import scipy.interpolate as interp
R_advection = np.zeros((num_particles))

def advectionx(R,A,T,t):
    for i in xrange(0,num_particles):
        if A[i] == 1 and R[i,0] > 0.0:
            alt_part = R[i,0]
            lat_part = R[i,1]
            lon_part = R[i,2]
            a = int(R[i,0]/29000.*29.)
            b = int((R[i,1]+90.)/180.*73.)
            c = int(R[i,2]/360.*144.)
            if a == 29:
                a_high = a
            else:
                a_high = a+1
                
            alt_low = alt_coor[a]
            alt_high = alt_coor[a_high]
            lat_down = lat_coor[b]
            lat_up = lat_coor[b+1]
            lon_left = lon_coor[c]
            lon_right = lon_coor[c+1]
            
            #trilinear interpolation
            #time 1
            interp_x1 = (lon_part - lon_left) / (lon_right - lon_left) * (U[T,a,b,c+1] - U[T,a,b,c]) + U[T,a,b,c]
            interp_x2 = (lon_part - lon_left) / (lon_right - lon_left) * (U[T,a,b+1,c+1] - U[T,a,b+1,c]) + U[T,a,b+1,c]
            interp_x3 = (lon_part - lon_left) / (lon_right - lon_left) * (U[T,a_high,b,c+1] - U[T,a_high,b,c]) + U[T,a_high,b,c]
            interp_x4 = (lon_part - lon_left) / (lon_right - lon_left) * (U[T,a_high,b+1,c+1] - U[T,a_high,b+1,c]) + U[T,a_high,b+1,c]

            interp_y1 = (lat_part - lat_down) / (lat_up - lat_down) * (interp_x2 - interp_x1) + interp_x1
            interp_y2 = (lat_part - lat_down) / (lat_up - lat_down) * (interp_x4 - interp_x3) + interp_x3

            if a_high == a:
                U_interp_1 = (interp_y1+interp_y2)/2.0
            else:
                U_interp_1 = (alt_part - alt_low) / (alt_high - alt_low) * (interp_y2 - interp_y1) + interp_y1
              
            #time 2
            interp_x1 = (lon_part - lon_left) / (lon_right - lon_left) * (U[T+1,a,b,c+1] - U[T+1,a,b,c]) + U[T+1,a,b,c]
            interp_x2 = (lon_part - lon_left) / (lon_right - lon_left) * (U[T+1,a,b+1,c+1] - U[T+1,a,b+1,c]) + U[T+1,a,b+1,c]
            interp_x3 = (lon_part - lon_left) / (lon_right - lon_left) * (U[T+1,a_high,b,c+1] - U[T+1,a_high,b,c]) + U[T+1,a_high,b,c]
            interp_x4 = (lon_part - lon_left) / (lon_right - lon_left) * (U[T+1,a_high,b+1,c+1] - U[T+1,a_high,b+1,c]) + U[T+1,a_high,b+1,c]

            interp_y1 = (lat_part - lat_down) / (lat_up - lat_down) * (interp_x2 - interp_x1) + interp_x1
            interp_y2 = (lat_part - lat_down) / (lat_up - lat_down) * (interp_x4 - interp_x3) + interp_x3

            if a_high == a:
                U_interp_2 = (interp_y1+interp_y2)/2.0
            else:
                U_interp_2 = (alt_part - alt_low) / (alt_high - alt_low) * (interp_y2 - interp_y1) + interp_y1
                  
            R_advection[i] =  (U_interp_2 - U_interp_1) / 1.0 * (t - float(T)) + U_interp_1

        else:
            R_advection[i] = 0.0
            
    return R_advection

advectiony.py

This module decided the V wind velocity at each particle.
#advection
import numpy as np
from parameters import *
R_advection = np.zeros((num_particles))

def advectiony(R,A,T,t):
for i in xrange(0,num_particles):
if A[i] == 1 and R[i,0] > 0.0:
alt_part = R[i,0]
lat_part = R[i,1]
lon_part = R[i,2]
a = int(R[i,0]/29000.*29.)
b = int((R[i,1]+90.)/180.*73.)
c = int(R[i,2]/360.*144.)
if a == 29:
a_high = a
else:
a_high = a+1

alt_low = alt_coor[a]
alt_high = alt_coor[a_high]
lat_down = lat_coor[b]
lat_up = lat_coor[b+1]
lon_left = lon_coor
lon_right = lon_coor

#time 1
interp_x1 = (lon_part – lon_left) / (lon_right – lon_left) * (V[T,a,b,c+1] – V[T,a,b,c]) + V[T,a,b,c]
interp_x2 = (lon_part – lon_left) / (lon_right – lon_left) * (V[T,a,b+1,c+1] – V[T,a,b+1,c]) + V[T,a,b+1,c]
interp_x3 = (lon_part – lon_left) / (lon_right – lon_left) * (V[T,a_high,b,c+1] – V[T,a_high,b,c]) + V[T,a_high,b,c]
interp_x4 = (lon_part – lon_left) / (lon_right – lon_left) * (V[T,a_high,b+1,c+1] – V[T,a_high,b+1,c]) + V[T,a_high,b+1,c]

interp_y1 = (lat_part – lat_down) / (lat_up – lat_down) * (interp_x2 – interp_x1) + interp_x1
interp_y2 = (lat_part – lat_down) / (lat_up – lat_down) * (interp_x4 – interp_x3) + interp_x3

if a_high == a:
V_interp_1 = (interp_y1+interp_y2)/2.0
else:
V_interp_1 = (alt_part – alt_low) / (alt_high – alt_low) * (interp_y2 – interp_y1) + interp_y1

#time 2
interp_x1 = (lon_part – lon_left) / (lon_right – lon_left) * (V[T+1,a,b,c+1] – V[T+1,a,b,c]) + V[T+1,a,b,c]
interp_x2 = (lon_part – lon_left) / (lon_right – lon_left) * (V[T+1,a,b+1,c+1] – V[T+1,a,b+1,c]) + V[T+1,a,b+1,c]
interp_x3 = (lon_part – lon_left) / (lon_right – lon_left) * (V[T+1,a_high,b,c+1] – V[T+1,a_high,b,c]) + V[T+1,a_high,b,c]
interp_x4 = (lon_part – lon_left) / (lon_right – lon_left) * (V[T+1,a_high,b+1,c+1] – V[T+1,a_high,b+1,c]) + V[T+1,a_high,b+1,c]

interp_y1 = (lat_part – lat_down) / (lat_up – lat_down) * (interp_x2 – interp_x1) + interp_x1
interp_y2 = (lat_part – lat_down) / (lat_up – lat_down) * (interp_x4 – interp_x3) + interp_x3

if a_high == a:
V_interp_2 = (interp_y1+interp_y2)/2.0
else:
V_interp_2 = (alt_part – alt_low) / (alt_high – alt_low) * (interp_y2 – interp_y1) + interp_y1

R_advection[i] = (V_interp_2 – V_interp_1) / 1.0 * (t – float(T)) + V_interp_1

else:
R_advection[i] = 0.0

return R_advection


advectionz.py

This module decided the W wind velocity at each particle.

#advection
import numpy as np
from parameters import *
R_advection = np.zeros((num_particles))

def advectionz(R,A,T,t):
    for i in xrange(0,num_particles):
        if A[i] == 1 and R[i,0] > 0.0:
            alt_part = R[i,0]
            lat_part = R[i,1]
            lon_part = R[i,2]
            a = int(R[i,0]/29000.*29.)
            b = int((R[i,1]+90.)/180.*73.)
            c = int(R[i,2]/360.*144.)
            if a == 29:
                a_high = a
            else:
                a_high = a+1
                
            alt_low = alt_coor[a]
            alt_high = alt_coor[a_high]
            lat_down = lat_coor[b]
            lat_up = lat_coor[b+1]
            lon_left = lon_coor[c]
            lon_right = lon_coor[c+1]
            
            #trilinear interpolation
            #time 1
            interp_x1 = (lon_part - lon_left) / (lon_right - lon_left) * (W[T,a,b,c+1] - W[T,a,b,c]) + W[T,a,b,c]
            interp_x2 = (lon_part - lon_left) / (lon_right - lon_left) * (W[T,a,b+1,c+1] - W[T,a,b+1,c]) + W[T,a,b+1,c]
            interp_x3 = (lon_part - lon_left) / (lon_right - lon_left) * (W[T,a_high,b,c+1] - W[T,a_high,b,c]) + W[T,a_high,b,c]
            interp_x4 = (lon_part - lon_left) / (lon_right - lon_left) * (W[T,a_high,b+1,c+1] - W[T,a_high,b+1,c]) + W[T,a_high,b+1,c]

            interp_y1 = (lat_part - lat_down) / (lat_up - lat_down) * (interp_x2 - interp_x1) + interp_x1
            interp_y2 = (lat_part - lat_down) / (lat_up - lat_down) * (interp_x4 - interp_x3) + interp_x3

            if a_high == a:
                W_interp_1 = (interp_y1+interp_y2)/2.0
            else:
                W_interp_1 = (alt_part - alt_low) / (alt_high - alt_low) * (interp_y2 - interp_y1) + interp_y1
              
            #time 2
            interp_x1 = (lon_part - lon_left) / (lon_right - lon_left) * (W[T+1,a,b,c+1] - W[T+1,a,b,c]) + W[T+1,a,b,c]
            interp_x2 = (lon_part - lon_left) / (lon_right - lon_left) * (W[T+1,a,b+1,c+1] - W[T+1,a,b+1,c]) + W[T+1,a,b+1,c]
            interp_x3 = (lon_part - lon_left) / (lon_right - lon_left) * (W[T+1,a_high,b,c+1] - W[T+1,a_high,b,c]) + W[T+1,a_high,b,c]
            interp_x4 = (lon_part - lon_left) / (lon_right - lon_left) * (W[T+1,a_high,b+1,c+1] - W[T+1,a_high,b+1,c]) + W[T+1,a_high,b+1,c]

            interp_y1 = (lat_part - lat_down) / (lat_up - lat_down) * (interp_x2 - interp_x1) + interp_x1
            interp_y2 = (lat_part - lat_down) / (lat_up - lat_down) * (interp_x4 - interp_x3) + interp_x3

            if a_high == a:
                W_interp_2 = (interp_y1+interp_y2)/2.0
            else:
                W_interp_2 = (alt_part - alt_low) / (alt_high - alt_low) * (interp_y2 - interp_y1) + interp_y1
                  
            R_advection[i] =  (W_interp_2 - W_interp_1) / 1.0 * (t - float(T)) + W_interp_1
            
        else:
            R_advection[i] = 0.0
    return R_advection

degree_conversion.py

This module converted a velocity in meters per second to a velocity in decimal degrees per second.

#settling
import numpy as np
from parameters import *
a = 6378137.0

def degree_to_dx(R):
    h = R[:,0]
    lat = R[:,1]
    lon = R[:,2]
    dx_lat = np.pi / 180. * (a + h)
    dx_lon = np.pi / 180. * (a + h) * np.cos(lat * np.pi / 180. )
    
    return dx_lat, dx_lon

dispersionx.py

This module simulates the dispersion in the x-direction.

#dispersion
import numpy as np
from parameters import *
R_dispersion = np.zeros((num_particles))

def dispersionx(A):
    c_h = np.sqrt(2.0 * K_h /dt)
    for i in xrange(0,num_particles):
        if A[i] == 1:
            R_dispersion[i] = np.random.normal(0.0,c_h)
        else:
            R_dispersion[i] = 0.0

    return R_dispersion

dispersiony.py

This module simulates the dispersion in the y-direction.

#dispersion
import numpy as np
from parameters import *
R_dispersion = np.zeros((num_particles))

def dispersiony(A):
    c_h = np.sqrt(2.0 * K_h /dt)
    for i in xrange(0,num_particles):
        if A[i] == 1:
            R_dispersion[i] = np.random.normal(0.0,c_h)
        else:
            R_dispersion[i] = 0.0

    return R_dispersion

dispersionz.py

This module simulates the dispersion in the z-direction.

#dispersion
import numpy as np
from parameters import *
R_dispersion = np.zeros((num_particles))

def dispersionz(A):
    c_v = np.sqrt(2.0 * K_v /dt)
    for i in xrange(0,num_particles):
        if A[i] == 1:
            R_dispersion[i] = np.random.normal(0.0,c_v)
        else:
            R_dispersion[i] = 0.0

    return R_dispersion

initial.py

This module sets up the initial position of the particles.

import numpy as np
from parameters import *
R = np.zeros((num_particles,3))

def initial(sigma_lat,sigma_lon):
    for i in xrange(0,num_particles):
        R[i,0] = 15000.* np.random.uniform()
        R[i,1] = np.random.normal(start_lat,sigma_lat)
        R[i,2] = np.random.normal(start_lon,sigma_lon)

    return R


landed.py

This module determines whether the particle is in the atmosphere or on the ground.

#landed
import numpy as np
from parameters import *

def landed(H,A):
    for i in xrange(0,num_particles):
        if A[i] == 1.0 and H[i] <= 0.0:
            A[i] = 0.0
            H[i] = 0.0
        if H[i] > alt_coor[29]:
            H[i] = alt_coor[29]
        if H[i] <= 0.0:
            H[i] = 0.0
    return A, H

parameters.py

This module sets up our parameters.

import numpy as np
#parameters

num_particles = 1000
time = 5.0 #days
dt = 10.0 * 60.#minutes
time_steps = int(time * 24.0 * 3600. / dt) + 1

D_log = np.zeros((num_particles))
for i in xrange(0,num_particles):
    D_log[i] = np.random.normal(-5.0,2.5)
D = 10. ** (D_log)

K_h = 2.0 * (10. **4.)
K_v = 10.

start_lat = 15.141667
start_lon = 120.35

sigma_lon = .01
sigma_lat = .01

U = np.load('u_wind.npy')
V = np.load('v_wind.npy')
W = np.load('w_wind.npy')

alt_coor = np.linspace(0,29000,30)
lat_coor = np.linspace(-90.,90.,73)
lon_coor = np.linspace(0.,360.,144)


settling.py

This module estimates the settling of the particles as a function of its diameter.

#settling
import numpy as np
from parameters import *
R_settling = np.zeros((num_particles))
constant = 1.09 * (10. ** 9.)

def settling(D,A):
    for i in xrange(0,num_particles):
        if A[i] == 1:
            R_settling[i] = 2.0 / 9.0 * constant * (D[i] ** 2.0)
        else:
            R_settling[i] = 0.0
    return R_settling

variables.py

This module sets up numpy arrays for our variables.

#variables
import numpy as np
from parameters import *

#particle #,  location of paritcles
Rnew = np.zeros((num_particles,3)) #lat,lon,alt
Rold = np.zeros((num_particles,3)) #lat,lon,alt
R_step1 = np.zeros((num_particles,3)) #lat,lon,alt
R_step2 = np.zeros((num_particles,3)) #lat,lon,alt
R_step3 = np.zeros((num_particles,3)) #lat,lon,alt
R_step4 = np.zeros((num_particles,3)) #lat,lon,alt
Active = np.ones((num_particles)) #lat,lon,alt