SPATZ/spatz/logger.py

75 lines
1.8 KiB
Python

import numpy as np
import pandas as pd
from typing import Any, Tuple
from numpy.typing import ArrayLike
from abc import abstractmethod
class Advanceable:
def __init__(self) -> None:
self.reset()
def step(self, dt: float):
"""Advances the simulation data in time.
Args:
dt (float): The step in time to make.
"""
self.__t += dt
self._on_step(dt)
def reset(self):
"""
Reset the Avanceable object to its initial state.
"""
self.__t = 0
self._on_reset()
@abstractmethod
def _on_step(self, dt: float):
pass
@abstractmethod
def _on_reset(self):
pass
def get_time(self) -> float:
"""
Returns:
float: Returns the current time of the Advanceable.
"""
return self.__t
class Logger(Advanceable):
def __init__(self) -> None:
super().__init__()
self.__idx = -1
def _on_step(self, _: float):
self.__df = pd.concat([self.__df, pd.Series().copy()], ignore_index=True)
self.__idx += 1
self.__df.loc[self.__idx, 'time'] = self.get_time()
def _on_reset(self):
self.__df = pd.DataFrame.from_dict({'time': [self.get_time()]})
def write(self, attrib: str, value: Any, domain: str = 'all'):
"""Writes a value to the logger.
Args:
attrib (str): The name of the value to log.
value (Any): The value to log.
domain (str, optional): The domain the value belongs to. Defaults to 'any'.
"""
name = domain + '/' + attrib
if name not in self.__df.columns:
self.__df[name] = pd.Series([pd.NA] * len(self.__df))
self.__df.loc[self.__idx, name] = value
def get_dataframe(self) -> pd.DataFrame:
return self.__df