def fit(self): """ Run problem with DFO. """ if self.minimizer == 'dfogn': self._soln = dfogn.solve(self.problem.eval_r, self._pinit) elif self.minimizer == 'dfols': self._soln = dfols.solve(self.problem.eval_r, self._pinit) self._popt = self._soln.x self._status = self._soln.flag
def fit(self): """ Run problem with DFO-GN. """ self.success = False self._soln = dfogn.solve(self._prediction_error, self._pinit) if (self._soln.flag == 0): self.success = True self._popt = self._soln.x
def runTest(self): # n, m = 2, 2 x0 = np.array([-1.2, 1.0]) soln = dfogn.solve(rosenbrock, x0) self.assertTrue( array_compare(soln.x, np.array([1.0, 1.0]), thresh=1e-4), "Wrong xmin") self.assertTrue( array_compare(soln.resid, rosenbrock(soln.x), thresh=1e-10), "Wrong resid") self.assertTrue( array_compare(soln.jacobian, rosenbrock_jacobian(soln.x), thresh=2e-2), "Wrong Jacobian") self.assertTrue(abs(soln.f) < 1e-10, "Wrong fmin")
def runTest(self): n, m = 2, 5 np.random.seed(0) # (fixing random seed) A = np.random.rand(m, n) b = np.random.rand(m) objfun = lambda x: np.dot(A, x) - b xmin = np.linalg.lstsq(A, b)[0] fmin = np.dot(objfun(xmin), objfun(xmin)) x0 = np.zeros((n, )) soln = dfogn.solve(objfun, x0) self.assertTrue(array_compare(soln.x, xmin, thresh=1e-2), "Wrong xmin") self.assertTrue( array_compare(soln.resid, objfun(soln.x), thresh=1e-10), "Wrong resid") self.assertTrue(array_compare(soln.jacobian, A, thresh=1e-2), "Wrong Jacobian") self.assertTrue(abs(soln.f - fmin) < 1e-4, "Wrong fmin")
def runTest(self): # n, m = 2, 2 x0 = np.array([-1.2, 0.7]) # standard start point too close to upper bounds lower = np.array([-2.0, -2.0]) upper = np.array([0.9, 0.9]) xmin = np.array([0.9, 0.81]) # approximate fmin = np.dot(rosenbrock(xmin), rosenbrock(xmin)) soln = dfogn.solve(rosenbrock, x0, lower=lower, upper=upper) print(soln.x) self.assertTrue(array_compare(soln.x, xmin, thresh=1e-2), "Wrong xmin") self.assertTrue( array_compare(soln.resid, rosenbrock(soln.x), thresh=1e-10), "Wrong resid") self.assertTrue( array_compare(soln.jacobian, rosenbrock_jacobian(soln.x), thresh=1e-2), "Wrong Jacobian") self.assertTrue(abs(soln.f - fmin) < 1e-4, "Wrong fmin")
def do_parameter_fit(x0, datas, lsq_solver, model_solver, LARGE_V=50): """ Function to fit parameters given a starting point and datas. Choice of which optimisation algorithm and which model to use. """ def prediction_error(x, show_plots=True, show_stars=True, save_plot_data=False): """ Compare model to data and return array of differences """ # Rescale x x = lower + (upper - lower) * x # Initial SOCs q0s = np.append([1], x[4:]) # Prepare dict modelVs = {} for i, name in enumerate(datas.keys()): data = datas[name] # Make dict of fitting parameters from x pars = { "epsnmax": x[0], "epssmax": x[1], "epspmax": x[0], "cmax": 5.65, "jref_n": x[2], "jref_p": x[2] / 10, "qinit": q0s[i], } # Shape preserving interpolation of current: do the hard work offline interpclass = interp.PchipInterpolator(data["time"], data["current"]) def Icircuit(t): return interpclass(t) # Load parameters pars = Parameters(fit=pars, Icircuit=Icircuit, Ibar=np.max(Icircuit(data["time"]))) # Nondimensionalise time t = data["time"] / pars.scales.time # Run model model = model_solver(t, pars, grid, Vonly=True) model.dimensionalise(pars, grid) # Take away resistance of the wires model.Vcircuit -= x[3] * data["current"][:, np.newaxis] # Remove NaNs model.Vcircuit[np.isnan(model.Vcircuit)] = LARGE_V # Store voltages modelVs[name] = model.Vcircuit # Plot data vs model if show_plots: plt.ion() fig = plt.figure(1) plt.clf() for i, name in enumerate(datas.keys()): plt.plot( datas[name]["time"], datas[name]["voltage"], "o", markersize=1, color="C" + str(i), ) plt.plot(datas[name]["time"], modelVs[name], color="C" + str(i), label=name) # plt.title('params={}'.format(x)) plt.xlabel("Time [h]") plt.ylabel("Voltage [V]") legend = plt.legend() fig.canvas.flush_events() time.sleep(0.01) # Make vector of differences (including weights) diffs = np.concatenate([ (data["voltage"] - modelVs[name][:, 0]) * data["weights"] for name, data in datas.items() ]) # Show progress # if show_stars: # plt.figure(2) # plt.plot(x, np.dot(diffs, diffs), 'rx') # plt.pause(.01) # Save plot data if save_plot_data: # Set linestyles linestyles = { "3A": "", "2.5A": "", "2A": "", "1.5A": "", "1A": "", "0.5A": "", } with open( "out/plot_calls/fits/{}_{}.txt".format( lsq_solver, model_solver.__name__), "w", ) as fit_plot_calls: # Save data and model from each current for i, name in enumerate(datas.keys()): save_data( "fits/{}/{}/{}_model".format(lsq_solver, model_solver.__name__, name), datas[name]["time"], modelVs[name], fit_plot_calls, linestyles[name], n_coarse_points=100, ) save_data( "fits/{}/{}/{}_data".format(lsq_solver, model_solver.__name__, name), datas[name]["time"], datas[name]["voltage"], fit_plot_calls, linestyles[name], n_coarse_points=100, ) # Add legend (two commas to ignore the data entries) fit_plot_calls.write( ("\\legend{{{!s}" + ", ,{!s}" * (len(datas.keys()) - 1) + "}}\n").format(*tuple(datas.keys()))) return diffs # Compute grid (doesn't depend on base parameters) grid = Grid(10) fit_currents = datas.keys() # Set the bounds lower = np.concatenate( [np.array([0.0, 0.0, 0.01, 0.0]), np.zeros(len(datas) - 1)]) upper = np.concatenate( [np.array([1.0, 1.0, 1.0, 1.0]), np.ones(len(datas) - 1)]) # Rescale x0 so that all fitting parameters go from 0 to 1 x0 = (x0 - lower) / (upper - lower) # errs = np.array([]) # js = np.linspace(0.01,1,10) # for j in js: # diffs = prediction_error(j, show_plots=True, show_stars=False) # errs = np.append(errs, np.dot(diffs, diffs)) # plt.figure(2) # plt.plot(js, errs) # plt.pause(0.01) # Do curve fitting print("Fit using {} on the {} model".format(lsq_solver, model_solver.__name__)) print("-" * 60) if lsq_solver in ["dfogn", "dfols"]: # Set logging to INFO to view progress logging.basicConfig(level=logging.INFO, format="%(message)s") # Call and time DFO-GN or DFO-LS start = time.time() if lsq_solver == "dfogn": soln = dfogn.solve( prediction_error, x0, lower=np.zeros(len(x0)), upper=np.ones(len(x0)), rhoend=1e-5, ) elif lsq_solver == "dfols": soln = dfols.solve( prediction_error, x0, bounds=(np.zeros(len(x0)), np.ones(len(x0))), rhoend=1e-5, ) soln_time = time.time() - start # Scale x back to original scale x = lower + (upper - lower) * soln.x # Display output print(" *** DFO-GN results *** ") print("Solution xmin = %s" % str(x)) print("Objective value f(xmin) = %.10g" % soln.f) print("Needed %g objective evaluations" % soln.nf) print("Exit flag = %g" % soln.flag) print(soln.msg) # Save solution parameters # save_output = {'y': True, 'n': False}[input('Save fitted params? (y/n): ')] # if save_output: # filename = "out/fits/dfogn_{}.txt".format(model_solver.__name__) # np.savetxt(filename, lower+(upper-lower)*soln.x) return (x, soln.f, soln_time) elif lsq_solver == "scipy": # Call and time scipy least squares start = time.time() soln = opt.least_squares( prediction_error, x0, bounds=(np.zeros(len(x0)), np.ones(len(x0))), method="trf", jac="2-point", diff_step=1e-5, ftol=1e-4, verbose=2, ) soln_time = time.time() - start # Scale x back to original scale x = lower + (upper - lower) * soln.x # Display output print(" *** SciPy results *** ") print("Solution xmin = %s" % str(x)) print("Objective value f(xmin) = %.10g" % (soln.cost * 2)) print("Needed %g objective evaluations" % soln.nfev) print("Exit flag = %g" % soln.status) print(soln.message) # Save solution parameters # save_output = {'y': True, 'n': False}[input('Save fitted params? (y/n): ')] # if save_output: # filename = "out/fits/scipy_{}.txt".format(model_solver.__name__) # np.savetxt(filename, x) return (x, soln.cost * 2, soln_time) elif lsq_solver is None: # Do nothing diffs = prediction_error(x0) return (x0, np.dot(diffs, diffs), 0) # save plots (hacky!) prediction_error(x, save_plot_data=True)
def rosenbrock_noisy(x): return rosenbrock(x) * (1.0 + 1e-2 * np.random.normal(size=(2, ))) # Define the starting point x0 = np.array([-1.2, 1.0]) np.random.seed(0) print("Demonstrate noise in function evaluation:") for i in range(5): print("objfun(x0) = %s" % str(rosenbrock_noisy(x0))) print("") soln = dfogn.solve(rosenbrock_noisy, x0) # Display output print(" *** DFO-GN results *** ") print("Solution xmin = %s" % str(soln.x)) print("Objective value f(xmin) = %.10g" % soln.f) print("Needed %g objective evaluations" % soln.nf) print("Residual vector = %s" % str(soln.resid)) print("Approximate Jacobian = %s" % str(soln.jacobian)) print("Exit flag = %g" % soln.flag) print(soln.msg) # Compare with a derivative-based solver import scipy.optimize as opt soln = opt.least_squares(rosenbrock_noisy, x0)
# http://support.sas.com/documentation/cdl/en/imlug/66112/HTML/default/viewer.htm#imlug_genstatexpls_sect004.htm from __future__ import print_function import math import numpy as np import dfogn # Want to solve: # x1 + x2 - x1*x2 + 2 = 0 # x1 * exp(-x2) - 1 = 0 def nonlinear_system(x): return np.array( [x[0] + x[1] - x[0] * x[1] + 2, x[0] * math.exp(-x[1]) - 1.0]) # Warning: if there are multiple solutions, which one # DFO-GN returns will likely depend on x0! x0 = np.array([0.1, -2.0]) soln = dfogn.solve(nonlinear_system, x0) # Display output print(" *** DFO-GN results *** ") print("Solution xmin = %s" % str(soln.x)) print("Objective value f(xmin) = %.10g" % soln.f) print("Needed %g objective evaluations" % soln.nf) print("Residual vector = %s" % str(soln.resid)) print("Exit flag = %g" % soln.flag) print(soln.msg)
# DFO-GN example: minimize the Rosenbrock function (with bounds) from __future__ import print_function import numpy as np import dfogn # Define the objective function def rosenbrock(x): return np.array([10.0 * (x[1] - x[0] ** 2), 1.0 - x[0]]) # Define the starting point x0 = np.array([-1.2, 1.0]) # Define optional bound constraints (a <= x <= b) a = np.array([-10.0, -10.0]) b = np.array([0.9, 0.85]) soln = dfogn.solve(rosenbrock, x0, lower=a, upper=b) # Display output print(" *** DFO-GN results *** ") print("Solution xmin = %s" % str(soln.x)) print("Objective value f(xmin) = %.10g" % soln.f) print("Needed %g objective evaluations" % soln.nf) print("Residual vector = %s" % str(soln.resid)) print("Approximate Jacobian = %s" % str(soln.jacobian)) print("Exit flag = %g" % soln.flag) print(soln.msg)
# DFO-GN example: minimize the Rosenbrock function from __future__ import print_function import numpy as np import dfogn # Define the objective function def rosenbrock(x): return np.array([10.0 * (x[1] - x[0]**2), 1.0 - x[0]]) # Define the starting point x0 = np.array([-1.2, 1.0]) # For optional extra output details # import logging # logging.basicConfig(level=logging.INFO, format='%(message)s') soln = dfogn.solve(rosenbrock, x0) # Display output print(" *** DFO-GN results *** ") print("Solution xmin = %s" % str(soln.x)) print("Objective value f(xmin) = %.10g" % soln.f) print("Needed %g objective evaluations" % soln.nf) print("Residual vector = %s" % str(soln.resid)) print("Approximate Jacobian = %s" % str(soln.jacobian)) print("Exit flag = %g" % soln.flag) print(soln.msg)
# Data fitting example # https://uk.mathworks.com/help/optim/ug/lsqcurvefit.html#examples from __future__ import print_function import numpy as np import dfogn tdata = np.array([0.9, 1.5, 13.8, 19.8, 24.1, 28.2, 35.2, 60.3, 74.6, 81.3]) ydata = np.array( [455.2, 428.6, 124.1, 67.3, 43.2, 28.1, 13.1, -0.4, -1.3, -1.5]) def prediction_error(x): return ydata - x[0] * np.exp(x[1] * tdata) x0 = np.array([100.0, -1.0]) upper = np.array([1e20, 0.0]) soln = dfogn.solve(prediction_error, x0, upper=upper) # Display output print(" *** DFO-GN results *** ") print("Solution xmin = %s" % str(soln.x)) print("Objective value f(xmin) = %.10g" % soln.f) print("Needed %g objective evaluations" % soln.nf) print("Exit flag = %g" % soln.flag) print(soln.msg)