def optimize_restarts(self, num_restarts=10, robust=False, verbose=True, parallel=False, num_processes=None, **kwargs):
        initial_length = len(self.optimization_runs)
        initial_parameters = self.optimizer_array.copy()
        if parallel:
            try:
                pool = mp.Pool(processes=num_processes)
                obs = [self.copy() for i in range(num_restarts)]
                [obs[i].randomize() for i in range(num_restarts-1)]
                jobs = pool.map(opt_wrapper, [(o,kwargs) for o in obs])
                pool.close()
                pool.join()
            except KeyboardInterrupt:
                print("Ctrl+c received, terminating and joining pool.")
                pool.terminate()
                pool.join()
        for i in range(num_restarts):
            try:
                if not parallel:
                    if i > 0:
                        self.randomize()
                    self.optimize(**kwargs)
                else:
                    self.optimization_runs.append(jobs[i])
                if verbose:
                    print(("Optimization restart {0}/{1}, f = {2}".format(i + 1, num_restarts, self.optimization_runs[-1].f_opt)))
            except Exception as e:
                if robust:
                    print(("Warning - optimization restart {0}/{1} failed".format(i + 1, num_restarts)))
                else:
                    raise e
        if len(self.optimization_runs) > initial_length:
            i = np.argmin([o.f_opt for o in self.optimization_runs[initial_length:]])
            self.optimizer_array = self.optimization_runs[initial_length + i].x_opt
        else:
            self.optimizer_array = initial_parameters
        return self.optimization_runs