def _homotopy(self, _lambda, f, x0, get_deltax, f_eval): """ Controls _lambda and the homotopy flow The lambda parameter is varied from 0 to 1. 0 corresponds to a problem easy to solve and 1 correstponds to the original problem. Uses bisection to find lambda step step size to reach 1. Inputs: _lambda: Initial value for lambda f: f(lambda) (for example gmin(lambda)) x0: initial guess (modified on output to best approximation) get_deltax and f_eval: functions passed to Newton's solver Output: (x, res, iterations, success) """ stack = [0., 1.] step = _lambda small = 1e-4 x = np.copy(x0) success = True totIter = 0 sepline = '====================================================' print(' lambda | Iterations | Residual') print(sepline) while stack: # Update parameter in nonlinear functions f(_lambda) (x, res, iterations, success1) = \ fsolve_Newton(x, get_deltax, f_eval) print('{0:15} | {1:15} | {2:15}'.format( _lambda, iterations, res), end='') totIter += iterations if success1: print('') # Save result x0[:] = x # Recover value of lambda_ from stack step = stack[-1] - _lambda _lambda = stack.pop() else: print(' <--- Backtracking') # Check if residual was big #if res > 1e-3: (not reliable) # Restore previous better guess x[:] = x0 # push _lambda into stack stack.append(_lambda) step *= .5 _lambda -= step if (_lambda < small) or (step < small): success = False break print(sepline) print('Total iterations: ', totIter) return (x, res, totIter, success)
def solve_simple(self, x0, sV): #"""Simple Newton's method""" # Docstring removed to avoid printing this all the time def get_deltax(x): (iVec, Jac) = self.get_i_Jac(x) self.errVec[:] = iVec - sV self._get_deltax() return self.deltaxVec def f_eval(x): iVec = self.get_i(x) return iVec - sV return fsolve_Newton(x0, get_deltax, f_eval)
def solve_simple(self, x0, sV): #"""Simple Newton's method""" # Docstring removed to avoid printing this all the time def get_deltax(x): (iVec, Jac) = self.get_i_Jac(x) return self._get_deltax(iVec - sV, Jac) def f_eval(x): iVec = self.get_i(x) return iVec - sV (x, res, iterations, success) = \ fsolve_Newton(x0, get_deltax, f_eval) if success: return (x, res, iterations) else: raise NoConvergenceError( 'No convergence. iter = {0} res = {1}'.format(iterations, res))
def solve_homotopy_source(self, x0, sV): """Newton's method with source stepping""" x = np.copy(x0) totIter = 0 # Here some sort of adaptive stepping should be implemented for lambda_ in np.linspace(start = .1, stop = 1., num = 10): def get_deltax(x): (iVec, Jac) = self.get_i_Jac(x) self.errVec[:] = iVec - lambda_ * sV self._get_deltax() return self.deltaxVec def f_eval(x): iVec = self.get_i(x) return iVec - lambda_ * sV (x, res, iterations) = fsolve_Newton(x, get_deltax, f_eval) print('lambda = {0}, res = {1}, iter = {2}'.format(lambda_, res, iterations)) totIter += iterations return (x, res, totIter)
def solve_homotopy_source(self, x0, sV): """Newton's method with source stepping""" x = np.copy(x0) totIter = 0 # Here some sort of adaptive stepping should be implemented for lambda_ in np.linspace(start=.1, stop=1., num=10): def get_deltax(x): (iVec, Jac) = self.get_i_Jac(x) self.errVec[:] = iVec - lambda_ * sV self._get_deltax() return self.deltaxVec def f_eval(x): iVec = self.get_i(x) return iVec - lambda_ * sV (x, res, iterations) = fsolve_Newton(x, get_deltax, f_eval) print('lambda = {0}, res = {1}, iter = {2}'.format( lambda_, res, iterations)) totIter += iterations return (x, res, totIter)