In [1]:
%run basics
import pytz
import re
%matplotlib


Using matplotlib backend: Qt4Agg

In [2]:
def get_clearsky_Fsd(ddd,hhh,k,info):
    longitude = info["longitude"]
    latitude = info["latitude"]
    altitude = info["altitude"]
    GMT_zone = info["GMT_zone"]
    eot = 0.17*numpy.sin(4*numpy.pi*(ddd-80)/373)-0.129*numpy.sin(2*numpy.pi*(ddd-8)/355)
    solar_noon = 12+(GMT_zone*15.0-longitude)/360*24-eot
    declination = numpy.radians(23.4)*numpy.sin((ddd+284)/365.0*2*numpy.pi)
    Fsd_TOA = (1+0.034*numpy.cos(ddd/365.25*2*numpy.pi))*1367.0
    hour_angle = abs(numpy.radians((solar_noon-hhh)*15))
    zenith = numpy.arccos(numpy.sin(numpy.radians(latitude))*numpy.sin(declination)+
                          numpy.cos(numpy.radians(latitude))*numpy.cos(declination)*
                          numpy.cos(hour_angle))
    zenith = numpy.ma.masked_greater_equal(zenith,numpy.pi/2)
    air_mass_ratio = (numpy.exp(-1*altitude/8343.5)/
                      (numpy.cos(zenith)+0.15*(numpy.degrees(90-zenith)+3.855)**-1.253))
    Fsd_cs = Fsd_TOA*numpy.exp(-k*air_mass_ratio)*numpy.cos(zenith)
    return Fsd_cs

In [3]:
def residuals(params,Fsd_obs,ddd,hhh,info,weighted,weight_type):
    k = params[0]
    nDays = info["nDays"]
    ntsInDay = info["ntsInDay"]
    Fsd_obs_max = numpy.ma.max(Fsd_obs.reshape(nDays,ntsInDay),axis=0)
    Fsd_cs = get_clearsky_Fsd(ddd,hhh,k,info)
    Fsd_cs_max = numpy.ma.max(Fsd_cs.reshape(nDays,ntsInDay),axis=0)
    resid = Fsd_obs_max - Fsd_cs_max
    if weighted:
        weights = CalculateWeights(resid,weight_type=weight_type)
        return resid*weights
    else:
        return resid

In [4]:
def irls_leastsq(func,p0,args=(),maxfev=3,weight_type='Huber',mode='verbose'):
    weighted = False
    popt,pcov = scipy.optimize.leastsq(func,p0,args=args+(weighted,weight_type))
    if mode!="quiet":
        print 'After non-weighted call to leastsq: ',popt
    n=1
    weighted = True
    while n<=maxfev:
        popt,pcov = scipy.optimize.leastsq(func,popt,args=args+(weighted,weight_type))
        if mode!="quiet":
            print 'Weighted call '+str(n)+' to leastsq: ',popt
        n = n + 1
    return popt,pcov

def CalculateWeights(resid,weight_type='Huber'):
    if weight_type.lower()=='tukey':
        weights = TukeyBiweight(MAD_scale(resid))
    elif weight_type.lower()=='huber':
        weights = HuberTWeight(MAD_scale(resid))
    elif weight_type.lower()=='ols':
        weights = OLSWeight(MAD_scale(resid))
    else:
        print "CalculateWeights: Unknown weight type, used Huber's t weight"
        weights = HuberTWeight(MAD_scale(resid))
    return weights

def TukeyBiweight(x):
    return ((numpy.abs(x)<1.0)*(1.0 - x**2)**2)

def HuberTWeight(x):
    weights = numpy.ones(len(x))
    idx = numpy.where(numpy.abs(x)>1.345)[0]
    weights[idx] = 1.345/numpy.abs(x[idx])
    return weights

def OLSWeight(x):
    weights = numpy.ones(len(x))
    return weights

def MAD_scale(resid):
    scale = numpy.median(numpy.abs(resid - numpy.median(resid))) / 0.6745
    return resid/scale

In [19]:
# read the netCDF file
ncname = qcio.get_filename_dialog()
ds = qcio.nc_read_series(ncname)
dt = ds.series["DateTime"]["Data"]

In [20]:
# create the info dictionary to hold useful stuff
info = {}
ts = int(ds.globalattributes["time_step"])
info["ntsInDay"] = int(24.0*60.0/float(ts))
info["longitude"] = float(ds.globalattributes["longitude"])
info["latitude"] = float(ds.globalattributes["latitude"])
if "elevation" in ds.globalattributes:
    info["altitude"] = int(re.sub("[^0123456789\.]","",str(ds.globalattributes["elevation"])))
else:
    info["altitude"] = 1.0
time_zone = ds.globalattributes["time_zone"]
tz = pytz.timezone(time_zone)
cdt = datetime.datetime(2013,6,1,0,0,0)
utcoffset = tz.utcoffset(cdt)
info["GMT_zone"] = utcoffset.seconds/float(3600)

In [21]:
# do each year and month separately
start_date = dt[0]
end_date = start_date+dateutil.relativedelta.relativedelta(months=1)
last_date = dt[-1]
while start_date<last_date:
    si = qcutils.GetDateIndex(dt,str(start_date),ts=ts,match="startnextday",default=0)
    ei = qcutils.GetDateIndex(dt,str(end_date),ts=ts,match="endpreviousday",default=len(dt)-1)
    mi = int((si+ei)/2)
    info["nDays"] = int((ei-si+1)/info["ntsInDay"])
    ddd,f,a = qcutils.GetSeries(ds,"Ddd",si=si,ei=ei)
    hhh,f,a = qcutils.GetSeries(ds,"Hdh",si=si,ei=ei)
    Fsd,f,a = qcutils.GetSeries(ds,"Fsd",si=si,ei=ei)
    # correct decimal hour to refer to centre of period rather than end of period
    hhh = hhh - float(ts)/(60.0*2)
    popt,pcov = irls_leastsq(residuals,[0.27],args=(Fsd,ddd,hhh,info),maxfev=3,weight_type='huber',mode="quiet")
    print dt[si],dt[mi],dt[ei],popt[0]
    start_date = end_date
    end_date = start_date+dateutil.relativedelta.relativedelta(months=1)


2011-12-02 00:30:00 2011-12-17 00:00:00 2012-01-01 00:00:00 0.171097494998
2012-01-02 00:30:00 2012-01-17 00:00:00 2012-02-01 00:00:00 0.159090026949
2012-02-02 00:30:00 2012-02-16 00:00:00 2012-03-01 00:00:00 0.169450041296
2012-03-02 00:30:00 2012-03-17 00:00:00 2012-04-01 00:00:00 0.179720817963
2012-04-02 00:30:00 2012-04-16 12:00:00 2012-05-01 00:00:00 0.18033042664
2012-05-02 00:30:00 2012-05-17 00:00:00 2012-06-01 00:00:00 0.131008029484
2012-06-02 00:30:00 2012-06-16 12:00:00 2012-07-01 00:00:00 0.106438051526
2012-07-02 00:30:00 2012-07-17 00:00:00 2012-08-01 00:00:00 0.143160414167
2012-08-02 00:30:00 2012-08-17 00:00:00 2012-09-01 00:00:00 0.194387476767
2012-09-02 00:30:00 2012-09-16 12:00:00 2012-10-01 00:00:00 0.186718932064
2012-10-02 00:30:00 2012-10-17 00:00:00 2012-11-01 00:00:00 0.195935651163
2012-11-02 00:30:00 2012-11-16 12:00:00 2012-12-01 00:00:00 0.196132515937
2012-12-02 00:30:00 2012-12-17 00:00:00 2013-01-01 00:00:00 0.17028889026
2013-01-02 00:30:00 2013-01-17 00:00:00 2013-02-01 00:00:00 0.171752113462
2013-02-02 00:30:00 2013-02-15 12:00:00 2013-03-01 00:00:00 0.190850385746
2013-03-02 00:30:00 2013-03-17 00:00:00 2013-04-01 00:00:00 0.194417835938
2013-04-02 00:30:00 2013-04-16 12:00:00 2013-05-01 00:00:00 0.169720038122
2013-05-02 00:30:00 2013-05-17 00:00:00 2013-06-01 00:00:00 0.13543852573
2013-06-02 00:30:00 2013-06-16 12:00:00 2013-07-01 00:00:00 0.120377278855
2013-07-02 00:30:00 2013-07-17 00:00:00 2013-08-01 00:00:00 0.142257852545
2013-08-02 00:30:00 2013-08-17 00:00:00 2013-09-01 00:00:00 0.170064739603
2013-09-02 00:30:00 2013-09-16 12:00:00 2013-10-01 00:00:00 0.198225458732
2013-10-02 00:30:00 2013-10-17 00:00:00 2013-11-01 00:00:00 0.177900742699
2013-11-02 00:30:00 2013-11-16 12:00:00 2013-12-01 00:00:00 0.172072482029
2013-12-02 00:30:00 2013-12-17 00:00:00 2014-01-01 00:00:00 0.165436125861
2014-01-02 00:30:00 2014-01-17 00:00:00 2014-02-01 00:00:00 0.218111430381
2014-02-02 00:30:00 2014-02-15 12:00:00 2014-03-01 00:00:00 0.177930944456
2014-03-02 00:30:00 2014-03-17 00:00:00 2014-04-01 00:00:00 0.154725649696
2014-04-02 00:30:00 2014-04-16 12:00:00 2014-05-01 00:00:00 0.176487991216
2014-05-02 00:30:00 2014-05-17 00:00:00 2014-06-01 00:00:00 0.152442738512
2014-06-02 00:30:00 2014-06-16 12:00:00 2014-07-01 00:00:00 0.123414390319
2014-07-02 00:30:00 2014-07-17 00:00:00 2014-08-01 00:00:00 0.135694266875
2014-08-02 00:30:00 2014-08-17 00:00:00 2014-09-01 00:00:00 0.154764248029
2014-09-02 00:30:00 2014-09-16 12:00:00 2014-10-01 00:00:00 0.213097033399
2014-10-02 00:30:00 2014-10-17 00:00:00 2014-11-01 00:00:00 0.177730930402
2014-11-02 00:30:00 2014-11-16 12:00:00 2014-12-01 00:00:00 0.20347748754
2014-12-02 00:30:00 2014-12-17 00:00:00 2015-01-01 00:00:00 0.16186171329
2015-01-02 00:30:00 2015-01-17 00:00:00 2015-02-01 00:00:00 0.200833388298
2015-02-02 00:30:00 2015-02-15 12:00:00 2015-03-01 00:00:00 0.179871759979
2015-03-02 00:30:00 2015-03-17 00:00:00 2015-04-01 00:00:00 0.158640750227
2015-04-02 00:30:00 2015-04-16 12:00:00 2015-05-01 00:00:00 0.151088766201
2015-05-02 00:30:00 2015-05-17 00:00:00 2015-06-01 00:00:00 0.153895356243
2015-06-02 00:30:00 2015-06-16 12:00:00 2015-07-01 00:00:00 0.12053151592
2015-07-02 00:30:00 2015-07-05 00:00:00 2015-07-08 00:00:00 0.122633698109

In [22]:
month,f,a = qcutils.GetSeries(ds,"Month")
ddd_all,f,a = qcutils.GetSeries(ds,"Ddd")
hhh_all,f,a = qcutils.GetSeries(ds,"Hdh")
Fsd_all,f,a = qcutils.GetSeries(ds,"Fsd")
for m in range(1,13):
    idx = numpy.where(month==m)[0]
    ddd = ddd_all[idx]
    hhh = hhh_all[idx]
    Fsd = Fsd_all[idx]
    info["nDays"] = int(len(idx)/info["ntsInDay"])
    # correct decimal hour to refer to centre of period rather than end of period
    hhh = hhh - float(ts)/(60.0*2)
    popt,pcov = irls_leastsq(residuals,[0.27],args=(Fsd,ddd,hhh,info),maxfev=3,weight_type='huber',mode="quiet")
    print m,popt[0]


1 0.127691800436
2 0.153471734324
3 0.139227758809
4 0.140089763987
5 0.119699030812
6 0.0930729344311
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-22-c93ff974d179> in <module>()
     11     # correct decimal hour to refer to centre of period rather than end of period
     12     hhh = hhh - float(ts)/(60.0*2)
---> 13     popt,pcov = irls_leastsq(residuals,[0.27],args=(Fsd,ddd,hhh,info),maxfev=3,weight_type='huber',mode="quiet")
     14     print m,popt[0]

<ipython-input-4-0f29344ef8af> in irls_leastsq(func, p0, args, maxfev, weight_type, mode)
      1 def irls_leastsq(func,p0,args=(),maxfev=3,weight_type='Huber',mode='verbose'):
      2     weighted = False
----> 3     popt,pcov = scipy.optimize.leastsq(func,p0,args=args+(weighted,weight_type))
      4     if mode!="quiet":
      5         print 'After non-weighted call to leastsq: ',popt

/home/peter/anaconda/lib/python2.7/site-packages/scipy/optimize/minpack.pyc in leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag)
    369     if not isinstance(args, tuple):
    370         args = (args,)
--> 371     shape, dtype = _check_func('leastsq', 'func', func, x0, args, n)
    372     m = shape[0]
    373     if n > m:

/home/peter/anaconda/lib/python2.7/site-packages/scipy/optimize/minpack.pyc in _check_func(checker, argname, thefunc, x0, args, numinputs, output_shape)
     18 def _check_func(checker, argname, thefunc, x0, args, numinputs,
     19                 output_shape=None):
---> 20     res = atleast_1d(thefunc(*((x0[:numinputs],) + args)))
     21     if (output_shape is not None) and (shape(res) != output_shape):
     22         if (output_shape[0] != 1):

<ipython-input-3-2519171d024b> in residuals(params, Fsd_obs, ddd, hhh, info, weighted, weight_type)
      3     nDays = info["nDays"]
      4     ntsInDay = info["ntsInDay"]
----> 5     Fsd_obs_max = numpy.ma.max(Fsd_obs.reshape(nDays,ntsInDay),axis=0)
      6     Fsd_cs = get_clearsky_Fsd(ddd,hhh,k,info)
      7     Fsd_cs_max = numpy.ma.max(Fsd_cs.reshape(nDays,ntsInDay),axis=0)

ValueError: total size of new array must be unchanged

In [ ]: