Source code for nrel.hive.model.vehicle.mechatronics.powercurve.tabular_powercurve

from __future__ import annotations

from typing import TYPE_CHECKING, Optional, Dict, Tuple, Any

import numpy as np

from nrel.hive.model.energy.energytype import EnergyType
from nrel.hive.model.vehicle.mechatronics.powercurve.powercurve import Powercurve
from nrel.hive.util.units import Seconds, SECONDS_TO_HOURS, Ratio

if TYPE_CHECKING:
    from nrel.hive.util.units import KwH, Kw


[docs]class TabularPowercurve(Powercurve): """ builds a tabular, interpolated lookup model from a file """ def __init__( self, data: Dict[str, Any], nominal_max_charge_kw: Optional[Kw] = None, battery_capacity_kwh: Optional[KwH] = None, ): if not nominal_max_charge_kw: try: nominal_max_charge_kw = float(data["nominal_max_charge_kw"]) except KeyError: raise AttributeError( "Must initialize TabularPowercurve with attribute nominal_max_charge_kw" ) if not battery_capacity_kwh: try: battery_capacity_kwh = float(data["battery_capacity_kwh"]) except KeyError: raise AttributeError( "Must initialize TabularPowercurve with attribute battery_capacity_kwh" ) expected_keys = [ "name", "power_type", "step_size_seconds", "power_curve", ] for key in expected_keys: if key not in data: raise IOError( f"invalid input file for tabular energy curve model missing key {key}" ) self.id = data["name"] self.energy_type = EnergyType.from_string(data["power_type"]) self.step_size_seconds = data["step_size_seconds"] # seconds if self.energy_type is None: pt = data.get("power_type") if pt is None: pt_msg = "no power_type argument" else: pt_msg = f"invalid energy type '{data['power_type']}'" raise AttributeError( f"TabularPowercurve configuration has {pt_msg}; " f"should be one of {{electric, gasoline}} " ) charging_model = sorted(data["power_curve"], key=lambda x: x["energy_kwh"]) self._charging_energy_kwh = ( np.array(list(map(lambda x: x["energy_kwh"], charging_model))) * battery_capacity_kwh ) self._charging_rate_kw = ( np.array(list(map(lambda x: x["power_kw"], charging_model))) * nominal_max_charge_kw )
[docs] def charge( self, start_soc: Ratio, full_soc: Ratio, power_kw: Kw, duration_seconds: Seconds = 1, # seconds ) -> Tuple[KwH, Seconds]: """ (estimated) energy rate due to fueling, based on an interpolated tabular lookup model :param start_soc: :param full_soc: the cutoff energy limit :param power_kw: how fast to charge :param duration_seconds: the amount of time to charge for :return: the energy source charged for this duration using this charger_id, along with the time charged """ # iterate for as many seconds in a time step, by step_size_seconds t = 0 energy_kwh = start_soc while t < duration_seconds and energy_kwh < full_soc: veh_kw_rate = float( np.interp(energy_kwh, self._charging_energy_kwh, self._charging_rate_kw) ) # kilowatt charge_power_kw = min(veh_kw_rate, power_kw) # kilowatt kwh = charge_power_kw * (self.step_size_seconds * SECONDS_TO_HOURS) # kilowatt-hours energy_kwh += kwh t += self.step_size_seconds return energy_kwh, t