class Experiment(object): """ The experiment class provides a general framework for defining a numerical experiment and running it. Any experiment should be subclassed from this "Experiment" cass. The functions to implement are "_initialize", "_compute" and "_visualize". The class provides methods to save data automatically to a central location. By convention a subclass should never modify the parameters passed to it. Use self.data.var_name or self.var_name depending on whether the data should be saved or not """ def __init__(self, params=Data()): self.proj_name = "test" self.run_name = "test" if "proj_name" in params: self.proj_name = params.proj_name if "run_name" in params: self.run_name = params.run_name if "material" in params: self.material = params.material self.params = params self.data = Data() self.data_loc = None self._assign_data_location() self._initialize() def _initialize(self): raise Exception("_initialize is still a stub method") def compute(self): """ Abstract base for the computation of an experiment """ return self._compute() def _compute(self): raise Exception("_compute is still a stub method") def visualize(self): """ Abstract base for the visualization of an experiment """ return self._visualize() def _visualize(self): raise Exception("_visualize is still a stub method") def save(self): """ Save the data and the parameters """ self.params.save(self.data_loc + "/params.pkl") self.data.save(self.data_loc + "/data.pkl") def load(self, filename): self.data = Data.load(filename) def _assign_data_location(self): """ This assigns a data folder to the experiment. The folder is chosen as the data_root/proj_name/run_name# where # is the lowest number that hasn't already been chosen. """ if self.data_loc is not None: return if MPI.COMM_WORLD.Get_rank() is not 0: return folder_name = data_root + "/" + self.proj_name if not os.path.exists(folder_name): os.mkdir(folder_name) timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") new_run_folder_name = folder_name + "/" + self.run_name + "_" + timestamp # We intentionally ignore the case where the folder already exists. # This means data may be overwritten, but it is the user's resp # to make sure this doesn't happen. if not os.path.exists(new_run_folder_name): os.mkdir(new_run_folder_name) self.data_loc = new_run_folder_name