pt_const程式說明

 

說明

  • 整體工作流程詳見CMAQ點源常數檔案之準備([[2022-07-06-pt_const]])
  • 目的:產生CMAQ所需的點源排放量中常數、不隨時間變化的部分
  • 相關程式見[[2022-07-07-pt_timvar.py]]及[[2022-07-06-pt_timvar]]說明

執行

  • 引數:CAMx分月高空點源,MM=01~12
for MM in {01..12};
do python pt_constLL.py fortBE.413_teds11.ptse$MM.nc
done
  • 輸入檔(ptse檔案):ptsEnHRBE.py港區計算結果([[2022-07-15-ptsEnHRBE.py程式說明]])
  • 結果:teds11.YYMM.const.nc

版本

  • 點源座標系統為LL
  • 版本:
    • TWN_3X3範圍、資料來源為TEDS資料庫,點源座標系統為LL
    • EAsia_81K範圍,除了TEDS之外,還讀取REAS處理結果

粗細網格pt_const程式版本之比較

項目 EAsia_81K TWN_3X3 說明
資料庫 REAS+TEDS TEDS 前者範圍較大需要REAS資料庫
引數及主要檔 逐月CAMx高空點源nc檔案 逐月CAMx高空點源nc檔案 (same)
其他輸入檔 point_SPEC.csv, *nc檔模版 *nc檔模版 csv詳見REASv3.1點源之讀取、格式轉換與合併
結果檔名 teds11.YYMM.const.nc, point_reasYYMM.csv(讓pt_timvar.py讀取) teds11.YYMM.const.nc (same)

*nc檔模版來自於USEPA之範例檔。

分段說明

模組

  • 時間標籤轉換副程式(dt2jul及jul2dt)
     1  import numpy as np
     2  import netCDF4
     3  import PseudoNetCDF as pnc
     4  import os,sys,twd97
     5  from pyproj import Proj
     6  import subprocess
     7  from pandas import *
     8  import datetime
     9
    10  def dt2jul(dt):
    11    yr=dt.year
    12    deltaT=dt-datetime.datetime(yr,1,1)
    13    deltaH=int((deltaT.total_seconds()-deltaT.days*24*3600)/3600.)
    14    return (yr*1000+deltaT.days+1,deltaH*10000)
    15
    16  def jul2dt(jultm):
    17    jul,tm=jultm[:]
    18    yr=int(jul/1000)
    19    ih=int(tm/10000.)
    20    return datetime.datetime(yr,1,1)+datetime.timedelta(days=int(jul-yr*1000-1))+datetime.timedelta(hours=ih)
    21
    22
  • 讀入檔案名稱的月份
  • 準備座標轉換之套件
    23  mon=int(sys.argv[1][-5:-3])
    24  #join the pollutants for this month
    25  pth='/nas1/cmaqruns/2016base/data/ptse/'
    26  #prepare interceptions
    27  Latitude_Pole, Longitude_Pole = 23.61000, 120.9900
    28  pnyc = Proj(proj='lcc', datum='NAD83', lat_1=10, lat_2=40, lat_0=Latitude_Pole, lon_0=Longitude_Pole, x_0=0, y_0=0.0)
    29

讀入CAMx點源檔案

  • 讀取各維度變數名稱
  • 讀取全域變數
    30  fname1=sys.argv[1]
    31  pt=netCDF4.Dataset(fname1, 'r')
    32  v3=list(filter(lambda x:pt.variables[x].ndim==3, [i for i in pt.variables]))
    33  v2=list(filter(lambda x:pt.variables[x].ndim==2, [i for i in pt.variables]))
    34  v1=list(filter(lambda x:pt.variables[x].ndim==1, [i for i in pt.variables]))
    35  nhr,nvar,dt=pt.variables[v3[0]].shape
    36  nt,nopts=pt.variables[v2[0]].shape
    37  XCELL=pt.XCELL
    38  XORIG=pt.XORIG
    39  YORIG=pt.XORIG
    40
  • 讀取起始時間(0800 LST)
  • 準備ncks程式
    41  tb=pt.STIME-80000 #UTC
    42  bdate=jul2dt([pt.SDATE,pt.STIME])
    43  fname1=fname1.replace('fortBE.413_','').replace('ptse','19').replace('.nc','')
    44  fname=fname1+'.const.nc'
    45  fname0=pth+'stack_groups_ptnonipm_12US1_2016ff_16j.nc' #as template
    46
    47  #ncks path
    48  path={'114-32-164-198.HINET-IP.hinet.net':'/opt/anaconda3/bin/', 'node03':'/usr/bin/', \
    49          'master':'/cluster/netcdf/bin/','DEVP':'/usr/bin/'}
    50  hname=subprocess.check_output('echo $HOSTNAME',shell=True).decode('utf8').strip('\n')
    51  if hname not in path:
    52    sys.exit('wrong HOSTNAME')
    53  ncks=path[hname]+'ncks'

由既有模版使用ncks切出所要的長度,成為輸出檔案的底版。

    54  x=list(pt.variables['xcoord'][:nopts])
    55  y=list(pt.variables['ycoord'][:nopts])
    56  lon, lat = pnyc(x, y, inverse=True)
    57
    58  os.system(ncks+' -O -d ROW,1,'+str(nopts)+' '+fname0+' '+fname)

開啟輸出檔,寫入全域變數。

    59  nc = netCDF4.Dataset(fname,'r+')
    60  nc.NROWS=nopts
    61  nc.GDNAM='TWN_3X3'
    62  nc.P_ALP = np.array(10.)
    63  nc.P_BET = np.array(40.)
    64  nc.P_GAM = np.array(120.98999786377)
    65  nc.XCENT = np.array(120.98999786377)
    66  nc.YCENT = np.array(23.6100196838379)
    67  nc.XCELL=XCELL #27000.000
    68  nc.YCELL=XCELL #27000.000
    69  nc.XORIG=XORIG #-877500.0
    70  nc.YORIG=XORIG #-877500.0
    71  nc.SDATE,nc.STIME=dt2jul(bdate+datetime.timedelta(hours=-8))
    72

參數名稱、單位、其他對照與轉換

  • 點源變數名稱:CMAQ對照到CAMx
  • 單位轉換:每小時->每秒
  • 給定經緯度、網格位置、時間標籤等
    73  mp={'STKDM':'stkdiam','STKHT':'stkheight','STKTK':'stktemp','STKVE':'stkspeed','XLOCA':'xcoord', 'YLOCA':'ycoord',}
    74
    75  for v in mp:
    76    nc.variables[v][0,0,:,0]=pt.variables[mp[v]][:]
    77  #velocity is m/hr in CAMx pt, but in m/s in CMAQ_pt
    78  nc.variables['STKVE'][0,0,:,0]=pt.variables[mp[v]][:]/3600.
    79  nc.variables['IFIP'][0,0,:,0]=[1000+i for i in range(nopts)]
    80  nc.variables['ISTACK'][0,0,:,0]=[1+i for i in range(nopts)]
    81
    82  nc.variables['COL'][0,0,:,0]=[int((i-nc.XORIG)/nc.XCELL) for i in x]
    83  nc.variables['ROW'][0,0,:,0]=[int((i-nc.YORIG)/nc.YCELL) for i in y]
    84  nc.variables['TFLAG'][0,:,0]=[nc.SDATE for i in range(nc.NVARS)]
    85  nc.variables['TFLAG'][0,:,1]=[nc.STIME for i in range(nc.NVARS)]
    86  nc.variables['LATITUDE'][0,0,:,0]=lat
    87  nc.variables['LONGITUDE'][0,0,:,0]=lon
    88  nc.close()

EAsia_81K 版本差異

輸入全年分項檔案

  • 讀出其中的座標以進行轉換
  • 讀出當月數據並寫成檔案以供pt_timvar.py使用
28a16,55
> XCELL=81000.000
> XORIG=-2389500.
>
> dfa=DataFrame({})
> for fn in fnames:
>   spec=fn.split('/')[-1].replace('point_','').replace('.csv','').replace('./','')
>   df=read_csv(fn)
>   #interceptions
>   lat,lon=(list(df.lat),list(df.lon))
>   x,y=pnyc(lon, lat, inverse=False)
>   df['x_m'],df['y_m']=(x,y)
>   boo=(df['x_m']>=XORIG) & (df['x_m']<=-XORIG) & (df['y_m']>=XORIG) & (df['y_m']<=-XORIG)
>   df=df.loc[boo].reset_index(drop=True)
>   #reduction
>   df.lat=[round(i,1) for i in df.lat]
>   df.lon=[round(i,1) for i in df.lon]
>   c=df.iloc[:,[0,1,mon+1]]
>   c.columns=['lon','lat',spec]
>   c=pivot_table(c,index=['lon','lat'],values=spec,aggfunc=sum).reset_index()
>   if fn==fnames[0]:
>     dfa=c
>   else:
>     dfa=merge(dfa,c,on=['lon','lat'],how='outer')
> df=dfa.fillna(0)
>
> fac=1000.*1000./monthrange(2015,mon)[1]/24/3600.
> mws={'BC':1,'BENZENE':78.11,'BUTANES':58.12,'CO':28, 'CO2':44, 'ETHANE':30.07,
>        'FORMALDEHYDE':30.031, 'INTERNAL_ALKENES':28.05, 'KETONES':86.13, 'NH3':17, 'NOX':46, 'OC':1,
>        'OTHER_ALKANES':58.12, 'OTHER_AROMATICS':106.16, 'PENTANES':72.15, 'PM10':1, 'PM25':1,
>        'PROPANE':44.1 , 'SO2':64, 'TERMINAL_ALKENES':28.05, 'TOLUENE':92.14, 'TOTAL_NMV':58.12,
>        'XYLENES':106.16}
>
> #units of gmole/s or gram/s
> for c in [ i for i in df.columns if i not in ['lon','lat']]:
>   if c not in mws:continue
>   df[c]=np.array(df[c])*fac/mws[c]
> lat,lon=(list(df.lat),list(df.lon))
> x,y=pnyc(lon, lat, inverse=False)
> df['x_m'],df['y_m']=(x,y)
> df.set_index('lon').to_csv('point_reas16'+sys.argv[1][-5:-3]+'.csv')

在TEDS之後再加上REAS數據

53,55c76,78
< ncks=path[hname]+'ncks'
< x=list(pt.variables['xcoord'][:nopts])
< y=list(pt.variables['ycoord'][:nopts])
---
>
> x=list(pt.variables['xcoord'][:nopts])+list(df.x_m)
> y=list(pt.variables['ycoord'][:nopts])+list(df.y_m)
58c81
< os.system(ncks+' -O -d ROW,1,'+str(nopts)+' '+fname0+' '+fname)
---
> os.system(path[hname]+'ncks -O -d ROW,1,'+str(nopts+len(df))+' '+fname0+' '+fname)
60,61c83,84
< nc.NROWS=nopts
< nc.GDNAM='TWN_3X3'
---
> nc.NROWS=nopts+len(df)
> nc.GDNAM='EAsia_81K'

填入REAS煙囪參數

73a97
> va={'STKDM':17.0  ,'STKHT':250   ,'STKTK':373.  ,'STKVE':19.0}
75,76d98
< for v in mp:
<   nc.variables[v][0,0,:,0]=pt.variables[mp[v]][:]
78,80c100,122
< nc.variables['STKVE'][0,0,:,0]=pt.variables[mp[v]][:]/3600.
< nc.variables['IFIP'][0,0,:,0]=[1000+i for i in range(nopts)]
< nc.variables['ISTACK'][0,0,:,0]=[1+i for i in range(nopts)]
---
> v='STKVE'
> STKVE=list(pt.variables[mp[v]][:]/3600.)
>
> for i in va:
>   val=va[i]
>   va.update({i:[val for i in range(len(df))]})
> va.update({'XLOCA':list(df.x_m),'YLOCA':list(df.y_m)})
> nc.variables['LMAJOR'][0,0,:,0]=[0 for i in range(nopts+len(df))]
> nc.variables['LPING'][0,0,:,0]=[0 for i in range(nopts+len(df))]
> for i in range(nopts+len(df)):
>   HSTK=250.
>   if i<nopts:
>     HSTK=pt.variables['stkheight'][i]
>   if HSTK>150.:
>     nc.variables['LPING'][0,0,i,0]=1
>     nc.variables['LMAJOR'][0,0,i,0]=1
> for v in mp:
>   if v=='STKVE' :continue
>   nc.variables[v][0,0,:,0]=np.array(list(pt.variables[mp[v]][:])+va[v])
> v='STKVE'
> nc.variables[v][0,0,:,0]=np.array(STKVE+va[v])
> nc.variables['IFIP'][0,0,:,0]=[1000+i for i in range(nopts+len(df))]
> nc.variables['ISTACK'][0,0,:,0]=[1+i for i in range(nopts+len(df))]

程式下載

Reference