Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utah Model Chilling Units #1753

Open
2 tasks done
saschahofmann opened this issue May 16, 2024 · 5 comments
Open
2 tasks done

Utah Model Chilling Units #1753

saschahofmann opened this issue May 16, 2024 · 5 comments
Labels
enhancement New feature or request

Comments

@saschahofmann
Copy link
Contributor

saschahofmann commented May 16, 2024

Addressing a Problem?

I am currently implementing an indicator that computes utah model chilling units based of Richardson EA, Seeley SD, Walker DR (1974) A model for estimating the completion of rest for Redhaven and Elberta peach trees. HortScience 9(4), 331-332.

The computation is quite straightforward but requires hourly temperature data. Since we don't have this I am implementing some utility function to compute hourly temperature from daily maximum and minimum temperature.

I was wondering whether you would be interested in me integrating this into xclim. My code would need some more adaptations to work with different calendars etc. but I think it could be done.

Additional context

Computing the hourly temperature requires computing time of sunrise and sunset, which is probably the biggest headache. My computation is based on this https://en.wikipedia.org/wiki/Sunrise_equation. This paper is suggesting how to compute the hourly temperature, it assumes that minimum temperature is reached just before sunrise, that maximum temperature is reached two hours before sunset and that during daylight the relation ship is sinoid and during nighttime logarithmic.

Most of the logic is needed because in UTC today's sunrise could be yesterday or tomorrow for locations close to -180 or 180 respectively. Additionally, the sun equation requires julian dates that I so far have found difficult to compute without several calendar conversions (we are using a 360day calendar from cftime and I couldn't figure out how to use cftime.date2num to compute the julian day number).

Contribution

  • I would be willing/able to open a Pull Request to contribute this feature.

Code of Conduct

  • I agree to follow this project's Code of Conduct
@saschahofmann saschahofmann added the enhancement New feature or request label May 16, 2024
@coxipi
Copy link
Contributor

coxipi commented May 16, 2024

This might help you: xclim.indices.helpers.cosine_of_solar_zenith_angle ? The case with sunlit=True?

@saschahofmann
Copy link
Contributor Author

Do I understand this right that this would be equivalent to this ?
image

@coxipi
Copy link
Contributor

coxipi commented May 21, 2024

# cosine_of_solar_zenith_angle
    if sunlit:
        # hour angle of sunset (eq. 2.15), with NaNs inside the polar day/night
        tantan = -np.tan(lat) * np.tan(declination)
        h_ss = np.arccos(tantan.where(abs(tantan) <= 1))

I would say no, it looks like it implements the first formula on the wiki page:
image

The code in stat == "instant" uses the formula:
image
see https://en.wikipedia.org/wiki/Solar_zenith_angle
which is equivalent to your formula, with the altitude not fixed, but to be computed. The output cosine_of_solar_zenith_angle is the cosine of solar zenith angle = sin of solar altitude.

I'm a bit confused, is this a fixed or a variable quantity? @aulemahal , any thoughts?

@aulemahal
Copy link
Collaborator

@coxipi I'm not sure I understand your question. Which quantity are you referring to ?

@saschahofmann Indeed cosine_of_solar_zenith_angle might help you, but maybe not as is, more like an inspiration.

(All functions referred to in this comment are in the xclim.indices.helpers module)

In the function, for the finer-than-daily case, we compute the local hour angle of the sun, of the time coordinate as:

S_IN_D = 24 * 60 * 60   # Number of seconds in a day
if time.dtype == "O":  # cftime
    # time_as_s : seconds elapsed since Jan 1st 1970 at 00:00.
    time_as_s = time.copy(data=xr.CFTimeIndex(time.values).asi8 / 1e6)
else:  # numpy
    time_as_s = time.copy(data=time.astype(float) / 1e9)
h_s_utc = (
    (
        (time_as_s % S_IN_D)   # Number of seconds since last midnight
        / S_IN_D               # Fraction of a day since last midnight
    ) * 2 * np.pi              # as radians (1 day = 2 pi)
   - np.pi                     # Midnight is -pi, noon is 0, next midnight is pi (see note)
).assign_attrs( units="rad")
h_s = h_s_utc + lon            # Assuming time as UTC we get local hour angle by simply adding longitude in radians

note : h_s is in radians, so it is defined modulo 2 pi. At the last step of h_s_utc, the current function does + np.pi, it's the same once we ensure radians are wrapped. See _wrap_radians.

Thus we have the local hour angle.

The (local) sunrise and sunset hour angles are further below, as shown by Eric:

if sunlit:
    # hour angle of sunset (eq. 2.15), with NaNs inside the polar day/night
    tantan = -np.tan(lat) * np.tan(declination)
    h_ss = np.arccos(tantan.where(abs(tantan) <= 1))

Where, declination was computed with solar_declination, two methods are implemented.

There is also a time_correction_for_solar_angle function that was taken from this article : https://link.springer.com/article/10.1007/s00484-020-01900-5, which cites this dead website : https://web.archive.org/web/20130217133755/http://www2.ncdc.noaa.gov/docs/gviug/html/l/app-l.htm. I have not dug deep enough to fully understand what that does, but it was needed to get similar results the first article, when implementing the cosine_of_solar_zenith_angle function for MRT and UTCI. The correction is used when we want the instant cosine, which means you might want it if you are comparing "instant" hour angles.

The cosine_of_solar_zenith_angle actually does an integral when stat is not "instant", which is why (?) the correction is not always required and why some of the trigonometric formulations are different : they are already integrated.

@saschahofmann
Copy link
Contributor Author

I actually figured that for my needs its enough to have the daily temperature distribution. The true times don't really matter that much. So I used xclim's day_lengths function and computed the hourly temperature but put the sunrise globally at midnight and sunrise would then be after daylength hours. Since I am using this to compute daily aggregated values like chilling units the true timestamps don't really matter. Would you be happy with an implementation like that ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants