def plot_parameter_evo(self, file=None): par_df = self.summary.drop([SCIPY.METHOD], axis=1) par_df = par_df.rename(columns={ x: 'error' if x == SCIPY.ERR else x for x in par_df.columns }) # Get axes axes = par_df.plot(subplots=True) fig = figures.get_figure(axes) # x label axes[-1].set_xlabel('Iteration') # ylim for error axes[-1].set_ylim(0, None) if file: fig.set_size_inches(SCIPY.FIG_SIZE) fig.savefig(file, dpi=SCIPY.FIG_DPI) return axes
def validate(self, vp=None): """ Performs a simulation with estimated parameters for the previously selected validation period. Other period can be chosen with the `vp` argument. User chosen `vp` in this method does not override the validation period chosen during instantiation of this class. Parameters ---------- vp: tuple or None Validation period given as a tuple of start and stop time in seconds. Returns ------- dict Validation error, keys: 'tot', '<var1>', '<var2>', ... pandas.DataFrame Simulation result """ # Get estimates est = self.final est.index = [0] # Reset index (needed by model.set_param()) self.logger.info("Validation of parameters: {}".format( str(est.iloc[0].to_dict()))) # Slice data if vp is None: start, stop = self.vp[0], self.vp[1] else: start, stop = vp[0], vp[1] inp_slice = self.inp.loc[start:stop] ideal_slice = self.ideal.loc[start:stop] # Initialize IC parameters and add to known if self.ic_param: for par in self.ic_param: ic = ideal_slice[self.ic_param[par]].iloc[0] self.known[par] = ic # Initialize model model = Model(self.fmu_path) model.set_input(inp_slice) model.set_param(est) model.set_param(self.known) model.set_outputs(list(self.ideal.columns)) # Simulate and get error try: result = model.simulate() except Exception as e: msg = "Problem found inside FMU. Did you set all parameters?" self.logger.error(str(e)) self.logger.error(msg) raise e err = modestpy.estim.error.calc_err(result, ideal_slice) # Create validation plot ax = plot_comparison(result, ideal_slice, f=None) fig = figures.get_figure(ax) fig.set_size_inches(Estimation.FIG_SIZE) fig.savefig(os.path.join(self.workdir, "validation.png"), dpi=Estimation.FIG_DPI) # Remove temp dirs self._clean() # Return return err, result
def estimate(self, get="best"): """ Estimates parameters. Returns average or best estimates depending on `get`. Average parameters are calculated as arithmetic average from all learning periods. Best parameters are those which resulted in the lowest error during respective learning period. It is advised to use 'best' parameters. The chosen estimates ('avg' or 'best') are saved in a csv file `final.csv` in the working directory. In addition estimates and errors from all learning periods are saved in `best_per_run.csv`. Parameters ---------- get: str, default 'best' Type of returned estimates: 'avg' or 'best' Returns ------- dict(str: float) """ # (0) Sanity checks allowed_types = ["best", "avg"] assert get in allowed_types, "get={} is not allowed".format(get) # (1) Initialize local variables # Tuple with method names # e.g. ('MODESTGA', 'PS'), ('MODESTGA', 'SCIPY') or ('MODESTGA', ) methods = self.methods # List of plots to be saved plots = list() cols = ["_method_", "_error_"] + [par_name for par_name in self.est] # Estimates and errors from all iterations from all methods summary = pd.DataFrame(columns=cols) summary.index.name = "_iter_" # List of DataFrames with summaries from all runs summary_list = list() # (2) Double step estimation n = 1 # Learning period counter for period in self.lp: # (2.1) Copy initial parameters est = copy.copy(self.est) # (2.2) Slice data start, stop = period[0], period[1] inp_slice = self.inp.loc[start:stop] ideal_slice = self.ideal.loc[start:stop] # (2.3) Get data for IC parameters and add to known parameters if self.ic_param: for par in self.ic_param: ic = ideal_slice[self.ic_param[par]].iloc[0] self.known[par] = ic # (2.4) Iterate over estimation methods (append results from all) m = 0 # Method counter for m_name in methods: # (2.4.1) Instantiate method class m_class = self.method_dict[m_name][0] m_opts = self.method_dict[m_name][1] m_inst = m_class(self.fmu_path, inp_slice, self.known, est, ideal_slice, **m_opts) # (2.4.2) Estimate m_estimates = m_inst.estimate() # (2.4.3) Update current estimates # (stored in self.est dictionary) for key in est: new_value = m_estimates[key].iloc[0] est[key] = (new_value, est[key][1], est[key][2]) # (2.4.4) Append summary full_traj = m_inst.get_full_solution_trajectory() if m > 0: # Add iterations from previous methods full_traj.index += summary.index[-1] summary = summary.append(full_traj, verify_integrity=True) summary.index.rename("_iter_", inplace=True) # (2.4.5) Save method's plots plots = m_inst.get_plots() for p in plots: fig = figures.get_figure(p["axes"]) fig_file = os.path.join(self.workdir, "{}_{}.png".format(p["name"], n)) fig.set_size_inches(Estimation.FIG_SIZE) fig.savefig(fig_file, dpi=Estimation.FIG_DPI) plt.close("all") # (2.4.6) Increase method counter m += 1 # (2.5) Add summary from this run to the list of all summaries summary_list.append(summary) summary = pd.DataFrame(columns=cols) # Reset # (2.6) Increase learning period counter n += 1 # (3) Get and save best estimates per run and final estimates best_per_run = self._get_finals(summary_list) best_per_run.to_csv(os.path.join(self.workdir, "best_per_run.csv")) if get == "best": cond = best_per_run["_error_"] == best_per_run["_error_"].min() # Take only one if more than one present final = best_per_run.loc[cond].iloc[0:1] final = final.drop("_error_", axis=1) elif get == "avg": final = best_per_run.drop("_error_", axis=1).mean().to_frame().T else: # This shouldn't happen, because the type is checked at (0) raise RuntimeError("Unknown type of estimates: {}".format(get)) final_file = os.path.join(self.workdir, "final.csv") final.to_csv(final_file, index=False) # (4) Save summaries from all learning periods for s, n in zip(summary_list, range(1, len(summary_list) + 1)): sfile = os.path.join(self.workdir, "summary_{}.csv".format(n)) s.to_csv(sfile) # (5) Save error plot including all learning periods ax = self._plot_error_per_run(summary_list, err_type=self.ftype) fig = figures.get_figure(ax) fig.savefig(os.path.join(self.workdir, "errors.png")) # (6) Assign results to instance attributes self.best_per_run = best_per_run self.final = final # (7) Estimates to dict final = final.to_dict("records")[0] # (8) Delete temp dirs self._clean() # (9) Return final estimates return final