Changeset 2463 in lmdz_wrf for trunk/tools


Ignore:
Timestamp:
Apr 23, 2019, 8:56:35 PM (7 years ago)
Author:
lfita
Message:

Adding:

  • `fix_CFdates': Fixing CF-time values with wrong setting
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tools/generic_tools.py

    r2462 r2463  
    118118# files_folder_HMT: Function to retrieve a list of files from a folder [fold] and files with [head]*[middle]*[tail]
    119119# fill_Narray: Function to fill a n-dimensional array with an arrary of lesser rank
     120# fix_CFdates: Fixing CF-time values with wrong setting
     121# gen_impose_gregorian: Function to impose gregorian calendar to a series of times with a
     122#   non-standard calendar independently from datetime (imposes yr > 1900)
    120123# gen_leapdays: Function to provide how many leap days are between two years avoiding datetime
    121124# generate_CFtimes: Function to generate CFtimes for a given period, frequency and units
     
    519522    return combos
    520523
     524def sign(number):
     525    """ Function to provide the sign of a number
     526      num: number to provide the sign
     527    >>> sign(7109)
     528    1
     529    >>> sign(-3.43512)
     530    -1.0
     531    """
     532    fname = 'sign'
     533
     534    sign = np.abs(number)/number
     535
     536    return sign
     537
     538##
     539####
     540######
     541####### Temporal functions #######
     542#####
     543###
     544#
    521545def days_month(year,month):
    522546    """ Function to give the number of days of a month of a given year
     
    592616
    593617    return Nleapdays
     618
     619def juliandate(yr,mo,dd,hr,mi,ss):
     620    """ Function to provide the julian date (in days since -4712 January 1st 00 UTC)
     621          for any greogiran date
     622      refdate: 1 January 4713 BC (= -4712 January 1), Greenwich mean noon (= 12h UT).
     623    FROM: https://aa.usno.navy.mil/faq/docs/JD_Formula.php
     624      after 1990 edition of the U.S. Naval Observatory's Almanac for Computers
     625    >>> juliandate(1877,8,11,7,30,0)
     626    2406843.3125
     627    >>> juliandate(877,8,11,7,30,0)
     628    2041601.3125
     629    >>> juliandate(1970,1,1,0,0,0)
     630    2440588.0
     631    >>> juliandate(1978,1,1,0,0,0)
     632    2443510.0
     633    >>> juliandate(1978,7,21,15,0,0)
     634    2443712.625
     635    >>> juliandate(2000,1,1,0,0,0)
     636    2451545.0
     637    """
     638    fname = 'juliandate'
     639
     640    sec1 = dd - 32075.
     641    sec2 = 1461.*(yr+4800.+(mo-14)/12.)/4.
     642    sec3 = 367.*(mo-2-(mo-14)/12.*12)/12.
     643    sec4 = 3.*((yr+4900.+(mo-14.)/12.)/100.)/4.
     644 
     645    juliand = int(sec1 + sec2 + sec3 - sec4)
     646
     647    juliand = juliand*1. + (hr + mi/60. + ss/3600.)/24.
     648
     649    # Alternative (without full agreement, just kept in case)
     650    #K = yr + 0
     651    #M = mo + 0
     652    #I = dd + 0
     653    #UT = hr*1. + mi/60. + ss/3600.
     654
     655    #sec1 = 367.*K
     656    #sec2 = int((7.*(K+int((M+9)/12.)))/4.)
     657    #sec3 = int((275.*M)/9.)
     658    #sec4 = I*1.
     659    #sec5 = 1721013.5
     660    #sec6 = UT/24.
     661    #sec7 = 0.5*sign(100.*K+M*1.-190002.5)
     662    #sec8 = 0.5
     663
     664    #juliand = sec1 - sec2 + sec3 + sec4 + sec5 + sec6 - sec7 + sec8
     665    #print '  juliand:', juliand
     666
     667    return juliand
     668
     669def juliandate_gregorian(juliand):
     670    """ Function to convert from julian date (days since -4712 January 1st 00 UTC)
     671         to the equivalent greogiran date
     672      juliand: julian date to convert
     673    FROM: https://aa.usno.navy.mil/faq/docs/JD_Formula.php
     674      after 1990 edition of the U.S. Naval Observatory's Almanac for Computers
     675    >>> juliandate_gregorian(2406843.3125)
     676    [1877, 8.0, 11, 7, 30, 0.0]
     677    >>> juliandate_gregorian(2041601.3125)
     678    [877, 8.0, 11, 7, 30, 0.0]
     679    >>> juliandate_gregorian(2440588.0)
     680    [1970, 1.0, 1, 0, 0, 0.0]
     681    >>> juliandate_gregorian(2443510.0)
     682    [1978, 1.0, 1, 0, 0, 0.0]
     683    >>> juliandate_gregorian(2443712.625)
     684    [1978, 7.0, 22, 15, 0, 0.0]
     685    """
     686    fname = 'juliandate_gregorian'
     687
     688    L = int(juliand+68569)
     689    N = 4*L/146097
     690    L = L-(146097*N+3)/4
     691    I = 4000*(L+1)/1461001
     692    L = L-1461*I/4+31
     693    J = 80*L/2447
     694    K = L-2447*J/80
     695    L = J/11
     696    J = J+2.-12.*L
     697    I = 100*(N-49)+I+L
     698
     699    yr = I
     700    mo = J
     701    dd = K
     702
     703    # hr, mi, ss
     704    ut = juliand - int(juliand)
     705    utsecs = ut*24.*3600.
     706    hh = int(utsecs/3600.)
     707    mi = int((utsecs - hh*3600.)/60.)
     708    ss = utsecs - hh*3600. - mi*60.
     709
     710    return [yr, mo, dd, hh, mi, ss]
    594711
    595712def datetimeStr_datetime(StringDT):
     
    19572074      Tunits: CF units of time [Tunits] since [DateRef]
    19582075      cal: non standard calendar
    1959       >>> impose_gregorian(np.range(800,10000,100), 'days since 1949-12-01 00:00:00',
     2076      >>> impose_gregorian(np.arange(800,10000,100), 'days since 1949-12-01 00:00:00',
    19602077        'noleap')
    19612078      [ 800. 901.]
     
    20582175      Tunits: CF units of time [Tunits] since [DateRef]
    20592176      cal: non standard calendar
    2060       >>> gen_impose_gregorian(np.range(800,10000,100), 'days since 1850-01-01 00:00:00',
     2177      >>> gen_impose_gregorian(np.arange(800,1000,100), 'days since 1850-01-01 00:00:00',
    20612178        'noleap')
    2062       [ 800. 901.]
     2179      [ 801. 901.]
    20632180      >>> gen_impose_gregorian(-7277.460938, 'days since 1949-12-01 00:00:00', 'noleap')
    20642181      [-7272.460938]
     
    20802197        Srefdate = lTunits[2] + ' ' + lTunits[3]
    20812198    refdate = [int(Srefdate[0:4]), int(Srefdate[5:7]), int(Srefdate[8:10]),          \
    2082       int(Srefdate[11:13]), int(Srefdate[14,16]), int(Srefdate[17:19]) ]
     2199      int(Srefdate[11:13]), int(Srefdate[14:16]), int(Srefdate[17:19]) ]
    20832200
    20842201    if type(timev) == type(range(2)):
     
    21012218
    21022219    if Tu == 'weeks':
    2103         timevsecs = timev * 24. * 7 * 3600.
     2220        timevdays = timev * 7
    21042221    elif Tu == 'days':
    2105         timevsecs = timev * 24. * 3600.
     2222        timevdays = timev * 1.
    21062223    elif Tu == 'hours':
    2107         timevsecs = timev * 3600.
     2224        timevdays = timev / 24.
    21082225    elif Tu == 'minutes':
    2109         timevsecs = timev * 60.
     2226        timevdays = timev / (24.*60.)
    21102227    elif Tu == 'seconds':
    2111         timevsecs = timev * 1.
     2228        timevdays = timev / (24.*3600.)
    21122229    else:
    21132230        print errormsg
     
    21182235    newtimes = np.zeros((dimt), dtype=np.float64)
    21192236
    2120     refsecs = juliandate(refdate[0], refdate[1], refdate[2], refdate[3], refdate[4], refdate[5])
    2121     refsecs = refsecs*3600.
     2237    refdays = juliandate(refdate[0], refdate[1], refdate[2], refdate[3], refdate[4], refdate[5])
    21222238
    21232239    yrref = refdate[0]
    21242240    if cal == 'noleap' or cal == '365d':
    21252241        for it in range(dimt):
    2126             # Some issues in implementations/machines ...
    2127             # FROM: https://stackoverflow.com/questions/33566939/timedelta-error-with-numpy-longdouble-dtype
    2128             tv = int(timevsecs[it])
    2129             deltaT = dt.timedelta(seconds=tv)
    2130             datetime = refdate + deltaT
    2131             yr = datetime.year
     2242            tdays = refdays + timevdays[it]
     2243            gdatev = juliandate_gregorian(tdays)
     2244
     2245            yr = gdatev[0]
     2246            mon = gdatev[1]
    21322247            if yr > yrref:
    2133                 Nleapd = leapdays(yrref, yr)
     2248                Nleapd = gen_leapdays(yrref, yr)
    21342249            else:
    2135                 Nleapd = leapdays(yr, yrref)
    2136             if datetime.month <= 2 and days_month(yr, 2) > 28: Nleapd = Nleapd - 1
    2137             newtimes[it] = timevsecs[it] + Nleapd*24*3600.
     2250                Nleapd = gen_leapdays(yr, yrref)
     2251            if mon <= 2 and leapyr(yr): Nleapd = Nleapd - 1
     2252
     2253            newtimes[it] = timevdays[it] + Nleapd
    21382254    else:
    21392255        print errormsg
     
    21442260    # Re-transforming to the original units
    21452261    if Tu == 'weeks':
    2146         newtimes = newtimes/(24.*7*3600.)
     2262        newtimes = newtimes/(7.)
    21472263    elif Tu == 'days':
    2148         newtimes = newtimes/(24.*3600.)
     2264        newtimes = newtimes*1.
    21492265    elif Tu == 'hours':
    2150         newtimes = newtimes/(3600.)
     2266        newtimes = newtimes*60.
    21512267    elif Tu == 'minutes':
    2152         newtimes = newtimes/(60.)
     2268        newtimes = newtimes*24.*3600.
    21532269
    21542270    return newtimes
     
    1595416070#        print '  ' , '(', inds[i,j,0], ',', inds[i,j,1], ')'
    1595516071
    15956 def sign(number):
    15957     """ Function to provide the sign of a number
    15958       num: number to provide the sign
    15959     >>> sign(7109)
    15960     1
    15961     >>> sign(-3.43512)
    15962     -1.0
    15963     """
    15964     fname = 'sign'
    15965 
    15966     sign = np.abs(number)/number
    15967 
    15968     return sign
    15969 
    15970 def juliandate(yr,mo,dd,hr,mi,ss):
    15971     """ Function to provide the julian date (in days since -4712 January 1st 00 UTC)
    15972           for any greogiran date
    15973       refdate: 1 January 4713 BC (= -4712 January 1), Greenwich mean noon (= 12h UT).
    15974     FROM: https://aa.usno.navy.mil/faq/docs/JD_Formula.php
    15975       after 1990 edition of the U.S. Naval Observatory's Almanac for Computers
    15976     >>> juliandate(1877,8,11,7,30,0)
    15977     2406843.3125
    15978     >>> juliandate(877,8,11,7,30,0)
    15979     2041601.3125
    15980     >>> juliandate(1970,1,1,0,0,0)
    15981     2440588.0
    15982     >>> juliandate(1978,1,1,0,0,0)
    15983     2443510.0
    15984     >>> juliandate(1978,7,21,15,0,0)
    15985     2443712.625
    15986     """
    15987     fname = 'juliandate'
    15988 
    15989     sec1 = dd - 32075.
    15990     sec2 = 1461.*(yr+4800.+(mo-14)/12.)/4.
    15991     sec3 = 367.*(mo-2-(mo-14)/12.*12)/12.
    15992     sec4 = 3.*((yr+4900.+(mo-14.)/12.)/100.)/4.
    15993  
    15994     juliand = int(sec1 + sec2 + sec3 - sec4)
    15995 
    15996     juliand = juliand*1. + (hr + mi/60. + ss/3600.)/24.
    15997 
    15998     # Alternative (without full agreement, just kept in case)
    15999     #K = yr + 0
    16000     #M = mo + 0
    16001     #I = dd + 0
    16002     #UT = hr*1. + mi/60. + ss/3600.
    16003 
    16004     #sec1 = 367.*K
    16005     #sec2 = int((7.*(K+int((M+9)/12.)))/4.)
    16006     #sec3 = int((275.*M)/9.)
    16007     #sec4 = I*1.
    16008     #sec5 = 1721013.5
    16009     #sec6 = UT/24.
    16010     #sec7 = 0.5*sign(100.*K+M*1.-190002.5)
    16011     #sec8 = 0.5
    16012 
    16013     #juliand = sec1 - sec2 + sec3 + sec4 + sec5 + sec6 - sec7 + sec8
    16014     #print '  juliand:', juliand
    16015 
    16016     return juliand
    16017 
    16018 def juliandate_gregorian(juliand):
    16019     """ Function to convert from julian date (days since -4712 January 1st 00 UTC)
    16020          to the equivalent greogiran date
    16021       juliand: julian date to convert
    16022     FROM: https://aa.usno.navy.mil/faq/docs/JD_Formula.php
    16023       after 1990 edition of the U.S. Naval Observatory's Almanac for Computers
    16024     >>> juliandate_gregorian(2406843.3125)
    16025     [1877, 8.0, 11, 7, 30, 0.0]
    16026     >>> juliandate_gregorian(2041601.3125)
    16027     [877, 8.0, 11, 7, 30, 0.0]
    16028     >>> juliandate_gregorian(2440588.0)
    16029     [1970, 1.0, 1, 0, 0, 0.0]
    16030     >>> juliandate_gregorian(2443510.0)
    16031     [1978, 1.0, 1, 0, 0, 0.0]
    16032     >>> juliandate_gregorian(2443712.625)
    16033     [1978, 7.0, 22, 15, 0, 0.0]
    16034     """
    16035     fname = 'juliandate_gregorian'
    16036 
    16037     L = int(juliand+68569)
    16038     N = 4*L/146097
    16039     L = L-(146097*N+3)/4
    16040     I = 4000*(L+1)/1461001
    16041     L = L-1461*I/4+31
    16042     J = 80*L/2447
    16043     K = L-2447*J/80
    16044     L = J/11
    16045     J = J+2.-12.*L
    16046     I = 100*(N-49)+I+L
    16047 
    16048     yr = I
    16049     mo = J
    16050     dd = K
    16051 
    16052     # hr, mi, ss
    16053     ut = juliand - int(juliand)
    16054     utsecs = ut*24.*3600.
    16055     hh = int(utsecs/3600.)
    16056     mi = int((utsecs - hh*3600.)/60.)
    16057     ss = utsecs - hh*3600. - mi*60.
    16058 
    16059     return [yr, mo, dd, hh, mi, ss]
     16072#print juliandate_gregorian(2453408.5)
     16073#print juliandate_gregorian(2453683.5)
     16074
     16075#quit()
    1606016076
    1606116077def fix_CFdates(timevals, origcftimeu, origcal,                                      \
     
    1607016086    >>> fix_CFdates(times, 'days since 1850-01-01 00:00:00', 'noleap',
    1607116087      'days since 1949-12-01 00:00:00')
    16072     [-36477.5 -36448.  -36418.5 -36388.  -36357.5 -36327.  -36296.5 -36265.5
    16073      -36235.  -36204.5 -36174. ]
     16088    [-36478.5 -36449.  -36419.5 -36389.  -36358.5 -36328.  -36297.5 -36266.5
     16089      -36236.  -36205.5 -36175. ]
     16090    >>> times = [56649.5, 56680, 56710.5, 56741, 56771.5, 56802.5, 56833, 56863.5, 56894, 56924.5]
     16091    >>> fix_CFdates(times, 'days since 1850-01-01 00:00:00', 'noleap',
     16092      'days since 1949-12-01 00:00:00')
     16093    [ 20193.5  20224.   20254.5  20285.   20315.5  20346.5  20377.   20407.5
     16094      20438.   20468.5]
    1607416095    """
    1607516096    import datetime as dt
     
    1608516106    origSrefdate = origtv[2]
    1608616107
    16087     yrref=origSrefdate[0:4]
    16088     monref=origSrefdate[5:7]
    16089     dayref=origSrefdate[8:10]
     16108    yrref = int(origSrefdate[0:4])
     16109    monref = int(origSrefdate[5:7])
     16110    dayref = int(origSrefdate[8:10])
    1609016111
    1609116112    if int(yrref) < 1970: origsing = -1.
     
    1611016131        secref = 0
    1611116132
    16112     seconds = juliandate(yrref,monref,dayref,horref,minref,secref)
    16113     seconds = seconds*24.*3600.
     16133    origdays = juliandate(yrref,monref,dayref,horref,minref,secref)
    1611416134
    1611516135    # new
     
    1611816138    newSrefdate = newtv[2]
    1611916139
    16120     yrnew=newSrefdate[0:4]
    16121     monnew=newSrefdate[5:7]
    16122     daynew=newSrefdate[8:10] 
     16140    yrnew = int(newSrefdate[0:4])
     16141    monnew = int(newSrefdate[5:7])
     16142    daynew = int(newSrefdate[8:10]) 
    1612316143
    1612416144    if int(yrnew) < 1970: newsing = -1.
     
    1614316163        secnew = 0
    1614416164
    16145     seconds = juliandate(yrnew,monnew,daynew,hornew,minnew,secnew)
     16165    newdays = juliandate(yrnew,monnew,daynew,hornew,minnew,secnew)
    1614616166
    1614716167    # Using shell date `coreutil' (a relic of the past...)
     
    1615016170    #newsecondsdiff = np.float64(seconds.communicate()[0].replace('\n',''))
    1615116171
    16152     # If the calendar is not gregorian, it needs to be fixed from origSrefdate!
    16153     if origcal == 'noleap' or origcal == '365d':
    16154         print '  ' + fname + ": found non-standard calendar '" + origcal + "' !!"
    16155         # Imposing to gregorian calendar
    16156         newtimevals = gen_impose_gregorian(timevals, origcftimeu, origcal)
    16157 
    16158     # Seconds difference respect new date
    16159     secsdiff = origsecondsdiff - newsecondsdiff
    16160 
    1616116172    if origtunits == 'years':
    16162         secsdtr = 365 * 24 * 3600.
     16173        daysdtr = 365.
    1616316174    elif origtunits == 'weeks':
    16164         secsdtr = 7 * 24 * 3600.
     16175        daysdtr = 7.
    1616516176    elif origtunits == 'days':
    16166         secsdtr = 24 * 3600.
     16177        daysdtr = 1.
    1616716178    elif origtunits == 'hours':
    16168         secsdtr = 3600.
     16179        daysdtr = 1./24.
    1616916180    elif origtunits == 'minutes':
    16170         secsdtr = 60.
     16181        daysdtr = 1./(24.*60.)
    1617116182    elif origtunits == 'seconds':
    16172         secsdtr = 1.
     16183        daysdtr = 1./(24.*3600.)
    1617316184    else:
    1617416185        print errormsg
     
    1617716188        quit(-1)
    1617816189
     16190    # If the calendar is not gregorian, it needs to be fixed from origSrefdate!
     16191    if origcal == 'noleap' or origcal == '365d':
     16192        print '  ' + fname + ": found non-standard calendar '" + origcal + "' !!"
     16193        # Imposing to gregorian calendar
     16194        timevals = gen_impose_gregorian(timevals, origcftimeu, origcal)     
     16195
     16196    # Seconds difference respect new date
     16197    daysdiff = origdays - newdays
     16198
    1617916199    if type(timevals) != type(np.ones((2), dtype=int)):
    1618016200        newtimevals = np.array(timevals, dtype=np.float64)
    16181         newtimevals = newtimevals*secsdtr
     16201        newtimevals = newtimevals*daysdtr
    1618216202    else:
    16183         newtimevals = timevals*secsdtr
    16184 
    16185     newtimevals = newtimevals + origsecondsdiff
    16186     newtimevals = newtimevals - newsecondsdiff
     16203        newtimevals = timevals*daysdtr
     16204
     16205    # Re-scaling to the absolute reference
     16206    newtimevals = newtimevals + origdays
     16207
     16208    # Re-scaling to the CF-time reference
     16209    newtimevals = newtimevals - newdays
    1618716210
    1618816211    # Re-scaling to the new time units
    1618916212    if newtunits == 'years':
    16190         secsdtr = 365 * 24 * 3600.
     16213        daysdtr = 1. / (365.)
    1619116214    elif newtunits == 'weeks':
    16192         secsdtr = 7 * 24 * 3600.
     16215        daysdtr = 1. / 7.
    1619316216    elif newtunits == 'days':
    16194         secsdtr = 24 * 3600.
     16217        daysdtr = 1.
    1619516218    elif newtunits == 'hours':
    16196         secsdtr = 3600.
     16219        daysdtr = 24.
    1619716220    elif newtunits == 'minutes':
    16198         secsdtr = 60.
     16221        daysdtr = 24. * 60.
    1619916222    elif newtunits == 'seconds':
    16200         secsdtr = 1.
     16223        daysdtr = 24. * 3600.
    1620116224    else:
    1620216225        print errormsg
     
    1620416227        print '    available ones: ', availtu
    1620516228        quit(-1)
    16206     newtimevals = newtimevals / secsdtr
     16229    newtimevals = newtimevals * daysdtr
    1620716230
    1620816231    return newtimevals
    1620916232
    1621016233#times = [15.5, 45, 74.5, 105, 135.5, 166, 196.5, 227.5, 258, 288.5, 319]
    16211 #times = [56649.5, 56680, 56710.5, 56741, 56771.5, 56802.5, 56833, 56863.5, 56894, 56924.5]
    16212 #print fix_CFdates(times, 'days since 1850-01-01 00:00:00', 'noleap', \
    16213 #  'days since 1949-12-01 00:00:00')
     16234times = [56649.5, 56680, 56710.5, 56741, 56771.5, 56802.5, 56833, 56863.5, 56894, 56924.5]
     16235print fix_CFdates(times, 'days since 1850-01-01 00:00:00', 'noleap', \
     16236  'days since 1949-12-01 00:00:00')
    1621416237
    1621516238#quit()
Note: See TracChangeset for help on using the changeset viewer.