Something went wrong on our end
Forked from
CTDAS / CTDAS
528 commits behind the upstream repository.
-
Peters, Wouter authoredPeters, Wouter authored
expand_fluxes.py 20.39 KiB
#!/usr/bin/env python
# expand_fluxes.py
import sys
sys.path.append('../../')
import os
import getopt
from pylab import array, arange, transpose, date2num
from datetime import datetime
from da.tools.general import CreateDirs
from da.tools.io4 import CT_Read, CT_CDF, std_savedict, GetVariable
"""
Author: Wouter Peters (Wouter.Peters@noaa.gov)
Revision History:
File created on 21 Ocotber 2008.
"""
def proceed_dialog(txt, yes=['y','yes'], all=['a','all', 'yes-to-all']):
""" function to ask whether to proceed or not """
response=raw_input(txt)
if response.lower() in yes:
return 1
if response.lower() in all:
return 2
return 0
def SaveWeeklyAvg1x1Data(DaCycle):
""" Function SaveFlux1x1Data saves 3-hourly surface flux data to NetCDF files
*** Inputs ***
rundat : a RunInfo object
*** Outputs ***
daily NetCDF file containing 1-hourly global surface fluxes at 1x1 degree
*** Example ***
./expand_savestate project=enkf_release sd=20000101 ed=20010101 """
import da.tools.io4 as io
import logging
#
dirname = 'data_flux1x1_weekly'
#
dirname = CreateDirs(os.path.join(DaCycle['dir.analysis'],dirname))
#
# Some help variables
#
dectime0 = date2num(datetime(2000,1,1))
dt = DaCycle['cyclelength']
startdate = DaCycle['time.start']
enddate = DaCycle['time.end']
msg = "DA Cycle start date is %s" % startdate.strftime('%Y-%m-%d %H:%M') ; logging.info(msg)
msg = "DA Cycle end date is %s" % enddate.strftime('%Y-%m-%d %H:%M') ; logging.info(msg)
#
# Create or open NetCDF output file
#
saveas = os.path.join(dirname,'flux_1x1.nc')
ncf = io.CT_CDF(saveas,'write')
#
# Create dimensions and lat/lon grid
#
dimgrid = ncf.AddLatLonDim()
dimdate = ncf.AddDateDim()
#
# set title and tell GMT that we are using "pixel registration"
#
setattr(ncf,'Title','CarbonTracker fluxes')
setattr(ncf,'node_offset',1)
#
# skip dataset if already in file
#
ncfdate = date2num(startdate)-dectime0+dt.days/2.0
skip = ncf.has_date(ncfdate)
if skip:
msg = 'Skipping writing of data for date %s : already present in file %s' % (startdate.strftime('%Y-%m-%d'),saveas) ; logging.warning(msg)
else:
#
# if not, process this cycle. Start by getting input data from CTDAS
#
filename = os.path.join(DaCycle['dir.output'],'flux1x1_%s_%s.nc'%(startdate.strftime('%Y%m%d%H'),enddate.strftime('%Y%m%d%H'),) )
file = io.CT_Read(filename,'read')
bio = array(file.GetVariable(DaCycle.DaSystem['background.co2.bio.flux']))
ocean = array(file.GetVariable(DaCycle.DaSystem['background.co2.ocean.flux']))
fire = array(file.GetVariable(DaCycle.DaSystem['background.co2.fires.flux']))
fossil = array(file.GetVariable(DaCycle.DaSystem['background.co2.fossil.flux']))
mapped_parameters = array(file.GetVariable(DaCycle.DaSystem['final.param.mean.1x1']))
file.close()
next=ncf.inq_unlimlen()[0]
# Start adding datasets from here on, both prior and posterior datasets for bio and ocn
for prior in [False, True]:
#
# if prior, do not multiply fluxes with parameters, otherwise do
#
if prior:
qual_short='prior'
biomapped=bio
oceanmapped=ocean
else:
qual_short='opt'
biomapped=bio*mapped_parameters
oceanmapped=ocean*mapped_parameters
#
# For each dataset, get the standard definitions from the module mysettings, add values, dimensions, and unlimited count, then write
#
savedict=ncf.StandardVar(varname='bio_flux_'+qual_short)
savedict['values']=biomapped.tolist()
savedict['dims']=dimdate+dimgrid
savedict['count']=next
savedict['nsets']=1
ncf.AddData(savedict)
#
savedict=ncf.StandardVar(varname='ocn_flux_'+qual_short)
savedict['name']='ocn_flux_'+qual_short
savedict['values']=oceanmapped.tolist()
savedict['dims']=dimdate+dimgrid
savedict['count']=next
ncf.AddData(savedict)
#
savedict=ncf.StandardVar(varname='fire_flux_imp')
savedict['values']=fire.tolist()
savedict['dims']=dimdate+dimgrid
savedict['count']=next
ncf.AddData(savedict)
#
savedict=ncf.StandardVar(varname='fossil_flux_imp')
savedict['values']=fossil.tolist()
savedict['dims']=dimdate+dimgrid
savedict['count']=next
ncf.AddData(savedict)
#
savedict=ncf.StandardVar(varname='date')
savedict['values']=date2num(startdate)-dectime0+dt.days/2.0
savedict['dims']=dimdate
savedict['count']=next
ncf.AddData(savedict)
sys.stdout.write('.')
sys.stdout.flush()
#
# Done, close the new NetCDF file
#
ncf.close()
#
# Return the full name of the NetCDF file so it can be processed by the next routine
#
msg="Gridded weekly average fluxes now written" ; logging.info(msg)
return saveas
def SaveWeeklyAvgTCData(DaCycle):
""" Function SaveEcoData saves weekly surface flux data to NetCDF files
*** Inputs ***
DaCycle : a DaCycle object
"""
from da.analysis.tools_regions import globarea, StateToGrid
from da.analysis.tools_transcom import StateToTranscom, StateCovToTranscom, transcommask
import da.tools.io4 as io
from numpy import dot
import logging
#
dirname = 'data_tc_weekly'
#
dirname = CreateDirs(os.path.join(DaCycle['dir.analysis'],dirname))
#
# Some help variables
#
dectime0 = date2num(datetime(2000,1,1))
dt = DaCycle['cyclelength']
startdate = DaCycle['time.start']
enddate = DaCycle['time.end']
ncfdate = date2num(startdate)-dectime0+dt.days/2.0
msg = "DA Cycle start date is %s" % startdate.strftime('%Y-%m-%d %H:%M') ; logging.info(msg)
msg = "DA Cycle end date is %s" % enddate.strftime('%Y-%m-%d %H:%M') ; logging.info(msg)
# Write/Create NetCDF output file
#
saveas = os.path.join(dirname,'tcfluxes.nc')
ncf = io.CT_CDF(saveas,'write')
dimdate = ncf.AddDateDim()
dimidateformat = ncf.AddDateDimFormat()
dimregs = ncf.AddRegionDim(type='tc')
#
# set title and tell GMT that we are using "pixel registration"
#
setattr(ncf,'Title','CarbonTracker TransCom fluxes')
setattr(ncf,'node_offset',1)
#
skip = ncf.has_date(ncfdate)
if skip:
msg = 'Skipping writing of data for date %s : already present in file %s' % (startdate.strftime('%Y-%m-%d'),saveas) ; logging.warning(msg)
else:
# Get input data
area=globarea()
infile=os.path.join(DaCycle['dir.analysis'],'data_flux1x1_weekly','flux_1x1.nc')
if not os.path.exists(infile):
msg="Needed input file (%s) does not exist yet, please create weekly eco flux files first, returning..."%infile ; logging.error(msg)
return None
ncf_in = io.CT_Read(infile,'read')
# Transform data one by one
# Get the date variable, and find index corresponding to the DaCycle date
try:
dates = ncf_in.variables['date'][:]
except KeyError:
msg = "The variable date cannot be found in the requested input file (%s) " % infile ; logging.error(msg)
msg = "Please make sure you create gridded fluxes before making TC fluxes " ; logging.error(msg)
raise KeyError
try:
index = dates.tolist().index(ncfdate)
except ValueError:
msg = "The requested cycle date is not yet available as gridded flux in file %s "% infile ; logging.error(msg)
msg = "Please make sure you create gridded fluxes before making TC fluxes " ; logging.error(msg)
raise ValueError
# First add the date for this cycle to the file, this grows the unlimited dimension
savedict = ncf.StandardVar(varname='date')
savedict['values'] = ncfdate
savedict['dims'] = dimdate
savedict['count'] = index
dummy = ncf.AddData(savedict)
# Now convert other variables that were inside the flux_1x1 file
vardict = ncf_in.variables
for vname, vprop in vardict.iteritems():
data = ncf_in.GetVariable(vname)[index]
if vname=='latitude': continue
elif vname=='longitude': continue
if vname not in ['date','idate']:
if 'cov' in vname:
alldata=[]
dd=StateCovToGrid(data*area,transcommask,reverse=True)
data=array(dd)
dims=dimdate+dimregs+dimregs
else:
dd=StateToGrid(data*area,transcommask,reverse=True)
data=array(dd)
dims=dimdate+dimregs
savedict = ncf.StandardVar(varname=vname)
savedict['values'] = data.tolist()
savedict['dims'] = dims
savedict['units'] = 'mol/region/s'
savedict['count'] = index
ncf.AddData(savedict)
ncf_in.close()
ncf.close()
msg="TransCom weekly average fluxes now written" ; logging.info(msg)
return saveas
def SaveTCDataExt(rundat):
""" Function SaveTCDataExt saves surface flux data to NetCDF files for extended TransCom regions
*** Inputs ***
rundat : a RunInfo object
*** Outputs ***
NetCDF file containing n-hourly global surface fluxes per TransCom region
*** Example ***
./expand_savestate project=enkf_release sd=20000101 ed=20010101 """
from da.analysis.tools_transcom import StateCovToGrid, transcommask, ExtendedTCRegions
import da.tools.io4 as io
infile=os.path.join(rundat.outputdir,'data_tc_weekly','tcfluxes.nc')
if not os.path.exists(infile):
print "Needed input file (%s) does not exist yet, please create weekly tc flux files first, returning..."%infile
return None
# Create NetCDF output file
#
saveas = os.path.join(rundat.outputdir,'data_tc_weekly','tc_extfluxes.nc')
ncf = io.CT_CDF(saveas,'create')
dimdate = ncf.AddDateDim()
dimidateformat = ncf.AddDateDimFormat()
dimregs = ncf.AddRegionDim(type='tc_ext')
ncf_in = io.CT_Read(infile,'read')
vardict = ncf_in.variables
for vname, vprop in vardict.iteritems():
data = ncf_in.GetVariable(vname)[:]
if vname=='latitude': continue
elif vname=='longitude': continue
elif vname=='date': dims=dimdate
elif vname=='idate': dims=dimdate+dimidateformat
if vname not in ['date','idate']:
if 'cov' in vname:
alldata=[]
for dd in data:
dd=StateCovToGrid(dd*area,transcommask,reverse=True)
alldata.append(dd)
data=array(alldata)
dims=dimdate+dimregs+dimregs
else:
data=ExtendedTCRegions(data)
dims=dimdate+dimregs
print vname,data.shape
savedict = ncf.StandardVar(varname=vname)
savedict['values'] = data.tolist()
savedict['dims'] = dims
savedict['units'] = 'mol/region/s'
savedict['count'] = 0
ncf.AddData(savedict,nsets=data.shape[0])
ncf.close()
return saveas
def SaveEcoDataExt(rundat):
""" Function SaveEcoDataExt saves surface flux data to NetCDF files for extended ecoregions
*** Inputs ***
rundat : a RunInfo object
*** Outputs ***
NetCDF file containing n-hourly global surface fluxes per TransCom region
*** Example ***
./expand_savestate project=enkf_release sd=20000101 ed=20010101 """
from ecotools import xte
from da.analysis.tools_transcom import LookUpName
import pycdf as CDF
infile=os.path.join(rundat.outputdir,'data_eco_weekly','ecofluxes.nc')
if not os.path.exists(infile):
print "Needed input file (%s) does not exist yet, please create weekly ecoflux files first, returning..."%infile
return None
# Create NetCDF output file
#
saveas=os.path.join(rundat.outputdir,'data_eco_weekly','eco_extfluxes.nc')
ncf=CT_CDF(saveas,'create')
dimdate=ncf.AddDateDim()
dimidateformat=ncf.AddDateDimFormat()
dimregs = ncf.AddRegionDim(type='tc_ext')
ncf_in=CDF.CDF(infile)
vardict=ncf_in.variables()
for vname, vprop in vardict.iteritems():
dims=()
data=array(ncf_in.var(vname)[:])
atts=ncf_in.var(vname).attributes()
if vname not in ['date','idate']:
if 'cov' in vname:
data=xte(data[:,0:rundat.n_land,0:rundat.n_land],cov=True)
dims=dimdate+dimregs+dimregs
else:
data=xte(data[:,0:rundat.n_land])
dims=dimdate+dimregs
elif vname=='date': dims=dimdate
elif vname=='idate': dims=dimdate+dimidateformat
else:
print 'Dataset with unknown dimensions encountered in file: %s'%vname
savedict=ncf.StandardVar(varname=vname)
savedict['units']=atts['units']
savedict['values']=data.tolist()
savedict['dims']=dims
ncf.AddData(savedict,nsets=data.shape[0])
ncf.close()
return saveas
def SaveTimeAvgData(rundat,infile,avg='monthly'):
""" Function saves time mean surface flux data to NetCDF files
*** Inputs ***
rundat : a RunInfo object
*** Outputs ***
daily NetCDF file containing 1-hourly global surface fluxes at 1x1 degree
*** Example ***
./expand_savestate project=enkf_release sd=20000101 ed=20010101 """
import da.analysis.tools_time as timetools
import da.tools.io4 as io
dirname,filename = os.path.split(infile)
dirname = CreateDirs(os.path.join(rundat.outputdir,dirname.replace('weekly',avg) ) )
dectime0 = date2num(datetime(2000,1,1))
# Create NetCDF output file
#
saveas = os.path.join(dirname,filename)
ncf = io.CT_CDF(saveas,'create')
dimdate = ncf.AddDateDim()
#
# Open input file specified from the command line
#
if not os.path.exists(infile):
print "Needed input file (%s) not found. Please create this first:"%infile
print "returning..."
return None
else:
pass
file = io.CT_Read(infile,'read')
datasets = file.variables.keys()
date = file.GetVariable('date')
globatts = file.ncattrs()
time = [datetime(2000,1,1)+timedelta(days=d) for d in date]
#
# Add global attributes, sorted
#
keys = globatts
keys.sort()
for k in keys:
setattr(ncf,k,k)
# loop over datasets in infile, skip idate and date as we will make new time axis for the averaged data
for sds in datasets:
if sds in ['idate','date'] : continue
print '['
# get original data
data = array(file.GetVariable(sds))
varatts = file.variables[sds].ncattrs()
vardims = file.variables[sds].dimensions
#
# Depending on dims of input dataset, create dims for output dataset. Note that we add the new dimdate now.
#
dims=()
for d in vardims:
if 'latitude' in d:
dimgrid = ncf.AddLatLonDim()
dims += (dimgrid[0],)
if 'longitude' in d:
dimgrid = ncf.AddLatLonDim()
dims += (dimgrid[1],)
for type in ['eco','eco_ext','tc','tc_ext','olson']:
if 'regions_%s' % type == d:
dimregs = ncf.AddRegionDim(type)
dims += dimregs
#
# If the variable name from the infile is not defined in the standard, simply copy attributes from the old to the new sds
# Do not copy over the grid information
#
if ncf.StandardVar(sds)['name'] == 'unknown':
savedict = ncf.StandardVar(sds)
savedict['name'] = sds
savedict['values'] = data.tolist()
savedict['dims'] = dims
savedict['units'] = file.variables[sds].units
savedict['long_name'] = file.variables[sds].long_name
savedict['comment'] = file.variables[sds].comment
savedict['standard_name'] = file.variables[sds].standard_name
savedict['count'] =0
ncf.AddData(savedict)
sys.stdout.write('.')
sys.stdout.flush()
else:
if sds in ['latitude','longitude']: continue
if avg == 'monthly':
time_avg, data_avg = timetools.monthly_avg(time,data)
elif avg == 'seasonal':
time_avg, data_avg = timetools.season_avg(time,data)
elif avg == 'yearly':
time_avg, data_avg = timetools.yearly_avg(time,data)
elif avg == 'longterm':
time_avg, data_avg = timetools.longterm_avg(time,data)
time_avg = [time_avg]
data_avg = [data_avg]
else:
raise ValueError,'Averaging (%s) does not exist' % avg
count=-1
for dd,data in zip(time_avg,data_avg):
count=count+1
if not ncf.has_date(date2num(dd)-dectime0):
savedict=ncf.StandardVar('date')
savedict['values']=date2num(dd)-dectime0
savedict['dims']=dimdate
savedict['count']=count
ncf.AddData(savedict)
savedict=ncf.StandardVar(sds)
savedict['values']=data.tolist()
savedict['units']=file.variables[sds].units
if 'cov' in sds:
savedict['dims']=dimdate+dims+dims
else:
savedict['dims']=dimdate+dims
savedict['count']=count
ncf.AddData(savedict)
sys.stdout.write('.')
sys.stdout.flush()
print ']'
# end NetCDF file access
file.close()
ncf.close()
if __name__ == "__main__":
import logging
from da.tools.initexit import CycleControl
from da.ct.dasystem import CtDaSystem
sys.path.append('../../')
logging.root.setLevel(logging.INFO)
DaCycle = CycleControl(args={'rc':'../../da.rc'})
DaCycle.Initialize()
DaCycle.ParseTimes()
DaSystem = CtDaSystem('../rc/carbontracker.rc')
DaSystem.Initialize()
DaCycle.DaSystem = DaSystem
no, yes, all = range(3)
proceed = no
# first, parse results from the inverse part of the run
if proceed != all:
proceed = proceed_dialog('Create average 1x1 flux data files? [y|yes, n|no, a|all|yes-to-all ]')
if proceed != no:
while DaCycle['time.start'] < DaCycle['time.finish']:
savedas=SaveWeeklyAvg1x1Data(DaCycle)
savedas=SaveWeeklyAvgTCData(DaCycle)
DaCycle.AdvanceCycleTimes()
sys.exit(2)
a=SaveTimeAvgData(rundat,savedas,avg='monthly')
a=SaveTimeAvgData(rundat,savedas,avg='yearly')
a=SaveTimeAvgData(rundat,savedas,avg='longterm')
if proceed != all:
proceed = proceed_dialog('Create average tc flux data files? [y|yes, n|no, a|all|yes-to-all] ')
if proceed != no:
a=SaveTimeAvgData(rundat,savedas,avg='monthly')
a=SaveTimeAvgData(rundat,savedas,avg='seasonal')
a=SaveTimeAvgData(rundat,savedas,avg='yearly')
a=SaveTimeAvgData(rundat,savedas,avg='longterm')
if proceed != all:
proceed = proceed_dialog('Create average extended tc flux data files? [y|yes, n|no, a|all|yes-to-all] ')
if proceed != no:
savedas=SaveTCDataExt(rundat)
a=SaveTimeAvgData(rundat,savedas,avg='monthly')
a=SaveTimeAvgData(rundat,savedas,avg='seasonal')
a=SaveTimeAvgData(rundat,savedas,avg='yearly')
a=SaveTimeAvgData(rundat,savedas,avg='longterm')
sys.exit(0)