Changeset 2462 in lmdz_wrf for trunk/tools/generic_tools.py


Ignore:
Timestamp:
Apr 23, 2019, 7:43:12 PM (6 years ago)
Author:
lfita
Message:

Adding:

  • `gen_leapdays': Function to provide how many leap days are between two years avoiding datetime
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/tools/generic_tools.py

    r2461 r2462  
    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# gen_leapdays: Function to provide how many leap days are between two years avoiding datetime
     121# generate_CFtimes: Function to generate CFtimes for a given period, frequency and units
    120122# get_configuration: Function to get the configuration from an ASCII external file
    121123# get_right_CFtimeunits: Function to get the right CFtime units from any given format
    122124# get_specdictionary_HMT: Function to get specific values from a dictionary by selcting that keys with H*M*T
    123125# getting_fixedline: Function to get the values from a line of text with fixed lenght of different values
    124 # generate_CFtimes: Function to generate CFtimes for a given period, frequency and units
    125126# grib_CFequiv: Function to provide the CF name of a GRIB variable code number
    126127# inf_operSlist: Function to provide information from a string as a list separated by
     
    142143# juliandate: Function to provide the julian date (in days since -4712 January 1st 00 UTC)
    143144#   for any greogiran date
     145# juliandate_gregorian: Function to convert from julian date (days since -4712
     146#   January 1st 00 UTC) to the equivalent greogiran date
    144147# latex_fig_array: Function to add an array of figures to an existing tex file
    145148# latex_text: Function to transform a text to LaTeX following style rules
     
    546549    for iyr in range(yeari,yeare+1):
    547550        if days_month(iyr,2) == 29: Nleapdays=Nleapdays+1
     551
     552    return Nleapdays
     553
     554def leapyr(yr):
     555    """ Function to determine if it is a leap year (independently of datetime)
     556    FROM: https://en.wikipedia.org/wiki/Leap_year
     557      yr: year to check
     558    >>> leapyr(2019)
     559    False
     560    >>> leapyr(1976)
     561    True
     562    >>> leapyr(1800)
     563    False
     564    >>> leapyr(1850)
     565    False
     566    """
     567    fname = 'leapyr'
     568
     569    isleap = False
     570    if np.mod(yr,4) == 0: isleap = True
     571    if np.mod(yr,100) == 0: isleap = False
     572    if np.mod(yr,400) == 0: isleap = True
     573
     574    return isleap
     575
     576def gen_leapdays(yeari, yeare):
     577    """ Function to provide how many leap days are between two years avoiding datetime
     578      yeari: initial year from [yeari] Jan 01
     579      yeare: end year until [yearf] Dec 12
     580    >>> gen_leapdays(1970,1980)
     581    3
     582    >>> gen_leapdays(1976,1976)
     583    1
     584    >>> gen_leapdays(1850,1976)
     585    31
     586    """
     587    fname = 'gen_leapdays'
     588
     589    Nleapdays = 0
     590    for iyr in range(yeari,yeare+1):
     591        if leapyr(iyr): Nleapdays=Nleapdays+1
    548592
    549593    return Nleapdays
     
    19762020
    19772021    yrref = refdate.year
     2022    if cal == 'noleap' or cal == '365d':
     2023        for it in range(dimt):
     2024            # Some issues in implementations/machines ...
     2025            # FROM: https://stackoverflow.com/questions/33566939/timedelta-error-with-numpy-longdouble-dtype
     2026            tv = int(timevsecs[it])
     2027            deltaT = dt.timedelta(seconds=tv)
     2028            datetime = refdate + deltaT
     2029            yr = datetime.year
     2030            if yr > yrref:
     2031                Nleapd = leapdays(yrref, yr)
     2032            else:
     2033                Nleapd = leapdays(yr, yrref)
     2034            if datetime.month <= 2 and days_month(yr, 2) > 28: Nleapd = Nleapd - 1
     2035            newtimes[it] = timevsecs[it] + Nleapd*24*3600.
     2036    else:
     2037        print errormsg
     2038        print '  ' + fname + ": calendar '" + cal + "' not ready !!"
     2039        print '    available ones:', availcalendar
     2040        quit(-1)
     2041       
     2042    # Re-transforming to the original units
     2043    if Tu == 'weeks':
     2044        newtimes = newtimes/(24.*7*3600.)
     2045    elif Tu == 'days':
     2046        newtimes = newtimes/(24.*3600.)
     2047    elif Tu == 'hours':
     2048        newtimes = newtimes/(3600.)
     2049    elif Tu == 'minutes':
     2050        newtimes = newtimes/(60.)
     2051
     2052    return newtimes
     2053
     2054def gen_impose_gregorian(timev, Tunits, cal):
     2055    """ Function to impose gregorian calendar to a series of times with a
     2056        non-standard calendar independently from datetime (imposes yr > 1900)
     2057      timev: list of values
     2058      Tunits: CF units of time [Tunits] since [DateRef]
     2059      cal: non standard calendar
     2060      >>> gen_impose_gregorian(np.range(800,10000,100), 'days since 1850-01-01 00:00:00',
     2061        'noleap')
     2062      [ 800. 901.]
     2063      >>> gen_impose_gregorian(-7277.460938, 'days since 1949-12-01 00:00:00', 'noleap')
     2064      [-7272.460938]
     2065    """
     2066    fname = 'gen_impose_gregorian'
     2067
     2068    availTu = ['weeks', 'days', 'hours', 'minutes', 'seconds']
     2069    availcalendar = ['noleap', '365d']
     2070
     2071    lTunits = Tunits.split(' ')
     2072    NTunits = len(lTunits)
     2073    Tu = lTunits[0]
     2074
     2075    if NTunits < 4:
     2076        print infmsg
     2077        print '  ' + fname + ": CF-time units without time, adding '00:00:00' !!"
     2078        Srefdate = lTunits[2] + ' 00:00:00'
     2079    else:
     2080        Srefdate = lTunits[2] + ' ' + lTunits[3]
     2081    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]) ]
     2083
     2084    if type(timev) == type(range(2)):
     2085        dimt = len(timev)
     2086        timev = np.array(timev)
     2087    elif type(timev) == type(np.arange(2)):
     2088        dimt = timev.shape[0]
     2089    elif type(timev) == type(int(2)) or type(timev) == type(np.float(2.)) or         \
     2090      type(timev) == type(float(2.)) or type(timev) == type(np.float32(2.)) or       \
     2091      type(timev) == type(np.float64(2.)):
     2092        dimt = 1
     2093        timev = np.ones(dimt, dtype=type(timev))*timev
     2094    else:
     2095        print errormsg
     2096        print '  ' + fname + ": type of time values: '", type(timev), "' not ready !!"
     2097        print '    available ones:', type(range(2)), type(np.arange(2)),type(int(2)),\
     2098          type(np.float(2.)), type(float(2.)), type(np.float32(2.)),                 \
     2099          type(np.float64(2.))
     2100        quit(-1)
     2101
     2102    if Tu == 'weeks':
     2103        timevsecs = timev * 24. * 7 * 3600.
     2104    elif Tu == 'days':
     2105        timevsecs = timev * 24. * 3600.
     2106    elif Tu == 'hours':
     2107        timevsecs = timev * 3600.
     2108    elif Tu == 'minutes':
     2109        timevsecs = timev * 60.
     2110    elif Tu == 'seconds':
     2111        timevsecs = timev * 1.
     2112    else:
     2113        print errormsg
     2114        print '  ' + fname + ": CF time units '" + Tu + "' not ready !!"
     2115        print '    available ones:', availTu
     2116        quit(-1)
     2117
     2118    newtimes = np.zeros((dimt), dtype=np.float64)
     2119
     2120    refsecs = juliandate(refdate[0], refdate[1], refdate[2], refdate[3], refdate[4], refdate[5])
     2121    refsecs = refsecs*3600.
     2122
     2123    yrref = refdate[0]
    19782124    if cal == 'noleap' or cal == '365d':
    19792125        for it in range(dimt):
     
    1580815954#        print '  ' , '(', inds[i,j,0], ',', inds[i,j,1], ')'
    1580915955
    15810 def leapyr(yr):
    15811     """ Function to determine if it is a leap year (independently of datetime)
    15812     FROM: https://en.wikipedia.org/wiki/Leap_year
    15813       yr: year to check
    15814     >>> leapyr(2019)
    15815     False
    15816     >>> leapyr(1976)
    15817     True
    15818     >>> leapyr(1800)
    15819     False
    15820     >>> leapyr(1850)
    15821     False
    15822     """
    15823     fname = 'leapyr'
    15824 
    15825     isleap = False
    15826     if np.mod(yr,4) == 0: isleap = True
    15827     if np.mod(yr,100) == 0: isleap = False
    15828     if np.mod(yr,400) == 0: isleap = True
    15829 
    15830     return isleap
    15831 
    1583215956def sign(number):
    1583315957    """ Function to provide the sign of a number
     
    1589116015
    1589216016    return juliand
     16017
     16018def 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]
    1589316060
    1589416061def fix_CFdates(timevals, origcftimeu, origcal,                                      \
     
    1594316110        secref = 0
    1594416111
    15945     addsecs = horref*3600 + minref*60 + secref
    15946     addsS = str(addsecs)
    15947 
    15948     # Using shell date `coreutil'
    15949     seconds = sub.Popen('/bin/date +%s -u -d"' + origSrefdate[0:10] + ' ' + addsS +  \
    15950       ' seconds"', shell=True, stdout=sub.PIPE)
    15951     origsecondsdiff = np.float64(seconds.communicate()[0].replace('\n',''))
     16112    seconds = juliandate(yrref,monref,dayref,horref,minref,secref)
     16113    seconds = seconds*24.*3600.
    1595216114
    1595316115    # new
     
    1595616118    newSrefdate = newtv[2]
    1595716119
    15958     yrref=newSrefdate[0:4]
    15959     monref=newSrefdate[5:7]
    15960     dayref=newSrefdate[8:10] 
    15961 
    15962     if int(yrref) < 1970: newsing = -1.
     16120    yrnew=newSrefdate[0:4]
     16121    monnew=newSrefdate[5:7]
     16122    daynew=newSrefdate[8:10] 
     16123
     16124    if int(yrnew) < 1970: newsing = -1.
    1596316125    else: newsing = 1.
    1596416126
    1596516127# Does reference date contain a time value [YYYY]-[MM]-[DD] [HH]:[MI]:[SS]
    1596616128##
    15967     trefT = newcftimeu.find(':')
    15968     if not trefT == -1:
     16129    tnewT = newcftimeu.find(':')
     16130    if not tnewT == -1:
    1596916131        if len(newtv) == 3:
    15970             horref=int(newSrefdate[11:13])
    15971             minref=int(newSrefdate[14:16])
    15972             secref=int(newSrefdate[17:19])
     16132            hornew=int(newSrefdate[11:13])
     16133            minnew=int(newSrefdate[14:16])
     16134            secnew=int(newSrefdate[17:19])
    1597316135        else:
    1597416136            newSreftime = newtv[3]
    15975             horref=int(newSreftime[0:2])
    15976             minref=int(newSreftime[3:5])
    15977             secref=int(newSreftime[6:8])
     16137            hornew=int(newSreftime[0:2])
     16138            minnew=int(newSreftime[3:5])
     16139            secnew=int(newSreftime[6:8])
    1597816140    else:
    15979         horref = 0
    15980         minref = 0
    15981         secref = 0
    15982 
    15983     addsecs = horref*3600 + minref*60 + secref
    15984     addsS = str(addsecs)
    15985 
    15986     # Using shell date `coreutil'
    15987     seconds = sub.Popen('/bin/date +%s -u -d"' + newSrefdate[0:10] + ' ' + addsS +   \
    15988       ' seconds"', shell=True, stdout=sub.PIPE)
    15989     newsecondsdiff = np.float64(seconds.communicate()[0].replace('\n',''))
     16141        hornew = 0
     16142        minnew = 0
     16143        secnew = 0
     16144
     16145    seconds = juliandate(yrnew,monnew,daynew,hornew,minnew,secnew)
     16146
     16147    # Using shell date `coreutil' (a relic of the past...)
     16148    #seconds = sub.Popen('/bin/date +%s -u -d"' + newSrefdate[0:10] + ' ' + addsS +   \
     16149    #  ' seconds"', shell=True, stdout=sub.PIPE)
     16150    #newsecondsdiff = np.float64(seconds.communicate()[0].replace('\n',''))
     16151
     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)
    1599016157
    1599116158    # Seconds difference respect new date
     
    1601516182    else:
    1601616183        newtimevals = timevals*secsdtr
     16184
    1601716185    newtimevals = newtimevals + origsecondsdiff
    1601816186    newtimevals = newtimevals - newsecondsdiff
     
    1603816206    newtimevals = newtimevals / secsdtr
    1603916207
    16040     if origcal == 'noleap3' or origcal == '365d':
    16041         print '  ' + fname + ": found non-standard calendar '" + origcal + "' !!"
    16042         # Imposing to gregorian calendar
    16043         newtimevals = impose_gregorian(newtimevals, newcftimeu, origcal)
    16044 
    1604516208    return newtimevals
    1604616209
Note: See TracChangeset for help on using the changeset viewer.