"""Fast scalar path for oggm.utils.floatyear_to_date (same algorithm, plain Python). Arrays and return_day=True still go to the original. patch() installs it where FlowlineModel.get_mb and get_days_of_month look it up. """ import bisect import math import numpy as np from oggm import utils from oggm.utils import _funcs _orig = _funcs.floatyear_to_date _CUM = [31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365] _ONE_M = math.nextafter(1.0, 0.0) def fast_floatyear_to_date(yr, return_day=False): if return_day or np.ndim(yr) != 0: return _orig(yr, return_day=return_day) yr = float(yr) y = math.floor(yr) f = min(max(yr - y, 0.0), _ONE_M) leap = (y % 4 == 0) and ((y % 100 != 0) or (y % 400 == 0)) n = 365 + leap d = min(max(round(f * n), 0), n - 1) # round() is half-to-even, like np.rint if y + d / n > yr: d = min(max(d - 1, 0), n - 1) doy = d + 1 adj = doy - (1 if (leap and doy > 59) else 0) return np.int64(y), np.int64(bisect.bisect_left(_CUM, adj) + 1) def patch(): utils.floatyear_to_date = fast_floatyear_to_date _funcs.floatyear_to_date = fast_floatyear_to_date