Source code for dove.core.cashflow
# Copyright 2024, Battelle Energy Alliance, LLC
# ALL RIGHTS RESERVED
"""
``dove.core.cashflow``
======================
Module containing cash flow classes for financial modeling in DOVE.
This module defines classes for representing financial cash flows in energy system models,
including both costs and revenues. These cash flows can vary over time and have
configurable scaling factors.
Classes
--------
CashFlow: Abstract base class for all cash flows
Cost: Represents expenses or negative cash flows
Revenue: Represents income or positive cash flows
"""
from __future__ import annotations
from abc import ABC
from dataclasses import dataclass, field
from typing import TypeAlias
import numpy as np
from numpy.typing import NDArray
TimeDependent: TypeAlias = list[float] | NDArray[np.float64]
[docs]
@dataclass
class CashFlow(ABC):
"""
Abstract base class representing a financial cash flow.
This class serves as the foundation for different types of cash flows in the system.
Cash flows have associated pricing profiles that can vary over time. If a price profile
is not provided, it will default to using alpha as the fixed recurring value for the
length of the simulation.
Parameters
----------
name : str
Identifier for the cash flow.
price_profile : TimeDependent, optional
Time-dependent pricing data, defaults to empty list.
alpha : float, optional
Scaling factor for the cash flow magnitude, defaults to 1.0.
dprime : float, optional
Adjustment factor for price calculations, defaults to 1.0.
scalex : float, optional
Horizontal scaling factor for time-dependent functions, defaults to 1.0.
price_is_levelized : bool, optional
Flag indicating if the price is levelized, defaults to False. (Not Implemented)
sign : int, optional
Direction of the cash flow (positive or negative), defaults to 0.
"""
name: str
price_profile: TimeDependent = field(default_factory=list)
alpha: float = 1.0
dprime: float = 1.0
scalex: float = 1.0
price_is_levelized: bool = False
sign: int = 0
def __post_init__(self) -> None:
"""
Process the cashflow's price_profile after initialization.
"""
# Convert price_profile
self.price_profile = np.asarray(self.price_profile, float).ravel()
# Scale price profile by alpha
if len(self.price_profile) > 0:
self.price_profile = np.multiply(self.alpha, self.price_profile)
[docs]
@dataclass
class Cost(CashFlow):
"""
Represents a negative cash flow or cost.
This class is a subclass of the `CashFlow` abstract base class that specifically
represents costs or expenses. A `Cost` instance always has a negative sign,
which is enforced by setting the `sign` class attribute to -1.
Attributes
----------
sign : int
Fixed value of -1 to indicate that this cash flow represents a cost.
Examples
--------
A recurring cost of $1,000.00 per time period:
>>> cost = Cost(name="Recurring Cost", alpha=1000.0)
Note that not specifying a `price_profile` will default to using `alpha` as
the fixed value for the length of the simulation.
A time-dependent cost with a specific price profile:
>>> cost = Cost(
... name="Time-Dependent Cost",
... price_profile=[0.5, 1.0, 1.5],
... alpha=1000.0)
"""
sign: int = -1
[docs]
@dataclass
class Revenue(CashFlow):
"""
A class representing revenue in a financial context.
Revenue is a subclass of CashFlow with a positive sign (+1), indicating
incoming cash flow. It represents income generated from the sale of goods,
services, or other business activities.
Attributes
----------
sign : int
The sign of the cash flow, set to +1 for revenue (incoming cash).
"""
sign: int = +1