Ejemplo n.º 1
0
def earthsun_distance(moment):
    r'''Calculates the distance between the earth and the sun as a function 
    of date and time. Uses the Reda and Andreas (2004) model described in [1]_, 
    originally incorporated into the excellent 
    `pvlib library <https://github.com/pvlib/pvlib-python>`_
    
    Parameters
    ----------
    moment : datetime
        Time and date for the calculation, in UTC time (or GMT, which is
        almost the same thing); not local time, [-]
        
    Returns
    -------
    distance : float
        Distance between the center of the earth and the center of the sun,
        [m]        

    Examples
    --------
    >>> earthsun_distance(datetime(2003, 10, 17, 13, 30, 30))
    149090925951.18338
    
    The distance at perihelion, which occurs at 4:21 according to this
    algorithm. The real value is 04:38 (January 2nd).
        
    >>> earthsun_distance(datetime(2013, 1, 2, 4, 21, 50))
    147098089490.67123
    
    The distance at aphelion, which occurs at 14:44 according to this
    algorithm. The real value is dead on - 14:44 (July 5).
    
    >>> earthsun_distance(datetime(2013, 7, 5, 14, 44, 51, 0))
    152097354414.36044
        
    Notes
    -----
    This function is quite accurate. The difference comes from the impact of 
    the moon.

    Note this function is not continuous; the sun-earth distance is not 
    sufficiently accurately modeled for the change to be continuous throughout
    each day.

    References
    ----------
    .. [1] Reda, Ibrahim, and Afshin Andreas. "Solar Position Algorithm for 
       Solar Radiation Applications." Solar Energy 76, no. 5 (January 1, 2004):
       577-89. https://doi.org/10.1016/j.solener.2003.12.003.
    '''
    from fluids.optional import spa
    delta_t = spa.calculate_deltat(moment.year, moment.month)
    import calendar
    unixtime = calendar.timegm(moment.timetuple())
    # Convert datetime object to unixtime
    return float(spa.earthsun_distance(unixtime, delta_t=delta_t)) * au
Ejemplo n.º 2
0
def earthsun_distance(moment):
    r'''Calculates the distance between the earth and the sun as a function 
    of date and time. Uses the Reda and Andreas (2004) model described in [1]_, 
    originally incorporated into the excellent 
    `pvlib library <https://github.com/pvlib/pvlib-python>`_
    
    Parameters
    ----------
    moment : datetime
        Time and date for the calculation, in UTC time (or GMT, which is
        almost the same thing); not local time, [-]
        
    Returns
    -------
    distance : float
        Distance between the center of the earth and the center of the sun,
        [m]        

    Examples
    --------
    >>> earthsun_distance(datetime(2003, 10, 17, 13, 30, 30))
    149090925951.18338
    
    The distance at perihelion, which occurs at 4:21 according to this
    algorithm. The real value is 04:38 (January 2nd).
        
    >>> earthsun_distance(datetime(2013, 1, 2, 4, 21, 50))
    147098089490.67123
    
    The distance at aphelion, which occurs at 14:44 according to this
    algorithm. The real value is dead on - 14:44 (July 5).
    
    >>> earthsun_distance(datetime(2013, 7, 5, 14, 44, 51, 0))
    152097354414.36044
        
    Notes
    -----
    This function is quite accurate. The difference comes from the impact of 
    the moon.

    Note this function is not continuous; the sun-earth distance is not 
    sufficiently accurately modeled for the change to be continuous throughout
    each day.

    References
    ----------
    .. [1] Reda, Ibrahim, and Afshin Andreas. "Solar Position Algorithm for 
       Solar Radiation Applications." Solar Energy 76, no. 5 (January 1, 2004):
       577-89. https://doi.org/10.1016/j.solener.2003.12.003.
    '''
    from fluids.optional import spa
    delta_t = spa.calculate_deltat(moment.year, moment.month)
    import calendar
    unixtime = calendar.timegm(moment.timetuple())
    # Convert datetime object to unixtime
    return float(spa.earthsun_distance(unixtime, delta_t=delta_t))*au
Ejemplo n.º 3
0
def test_deltat_astropy():
    # Can't do a full range of tests because astropy doesn't have
    # answers before 1960, after 1999 in this version
    from astropy.time import Time
    from datetime import datetime
    def delta_t_astropy(dt):
        t = Time(dt, scale='utc')
        return -(dt - t.tt.value).total_seconds()

#    years = range(1, 3000, 100) + [3000]
    years = range(1960, 1999, 1)

    months = range(1, 13)
    for year in years:
        for month in months:
            delta_t_pvlib = spa.calculate_deltat(year, month)
            dt = datetime(year, month, 1)
            delta_t_external = delta_t_astropy(dt)
            assert_allclose(delta_t_pvlib, delta_t_external, atol=.5, rtol=.01)
Ejemplo n.º 4
0
def test_deltat_astropy():
    # Can't do a full range of tests because astropy doesn't have 
    # answers before 1960, after 1999 in this version
    from astropy.time import Time
    from datetime import datetime
    def delta_t_astropy(dt):
        t = Time(dt, scale='utc')
        return -(dt - t.tt.value).total_seconds()
    
#    years = range(1, 3000, 100) + [3000]
    years = range(1960, 1999, 1)
    
    months = range(1, 13)
    for year in years:
        for month in months:
            delta_t_pvlib = spa.calculate_deltat(year, month)
            dt = datetime(year, month, 1)
            delta_t_external = delta_t_astropy(dt)
            assert_allclose(delta_t_pvlib, delta_t_external, atol=.5, rtol=.01)
Ejemplo n.º 5
0
def sunrise_sunset(moment, latitude, longitude):
    r'''Calculates the times at which the sun is at sunset; sunrise; and
    halfway between sunrise and sunset (transit).

    Uses the Reda and Andreas (2004) model described in [1]_,
    originally incorporated into the excellent
    `pvlib library <https://github.com/pvlib/pvlib-python>`_

    Parameters
    ----------
    moment : datetime
        Date for the calculation; needs to contain only the year, month, and
        day; if it is timezone-aware, the return values will be localized to
        this timezone [-]
    latitude : float
        Latitude, between -90 and 90 [degrees]
    longitude : float
        Longitude, between -180 and 180, [degrees]

    Returns
    -------
    sunrise : datetime
        The time at the specified day when the sun rises **IN UTC IF MOMENT
        DOES NOT HAVE A TIMEZONE, OTHERWISE THE TIMEZONE GIVEN WITH IT**, [-]
    sunset : datetime
        The time at the specified day when the sun sets **IN UTC IF MOMENT
        DOES NOT HAVE A TIMEZONE, OTHERWISE THE TIMEZONE GIVEN WITH IT**, [-]
    transit : datetime
        The time at the specified day when the sun is at solar noon - halfway
        between sunrise and sunset **IN UTC IF MOMENT
        DOES NOT HAVE A TIMEZONE, OTHERWISE THE TIMEZONE GIVEN WITH IT**, [-]

    Examples
    --------
    >>> sunrise, sunset, transit = sunrise_sunset(datetime(2018, 4, 17),
    ... 51.0486, -114.07)
    >>> sunrise
    datetime.datetime(2018, 4, 17, 12, 36, 55, 782660)
    >>> sunset
    datetime.datetime(2018, 4, 18, 2, 34, 4, 249326)
    >>> transit
    datetime.datetime(2018, 4, 17, 19, 35, 46, 686265)

    Example with time zone:

    >>> import pytz
    >>> sunrise_sunset(pytz.timezone('America/Edmonton').localize(datetime(2018, 4, 17)), 51.0486, -114.07)
    (datetime.datetime(2018, 4, 16, 6, 39, 1, 570479, tzinfo=<DstTzInfo 'America/Edmonton' MDT-1 day, 18:00:00 DST>), datetime.datetime(2018, 4, 16, 20, 32, 25, 778162, tzinfo=<DstTzInfo 'America/Edmonton' MDT-1 day, 18:00:00 DST>), datetime.datetime(2018, 4, 16, 13, 36, 0, 386341, tzinfo=<DstTzInfo 'America/Edmonton' MDT-1 day, 18:00:00 DST>))

    Note that the year/month/day as input with a timezone, is converted to UTC
    time as well.


    Notes
    -----
    This functions takes on the order of 2 ms per calculation.

    References
    ----------
    .. [1] Reda, Ibrahim, and Afshin Andreas. "Solar Position Algorithm for
       Solar Radiation Applications." Solar Energy 76, no. 5 (January 1, 2004):
       577-89. https://doi.org/10.1016/j.solener.2003.12.003.
    '''
    from fluids.optional import spa
    import calendar
    if moment.utcoffset() is not None:
        moment_utc = moment + moment.utcoffset()
    else:
        moment_utc = moment

    delta_t = spa.calculate_deltat(moment_utc.year, moment_utc.month)
    # Strip the part of the day
    ymd_moment_utc = datetime(moment_utc.year, moment_utc.month, moment_utc.day)
    unixtime = calendar.timegm(ymd_moment_utc.utctimetuple())

    unixtime = unixtime - unixtime % (86400) # Remove the remainder of the value, rounding it to the day it is
    transit, sunrise, sunset = spa.transit_sunrise_sunset(unixtime, lat=latitude, lon=longitude, delta_t=delta_t)

    transit = datetime.utcfromtimestamp(transit)
    sunrise = datetime.utcfromtimestamp(sunrise)
    sunset = datetime.utcfromtimestamp(sunset)

    if moment.tzinfo is not None:
        sunrise = moment.tzinfo.fromutc(sunrise)
        sunset = moment.tzinfo.fromutc(sunset)
        transit = moment.tzinfo.fromutc(transit)
    return sunrise, sunset, transit
Ejemplo n.º 6
0
def solar_position(moment, latitude, longitude, Z=0.0, T=298.15, P=101325.0,
                   atmos_refract=0.5667):
    r'''Calculate the position of the sun in the sky. It is defined in terms of
    two angles - the zenith and the azimith. The azimuth tells where a sundial
    would see the sun as coming from; the zenith tells how high in the sky it
    is. The solar elevation angle is returned for convinience; it is the
    complimentary angle of the zenith.

    The sun's refraction changes how high it appears as though the sun is;
    so values are returned with an optional conversion to the aparent angle.
    This impacts only the zenith/elevation.

    Uses the Reda and Andreas (2004) model described in [1]_,
    originally incorporated into the excellent
    `pvlib library <https://github.com/pvlib/pvlib-python>`_

    Parameters
    ----------
    moment : datetime, optionally with pytz info
        Time and date for the calculation, in UTC time OR in the time zone
        of the latitude/longitude specified BUT WITH A TZINFO ATTATCHED!
        Please be careful with this argument, time zones are confusing. [-]
    latitude : float
        Latitude, between -90 and 90 [degrees]
    longitude : float
        Longitude, between -180 and 180, [degrees]
    Z : float, optional
        Elevation above sea level for the solar position calculation, [m]
    T : float, optional
        Temperature of atmosphere at ground level, [K]
    P : float, optional
        Pressure of atmosphere at ground level, [Pa]
    atmos_refract : float, optional
        Atmospheric refractivity, [degrees]

    Returns
    -------
    apparent_zenith : float
        Zenith of the sun as observed from the ground based after accounting
        for atmospheric refraction, [degrees]
    zenith : float
        Actual zenith of the sun (ignores atmospheric refraction), [degrees]
    apparent_altitude : float
        Altitude of the sun as observed from the ground based after accounting
        for atmospheric refraction, [degrees]
    altitude : float
        Actual altitude of the sun (ignores atmospheric refraction), [degrees]
    azimuth : float
        The azimuth of the sun, [degrees]
    equation_of_time : float
        Equation of time - the number of seconds to be added to the day's
        mean solar time to obtain the apparent solar noon time, [seconds]

    Examples
    --------
    >>> import pytz

    Perth, Australia - sunrise

    >>> solar_position(pytz.timezone('Australia/Perth').localize(datetime(2020, 6, 6, 7, 10, 57)), -31.95265, 115.85742)
    [90.89617025931, 90.89617025931, -0.896170259317, -0.896170259317, 63.6016017691, 79.0711232143]

    Perth, Australia - Comparing against an online source
    https://www.suncalc.org/#/-31.9526,115.8574,9/2020.06.06/14:30/1/0

    >>> solar_position(pytz.timezone('Australia/Perth').localize(datetime(2020, 6, 6, 14, 30, 0)), -31.95265, 115.85742)
    [63.4080568623, 63.4400018158, 26.59194313766, 26.55999818417, 325.121376246, 75.7467475485]

    Perth, Australia - time input without timezone; must be converted by user to UTC!

    >>> solar_position(datetime(2020, 6, 6, 14, 30, 0) - timedelta(hours=8), -31.95265, 115.85742)
    [63.4080568623, 63.4400018158, 26.59194313766, 26.55999818417, 325.121376246, 75.7467475485]

    Sunrise occurs when the zenith is 90 degrees (Calgary, AB):

    >>> local_time = datetime(2018, 4, 15, 6, 43, 5)
    >>> local_time = pytz.timezone('America/Edmonton').localize(local_time)
    >>> solar_position(local_time, 51.0486, -114.07)[0]
    90.0005468548

    Sunset occurs when the zenith is 90 degrees (13.5 hours later in this case):

    >>> solar_position(pytz.timezone('America/Edmonton').localize(datetime(2018, 4, 15, 20, 30, 28)), 51.0486, -114.07)
    [89.999569566, 90.5410381216, 0.000430433876, -0.541038121618, 286.831378190, 6.63142952587]

    Notes
    -----
    If you were standing at the same longitude of the sun such that it was no
    further east or west than you were, the amount of angle it was south or
    north of you is the *zenith*. If it were directly overhead it would be 0°;
    a little north or south and it would be a little positive;
    near sunset or sunrise, near 90°; and at night, between 90° and 180°.

    The *solar altitude angle* is defined as 90° -`zenith`.
    Note the *elevation* angle is just another name for the *altitude* angle.

    The *azimuth* the angle in degrees that the sun is East of the North angle.
    It is positive North eastwards 0° to 360°. Other conventions may be used.

    Note that due to differences in atmospheric refractivity, estimation of
    sunset and sunrise are accuract to no more than one minute. Refraction
    conditions truly vary across the atmosphere; so characterizing it by an
    average value is limiting as well.

    References
    ----------
    .. [1] Reda, Ibrahim, and Afshin Andreas. "Solar Position Algorithm for
       Solar Radiation Applications." Solar Energy 76, no. 5 (January 1, 2004):
       577-89. https://doi.org/10.1016/j.solener.2003.12.003.
    .. [2] "Navigation - What Azimuth Description Systems Are in Use? -
       Astronomy Stack Exchange."
       https://astronomy.stackexchange.com/questions/237/what-azimuth-description-systems-are-in-use?rq=1.
    '''
    from fluids.optional import spa
    import calendar
    tt = moment.utctimetuple()
    delta_t = spa.calculate_deltat(tt.tm_year, tt.tm_mon)
    unixtime = calendar.timegm(tt)
    # Input pressure in milibar; input temperature in deg C
#    print(dict(unixtime=unixtime, lat=latitude, lon=longitude, elev=Z,
#                          pressure=P*1E-2, temp=T-273.15, delta_t=delta_t,
#                          atmos_refract=atmos_refract, sst=False))
    result = spa.solar_position(unixtime, lat=latitude, lon=longitude, elev=Z,
                          pressure=P*1E-2, temp=T-273.15, delta_t=delta_t,
                          atmos_refract=atmos_refract, sst=False)
    # confirmed equation of time https://www.minasi.com/figeot.asp
    # Convert minutes to seconds; sometimes negative, sometimes positive

    result[-1] = result[-1]*60.0
    return result
Ejemplo n.º 7
0
def sunrise_sunset(moment, latitude, longitude):
    r'''Calculates the times at which the sun is at sunset; sunrise; and 
    halfway between sunrise and sunset (transit).
    
    Uses the Reda and Andreas (2004) model described in [1]_, 
    originally incorporated into the excellent 
    `pvlib library <https://github.com/pvlib/pvlib-python>`_    

    Parameters
    ----------
    moment : datetime
        Date for the calculation; needs to contain only the year, month, and
        day, [-]
    latitude : float
        Latitude, between -90 and 90 [degrees]
    longitude : float
        Longitude, between -180 and 180, [degrees]

    Returns
    -------
    sunrise : datetime
        The time at the specified day when the sun rises **IN UTC**, [-]
    sunset : datetime
        The time at the specified day when the sun sets **IN UTC**, [-]
    transit : datetime
        The time at the specified day when the sun is at solar noon - halfway 
        between sunrise and sunset **IN UTC**, [-]

    Examples
    --------
    >>> sunrise, sunset, transit = sunrise_sunset(datetime(2018, 4, 17), 
    ... 51.0486, -114.07)
    >>> sunrise
    datetime.datetime(2018, 4, 17, 12, 36, 55, 782660)
    >>> sunset
    datetime.datetime(2018, 4, 18, 2, 34, 4, 249326)
    >>> transit
    datetime.datetime(2018, 4, 17, 19, 35, 46, 686265)
    
    Notes
    -----    
    This functions takes on the order of 2 ms per calculation.
    
    The reason the function cannot return the time correct the local
    timezone is that the function does not know the timezone at the specified
    lat/long.

    References
    ----------
    .. [1] Reda, Ibrahim, and Afshin Andreas. "Solar Position Algorithm for 
       Solar Radiation Applications." Solar Energy 76, no. 5 (January 1, 2004):
       577-89. https://doi.org/10.1016/j.solener.2003.12.003.
    '''
    from fluids.optional import spa
    delta_t = spa.calculate_deltat(moment.year, moment.month)
    # Strip the part of the day
    moment = datetime(moment.year, moment.month, moment.day)
    import calendar
    unixtime = calendar.timegm(moment.timetuple())
    unixtime = unixtime - unixtime % (
        86400
    )  # Remove the remainder of the value, rounding it to the day it is
    transit, sunrise, sunset = spa.transit_sunrise_sunset(np.array([unixtime]),
                                                          lat=latitude,
                                                          lon=longitude,
                                                          delta_t=delta_t,
                                                          numthreads=1)

    transit = datetime.utcfromtimestamp(float(transit))
    sunrise = datetime.utcfromtimestamp(float(sunrise))
    sunset = datetime.utcfromtimestamp(float(sunset))
    return sunrise, sunset, transit
Ejemplo n.º 8
0
def solar_position(moment,
                   latitude,
                   longitude,
                   Z=0.0,
                   T=298.15,
                   P=101325.0,
                   atmos_refract=0.5667):
    r'''Calculate the position of the sun in the sky. It is defined in terms of
    two angles - the zenith and the azimith. The azimuth tells where a sundial
    would see the sun as coming from; the zenith tells how high in the sky it
    is. The solar elevation angle is returned for convinience; it is the 
    complimentary angle of the zenith.
    
    The sun's refraction changes how high it appears as though the sun is;
    so values are returned with an optional conversion to the aparent angle.
    This impacts only the zenith/elevation.
    
    Uses the Reda and Andreas (2004) model described in [1]_, 
    originally incorporated into the excellent 
    `pvlib library <https://github.com/pvlib/pvlib-python>`_    
    
    Parameters
    ----------
    moment : datetime
        Time and date for the calculation, in local UTC time (not daylight 
        savings time), [-]
    latitude : float
        Latitude, between -90 and 90 [degrees]
    longitude : float
        Longitude, between -180 and 180, [degrees]
    Z : float, optional
        Elevation above sea level for the solar position calculation, [m]
    T : float, optional
        Temperature of atmosphere at ground level, [K]
    P : float, optional
        Pressure of atmosphere at ground level, [Pa]
    atmos_refract : float, optional
        Atmospheric refractivity, [degrees]

    Returns
    -------
    apparent_zenith : float
        Zenith of the sun as observed from the ground based after accounting
        for atmospheric refraction, [degrees]
    zenith : float
        Actual zenith of the sun (ignores atmospheric refraction), [degrees]
    apparent_altitude : float
        Altitude of the sun as observed from the ground based after accounting
        for atmospheric refraction, [degrees]
    altitude : float
        Actual altitude of the sun (ignores atmospheric refraction), [degrees]
    azimuth : float
        The azimuth of the sun, [degrees]
    equation_of_time : float
        Equation of time - the number of seconds to be added to the day's
        mean solar time to obtain the apparent solar noon time, [seconds]

    Examples
    --------
    >>> solar_position(datetime(2003, 10, 17, 13, 30, 30), 45, 45)
    [140.8367913391112, 140.8367913391112, -50.83679133911118, -50.83679133911118, 329.9096671679604, 878.4902950980904]

    Sunrise occurs when the zenith is 90 degrees (Calgary, AB):
    
    >>> solar_position(datetime(2018, 4, 15, 6, 43, 5), 51.0486, -114.07)[0]
    90.00054676987014
    
    Sunrise also occurs when the zenith is 90 degrees (13.5 hours later):
        
    >>> solar_position(datetime(2018, 4, 15, 20, 30, 28), 51.0486, -114.07)
    [89.9995695661236, 90.54103812161853, 0.00043043387640950836, -0.5410381216185247, 286.8313781904518, 6.631429525878048]
    
    Notes
    -----    
    If you were standing at the same longitude of the sun such that it was no
    further east or west than you were, the amount of angle it was south or 
    north of you is the *zenith*. If it were directly overhead it would be 0°;
    a little north or south and it would be a little positive;
    near sunset or sunrise, near 90°; and at night, between 90° and 180°.
    
    The *solar altitude angle* is defined as 90° -`zenith`.
    Note the *elevation* angle is just another name for the *altitude* angle.
    
    The *azimuth* the angle in degrees that the sun is East of the North angle.
    It is positive North eastwards 0° to 360°. Other conventions may be used.
    
    Note that due to differences in atmospheric refractivity, estimation of
    sunset and sunrise are accuract to no more than one minute. Refraction
    conditions truly vary across the atmosphere; so characterizing it by an
    average value is limiting as well.

    References
    ----------
    .. [1] Reda, Ibrahim, and Afshin Andreas. "Solar Position Algorithm for 
       Solar Radiation Applications." Solar Energy 76, no. 5 (January 1, 2004):
       577-89. https://doi.org/10.1016/j.solener.2003.12.003.
    .. [2] "Navigation - What Azimuth Description Systems Are in Use? - 
       Astronomy Stack Exchange." 
       https://astronomy.stackexchange.com/questions/237/what-azimuth-description-systems-are-in-use?rq=1.
    '''
    from fluids.optional import spa
    delta_t = spa.calculate_deltat(moment.year, moment.month)
    unixtime = time.mktime(moment.timetuple())
    # Input pressure in milibar; input temperature in deg C
    result = spa.solar_position_numpy(unixtime,
                                      lat=latitude,
                                      lon=longitude,
                                      elev=Z,
                                      pressure=P * 1E-2,
                                      temp=T - 273.15,
                                      delta_t=delta_t,
                                      atmos_refract=atmos_refract,
                                      sst=False,
                                      esd=False)
    # confirmed equation of time https://www.minasi.com/figeot.asp
    # Convert minutes to seconds; sometimes negative, sometimes positive

    result[-1] = result[-1] * 60.0
    return result
Ejemplo n.º 9
0
def sunrise_sunset(moment, latitude, longitude):
    r'''Calculates the times at which the sun is at sunset; sunrise; and 
    halfway between sunrise and sunset (transit).
    
    Uses the Reda and Andreas (2004) model described in [1]_, 
    originally incorporated into the excellent 
    `pvlib library <https://github.com/pvlib/pvlib-python>`_    

    Parameters
    ----------
    moment : datetime
        Date for the calculationl; needs to contain only the year, month, and
        day, [-]
    latitude : float
        Latitude, between -90 and 90 [degrees]
    longitude : float
        Longitude, between -180 and 180, [degrees]

    Returns
    -------
    sunrise : datetime
        The time at the specified day when the sun rises **IN UTC**, [-]
    sunset : datetime
        The time at the specified day when the sun sets **IN UTC**, [-]
    transit : datetime
        The time at the specified day when the sun is at solar noon - halfway 
        between sunrise and sunset **IN UTC**, [-]

    Examples
    --------
    >>> sunrise, sunset, transit = sunrise_sunset(datetime(2018, 4, 17), 
    ... 51.0486, -114.07)
    >>> sunrise
    datetime.datetime(2018, 4, 17, 12, 36, 55, 782660)
    >>> sunset
    datetime.datetime(2018, 4, 18, 2, 34, 4, 249326)
    >>> transit
    datetime.datetime(2018, 4, 17, 19, 35, 46, 686265)
    
    Notes
    -----    
    This functions takes on the order of 2 ms per calculation.
    
    The reason the function cannot return the time correct the local
    timezone is that the function does not know the timezone at the specified
    lat/long.

    References
    ----------
    .. [1] Reda, Ibrahim, and Afshin Andreas. "Solar Position Algorithm for 
       Solar Radiation Applications." Solar Energy 76, no. 5 (January 1, 2004):
       577-89. https://doi.org/10.1016/j.solener.2003.12.003.
    '''
    from fluids.optional import spa
    delta_t = spa.calculate_deltat(moment.year, moment.month)
    # Strip the part of the day
    moment = datetime(moment.year, moment.month, moment.day)
    import calendar 
    unixtime = calendar.timegm(moment.timetuple())
    unixtime = unixtime - unixtime % (86400) # Remove the remainder of the value, rounding it to the day it is
    transit, sunrise, sunset = spa.transit_sunrise_sunset(np.array([unixtime]), lat=latitude, lon=longitude, delta_t=delta_t, numthreads=1)
    
    transit = datetime.utcfromtimestamp(float(transit))
    sunrise = datetime.utcfromtimestamp(float(sunrise))
    sunset = datetime.utcfromtimestamp(float(sunset))
    return sunrise, sunset, transit
Ejemplo n.º 10
0
def solar_position(moment, latitude, longitude, Z=0.0, T=298.15, P=101325.0, 
                           atmos_refract=0.5667):
    r'''Calculate the position of the sun in the sky. It is defined in terms of
    two angles - the zenith and the azimith. The azimuth tells where a sundial
    would see the sun as coming from; the zenith tells how high in the sky it
    is. The solar elevation angle is returned for convinience; it is the 
    complimentary angle of the zenith.
    
    The sun's refraction changes how high it appears as though the sun is;
    so values are returned with an optional conversion to the aparent angle.
    This impacts only the zenith/elevation.
    
    Uses the Reda and Andreas (2004) model described in [1]_, 
    originally incorporated into the excellent 
    `pvlib library <https://github.com/pvlib/pvlib-python>`_    
    
    Parameters
    ----------
    moment : datetime
        Time and date for the calculation, in local UTC time (not daylight 
        savings time), [-]
    latitude : float
        Latitude, between -90 and 90 [degrees]
    longitude : float
        Longitude, between -180 and 180, [degrees]
    Z : float, optional
        Elevation above sea level for the solar position calculation, [m]
    T : float, optional
        Temperature of atmosphere at ground level, [K]
    P : float, optional
        Pressure of atmosphere at ground level, [Pa]
    atmos_refract : float, optional
        Atmospheric refractivity, [degrees]

    Returns
    -------
    apparent_zenith : float
        Zenith of the sun as observed from the ground based after accounting
        for atmospheric refraction, [degrees]
    zenith : float
        Actual zenith of the sun (ignores atmospheric refraction), [degrees]
    apparent_altitude : float
        Altitude of the sun as observed from the ground based after accounting
        for atmospheric refraction, [degrees]
    altitude : float
        Actual altitude of the sun (ignores atmospheric refraction), [degrees]
    azimuth : float
        The azimuth of the sun, [degrees]
    equation_of_time : float
        Equation of time - the number of seconds to be added to the day's
        mean solar time to obtain the apparent solar noon time, [seconds]

    Examples
    --------
    >>> solar_position(datetime(2003, 10, 17, 13, 30, 30), 45, 45)
    [140.8367913391112, 140.8367913391112, -50.83679133911118, -50.83679133911118, 329.9096671679604, 878.4902950980904]

    Sunrise occurs when the zenith is 90 degrees (Calgary, AB):
    
    >>> solar_position(datetime(2018, 4, 15, 6, 43, 5), 51.0486, -114.07)[0]
    90.00054676987014
    
    Sunrise also occurs when the zenith is 90 degrees (13.5 hours later):
        
    >>> solar_position(datetime(2018, 4, 15, 20, 30, 28), 51.0486, -114.07)
    [89.9995695661236, 90.54103812161853, 0.00043043387640950836, -0.5410381216185247, 286.8313781904518, 6.631429525878048]
    
    Notes
    -----    
    If you were standing at the same longitude of the sun such that it was no
    further east or west than you were, the amount of angle it was south or 
    north of you is the *zenith*. If it were directly overhead it would be 0°;
    a little north or south and it would be a little positive;
    near sunset or sunrise, near 90°; and at night, between 90° and 180°.
    
    The *solar altitude angle* is defined as 90° -`zenith`.
    Note the *elevation* angle is just another name for the *altitude* angle.
    
    The *azimuth* the angle in degrees that the sun is East of the North angle.
    It is positive North eastwards 0° to 360°. Other conventions may be used.
    
    Note that due to differences in atmospheric refractivity, estimation of
    sunset and sunrise are accuract to no more than one minute. Refraction
    conditions truly vary across the atmosphere; so characterizing it by an
    average value is limiting as well.

    References
    ----------
    .. [1] Reda, Ibrahim, and Afshin Andreas. "Solar Position Algorithm for 
       Solar Radiation Applications." Solar Energy 76, no. 5 (January 1, 2004):
       577-89. https://doi.org/10.1016/j.solener.2003.12.003.
    .. [2] "Navigation - What Azimuth Description Systems Are in Use? - 
       Astronomy Stack Exchange." 
       https://astronomy.stackexchange.com/questions/237/what-azimuth-description-systems-are-in-use?rq=1.
    '''
    from fluids.optional import spa
    delta_t = spa.calculate_deltat(moment.year, moment.month)
    unixtime = time.mktime(moment.timetuple())    
    # Input pressure in milibar; input temperature in deg C
    result = spa.solar_position_numpy(unixtime, lat=latitude, lon=longitude, elev=Z, 
                          pressure=P*1E-2, temp=T-273.15, delta_t=delta_t,
                          atmos_refract=atmos_refract, sst=False, esd=False)
    # confirmed equation of time https://www.minasi.com/figeot.asp
    # Convert minutes to seconds; sometimes negative, sometimes positive

    result[-1] = result[-1]*60.0 
    return result