"""This module defines the basic class encapsulating mode variable attributes."""
import copy
from typing import Any, Optional
from cosapp.ports.enum import Scope
from cosapp.ports.variable import BaseVariable, Types
from cosapp.utils.helpers import check_arg
import logging
logger = logging.getLogger(__name__)
[docs]class ModeVariable(BaseVariable):
"""Container for mode variables.
Parameters
----------
name : str
Variable name
port : ModeVarPort, optional
Port to which the variable belongs
value : Any
Variable value
unit : str, optional
Variable unit; default empty string (i.e. dimensionless)
dtype : type or iterable of type, optional
Variable type; default None (i.e. type of initial value)
desc : str, optional
Variable description; default ''
init : Any, optional
Value imposed at the beginning of time simulations, if
variable is an output (unused otherwise).
If unspecified (default), the variable remains untouched.
scope : Scope {PRIVATE, PROTECTED, PUBLIC}, optional
Variable visibility; default PRIVATE
"""
__slots__ = (
"_init",
)
def __init__(
self,
name: str,
port: "cosapp.ports.ModeVarPort",
value: Optional[Any] = None,
unit: str = "",
dtype: Types = None,
desc: str = "",
init: Optional[Any] = None,
scope: Scope = Scope.PRIVATE,
):
from cosapp.ports import ModeVarPort
from cosapp.core.eval_str import EvalString
check_arg(port, "port", ModeVarPort)
init = EvalString(init, port.owner)
init_value = init.eval()
if value is None:
value = init_value
elif init_value is not None:
if not isinstance(init_value, type(value)):
raise TypeError(
f"Initial value {init!r} appears to be inconsistent with arg value={value!r}."
)
super().__init__(name, port, value, unit, dtype, desc, scope)
self._init = init # type: EvalString
def _repr_markdown_(self) -> str:
"""Returns the representation of this variable in Markdown format.
Returns
-------
str
Markdown formatted representation
"""
msg = {"name":f"**{self.name}**" , "unit": f" {self.unit}" if self.unit else ""}
value = self.value
try:
msg["value"] = f"{value:.5g}"
except:
msg["value"] = value
lock_icon = "🔒"
if self.description:
msg["description"] = f" | {self.description}"
else:
msg["description"] = " |"
scope_format = {
Scope.PRIVATE: f" {lock_icon*2} ",
Scope.PROTECTED: f" {lock_icon} ",
Scope.PUBLIC: "",
}
msg["scope"] = scope_format[self.scope]
return (
"{name}{scope}: {value!s}{unit}"
"{description}".format(**msg)
)
@property
def init_expr(self) -> "cosapp.core.eval_str.EvalString":
"""EvalString : expression of initial value"""
return self._init
[docs] def init_value(self) -> Any:
"""Evaluate and return initial value"""
return self._init.eval()
[docs] def initialize(self) -> None:
"""Set mode variable to its prescribed initial value."""
value = self.init_value()
if value is not None:
try:
setattr(self._port, self._name, value)
except AttributeError:
pass
[docs] def copy(self, port: "BasePort", name: Optional[str] = None) -> "ModeVariable":
if name is None:
name = self.name
return ModeVariable(
name,
value = copy.copy(self.value),
port = port,
unit = self._unit,
dtype = copy.copy(self._dtype),
desc = self._desc,
scope = self._scope,
)