fym.logging module

There are several way to save a experimental data in fym. The Logger class provides several convient features to record a numerical data into a HDF5 format file using h5py module.

Inner logger

Basic usage

As long as a Logger instance is registered with the BaseEnv instance as a logger attribute, the Logger instance becomes the inner logger, and is ready to record the inner states.

env = Env()
env.logger = fym.Logger(path="data.h5")

"""..."""

env.close()

Note that you should BaseEnv.close the BaseEnv to ensure all the data is properly recorded into the file.

There are three ways to record BaseEnv’s inner states.

  1. Simply do nothing. The inner logger automatically records the time and all the inner states.

  2. Define the BaseEnv.logger_callback method that returns a dict, or make BaseEnv.set_dot method return a dict. The returned dict will be recorded.

  3. Make both in 2. The two dict is going to be merged where BaseEnv.logger_callback has priority. (i.e., set_dot_returned.update(logger_callback_returned))

BaseEnv.logger_callback

Sometimes, the data users want to record can be simply state variables within the BaseEnv and/or BaseSystem and data derived from them (i.e. control inputs). When using fym, there is one major BaseEnv that runs the simulation with BaseEnv.update method. The BaseEnv.logger_callback method defines information to be recorded in every time step when the environment updates. See the example below.

from fym.core import BaseEnv, BaseSystem
import fym.logging

class Env(BaseEnv):
    """Other methods"""
    def logger_callback(self, t):
        ud = self.controller.get(self.plant)
        return dict(t=t, **self.observe_dict(), ud=ud)

class Controller(BaseSystem):
    """Other methods"""
    def get(self, plant):
        x = plant.state
        k = self.state
        return - k * x[0]

env = Env()
env.logger = fym.logging.Logger("data.h5")
env.reset()

while True:
    env.render()
    done = env.step()

    if done:
        break

env.close()

data = fym.logging.load("data.h5")
print(data)

BaseEnv.set_dot

If all the variables to be recorded is already calculated in BaseEnv.set_dot, simply return a dictionary of them is going to be recorded automatically. It would reduce several lines of code and saves time. For this, you must remove the BaseEnv.logger_callback method as follows.

class Env(BaseEnv):
    """Other methods without logger_callback"""
		def set_dot(self, t):
				x = self.plant.state
				u = self.actuator.state
				ud = self.controller.get(self.plant)

				self.plant.dot = - x
				self.actuator.dot = - (u - ud)
				self.controller.set_dot()

				return dict(t=t, **self.observe_dict(), ud=ud)

When both returns are defined

  • BaseEnv.set_dot has returned value + BaseEnv.logger_callback is defined: record both (priority check: dict.update(set_dot, logger_callback))

  • BaseEnv.set_dot doesn’t have returned value + BaseEnv.logger_callback is defined: record BaseEnv.logger_callback

  • BaseEnv.set_dot has returned value + BaseEnv.logger_callback is not defined: record BaseEnv.set_dot

  • BaseEnv.set_dot doesn’t have returned value + BaseEnv.logger_callback is not defined: record t and BaseEnv.observe_dict()