Source code for evnrg.simulation.eligibility
from typing import NamedTuple
import numpy as np
import numba as nb
from evnrg.common.status import Status
__all__ = [
'EligibilityRules',
'ECode'
]
[docs]class EligibilityRules(NamedTuple):
mask: np.array = np.empty((0, 0), dtype=np.bool)
threshold_priority: int = Status.HOME_ELIGIBLE
away_threshold: int = 0
home_threshold: int = 0
@nb.njit
def check_mask(begin: int, end: int, col: int, rules: EligibilityRules):
out = Status.INELIGIBLE
if end < rules.mask.shape[0] and begin >= 0:
if rules.mask.ndim == 2:
out = max(rules.mask[begin:end, col].max(), 0)
elif rules.mask.ndim == 1:
out = max(rules.mask[begin:end].max(), 0)
return out
[docs]class ECode(NamedTuple):
"""Small `NamedTuple` to indicate the stop's eligibility.
Attributes:
begin_index (int): Beginning index of the stop.
end_index (int): Ending inde xof the stop.
This is also the index of the beginning of the next
trip.
code (Status): The status of the a stop. Will be one of
`Status.INELIGIBLE`, `Status.HOME_ELIGIBLE`, or
`Status.AWAY_ELIGIBLE`. If the stop is not actually a stop,
`Status.DRIVING` is used.
"""
begin_index: int
end_index: int
code: int
@nb.jit
def stop_eligibility(distance_array: np.array,
begin: int,
vidx: int,
rules: EligibilityRules,
use_mask: bool = True):
"""Returns an `ECode` code indicating the charge eligibility."""
status = Status.DRIVING
end = begin
if not (distance_array[begin] > 0):
status = Status.INELIGIBLE
alen = distance_array.shape[0]
while end < alen and not (distance_array[end] > 0):
end += 1
length = end - begin
# See if we've been stopped long enough to trigger
# a charge opportunity
home = False
if rules.home_threshold > 0 and length > rules.home_threshold:
home = True
away = False
if rules.away_threshold > 0 and length > rules.away_threshold:
away = True
if home and away:
status = rules.threshold_priority
elif home:
status = Status.HOME_ELIGIBLE
elif away:
status = Status.AWAY_ELIGIBLE
# Masks override any time-based rules
# This allows for time-fencing and geo-fencing at the data
# preparation level.
if use_mask:
charge_mask = check_mask(begin, end, vidx, rules)
allowed_mask_values = (
Status.HOME_ELIGIBLE,
Status.AWAY_ELIGIBLE
)
if charge_mask in allowed_mask_values:
status = charge_mask
return ECode(
begin_index=begin,
end_index=end,
code=status
)