class NewtonSolver(Driver): ''' Wrapper for some Newton style solvers. Currently supports fsolve from scipy.optimize. ''' implements(IHasParameters, IHasEqConstraints, ISolver) # pylint: disable-msg=E1101 tolerance = Float(1.0e-8, iotype='in', desc='Global convergence tolerance') max_iteration = Int(50, iotype='in', desc='Maximum number of iterations') method = Enum('fsolve', ['fsolve'], iotype='in', desc='Solution method (currently only fsolve from scipy optimize)') def __init__(self): super(NewtonSolver, self).__init__() self.workflow = CyclicWorkflow() def check_config(self): """ This solver requires a CyclicWorkflow. """ super(NewtonSolver, self).check_config() if not isinstance(self.workflow, CyclicWorkflow): msg = "The NewtonSolver requires a CyclicWorkflow workflow." self.raise_exception(msg, RuntimeError) def execute(self): """ Pick our solver method. """ # perform an initial run self.pre_iteration() self.run_iteration() self.post_iteration() # One choice self.execute_fsolve() def execute_fsolve(self): """ Solver execution loop: Newton-Krylov. """ x0 = self.workflow.get_independents() fsolve(self._solve_callback, x0, fprime=self._jacobian_callback, maxfev=self.max_iteration, xtol=self.tolerance) def _solve_callback(self, vals): """Function hook for evaluating our equations.""" self.workflow.set_independents(vals) # run the model self.pre_iteration() self.run_iteration() self.post_iteration() self.record_case() return self.workflow.get_dependents() def _jacobian_callback(self, vals): """This function is passed to the internal solver to return the jacobian of the dependents with respect to the independents.""" return self.workflow.calc_gradient()
class FixedPointIterator(Driver): """ A simple fixed point iteration driver, which runs a workflow and passes the value from the output to the input for the next iteration. Relative change and number of iterations are used as termination criterea. This type of iteration is also known as Gauss-Seidel.""" implements(IHasParameters, IHasEqConstraints, ISolver) # pylint: disable-msg=E1101 max_iteration = Int(25, iotype='in', desc='Maximum number of ' 'iterations before termination.') tolerance = Float(1.0e-3, iotype='in', desc='Absolute convergence ' 'tolerance between iterations.') norm_order = Enum('Infinity', ['Infinity', 'Euclidean'], desc='For multivariable iteration, type of norm ' 'to use to test convergence.') def __init__(self): super(FixedPointIterator, self).__init__() self.current_iteration = 0 self.workflow = CyclicWorkflow() def execute(self): """Perform the iteration.""" # perform an initial run self.pre_iteration() self.run_iteration() self.post_iteration() self.current_iteration = 0 # Find dimension of our problem. self.workflow.initialize_residual() # Get and save the intial value of the input parameters val0 = self.workflow.get_independents() nvar = len(val0) delta = zeros(nvar) res = self.workflow.get_dependents(fixed_point=True) if self.norm_order == 'Infinity': order = float('inf') else: order = self.norm_order unconverged = True while unconverged: if self._stop: self.raise_exception('Stop requested', RunStopped) # check max iteration if self.current_iteration >= self.max_iteration-1: self._logger.warning('Max iterations exceeded without ' 'convergence.') return # Pass output to input val0 += res self.workflow.set_independents(val0) # run the workflow self.pre_iteration() self.run_iteration() self.post_iteration() self.current_iteration += 1 # check convergence delta[:] = self.workflow.get_dependents(fixed_point=True) res = delta if norm(delta, order) < self.tolerance or self.should_stop(): break # relative tolerance -- problematic around 0 #if abs( (val1-val0)/val0 ) < self.tolerance: # break def check_config(self, strict=False): """Make sure the problem is set up right.""" super(FixedPointIterator, self).check_config(strict=strict) # We need to figure our severed edges before querying. eqcons = self.get_constraints().values() n_dep = len(eqcons) n_indep = len(self.get_parameters()) if n_dep != n_indep: msg = "The number of input parameters must equal the number of" \ " output constraint equations in FixedPointIterator." self.raise_exception(msg, RuntimeError) # Check to make sure we don't have a null problem. if n_dep == 0: self.workflow._get_topsort() if len(self.workflow._severed_edges) == 0: msg = "FixedPointIterator requires a cyclic workflow, or a " \ "parameter/constraint pair." self.raise_exception(msg, RuntimeError) # Check the eq constraints to make sure they look ok. for eqcon in eqcons: if eqcon.rhs.text == '0' or eqcon.lhs.text == '0': msg = "Please specify constraints in the form 'A=B'" msg += ': %s = %s' % (eqcon.lhs.text, eqcon.rhs.text) self.raise_exception(msg, RuntimeError) if len(eqcon.get_referenced_varpaths()) > 2: msg = "Please specify constraints in the form 'A=B'" msg += ': %s = %s' % (eqcon.lhs.text, eqcon.rhs.text) self.raise_exception(msg, RuntimeError)
class FixedPointIterator(Driver): """ A simple fixed point iteration driver, which runs a workflow and passes the value from the output to the input for the next iteration. Relative change and number of iterations are used as termination criterea. This type of iteration is also known as Gauss-Seidel.""" implements(IHasParameters, IHasEqConstraints, ISolver) # pylint: disable-msg=E1101 max_iteration = Int(25, iotype='in', desc='Maximum number of ' 'iterations before termination.') tolerance = Float(1.0e-3, iotype='in', desc='Absolute convergence ' 'tolerance between iterations.') norm_order = Enum('Infinity', ['Infinity', 'Euclidean'], desc='For multivariable iteration, type of norm ' 'to use to test convergence.') def __init__(self): super(FixedPointIterator, self).__init__() self.current_iteration = 0 self.workflow = CyclicWorkflow() def execute(self): """Perform the iteration.""" # perform an initial run self.pre_iteration() self.run_iteration() self.post_iteration() self.current_iteration = 0 # Find dimension of our problem. self.workflow.initialize_residual() # Get and save the intial value of the input parameters val0 = self.workflow.get_independents() nvar = len(val0) delta = zeros(nvar) res = self.workflow.get_dependents(fixed_point=True) if self.norm_order == 'Infinity': order = float('inf') else: order = self.norm_order unconverged = True while unconverged: if self._stop: self.raise_exception('Stop requested', RunStopped) # check max iteration if self.current_iteration >= self.max_iteration - 1: self._logger.warning('Max iterations exceeded without ' 'convergence.') self.record_case() return # Pass output to input val0 += res self.workflow.set_independents(val0) # run the workflow self.pre_iteration() self.run_iteration() self.post_iteration() self.record_case() self.current_iteration += 1 # check convergence delta[:] = self.workflow.get_dependents(fixed_point=True) res = delta if norm(delta, order) < self.tolerance: break # relative tolerance -- problematic around 0 #if abs( (val1-val0)/val0 ) < self.tolerance: # break def check_config(self): """Make sure the problem is set up right.""" # We need to figure our severed edges before querying. eqcons = self.get_constraints().values() n_dep = len(eqcons) n_indep = len(self.get_parameters()) if n_dep != n_indep: msg = "The number of input parameters must equal the number of" \ " output constraint equations in FixedPointIterator." self.raise_exception(msg, RuntimeError) # Check to make sure we don't have a null problem. if n_dep == 0: self.workflow._get_topsort() if len(self.workflow._severed_edges) == 0: msg = "FixedPointIterator requires a cyclic workflow, or a " + \ "parameter/constraint pair." self.raise_exception(msg, RuntimeError) # Check the eq constraints to make sure they look ok. for eqcon in eqcons: if eqcon.rhs.text == '0' or eqcon.lhs.text == '0': msg = "Please specify constraints in the form 'A=B'" msg += ': %s = %s' % (eqcon.lhs.text, eqcon.rhs.text) self.raise_exception(msg, RuntimeError) if len(eqcon.get_referenced_varpaths()) > 2: msg = "Please specify constraints in the form 'A=B'" msg += ': %s = %s' % (eqcon.lhs.text, eqcon.rhs.text) self.raise_exception(msg, RuntimeError)
class FixedPointIterator(Driver): """ A simple fixed point iteration driver, which runs a workflow and passes the value from the output to the input for the next iteration. Relative change and number of iterations are used as termination criterea. This type of iteration is also known as Gauss-Seidel.""" implements(IHasParameters, IHasEqConstraints, ISolver) # pylint: disable-msg=E1101 max_iteration = Int(25, iotype='in', desc='Maximum number of ' 'iterations before termination.') tolerance = Float(1.0e-3, iotype='in', desc='Absolute convergence ' 'tolerance between iterations.') norm_order = Enum('Infinity', ['Infinity', 'Euclidean'], desc='For multivariable iteration, type of norm ' 'to use to test convergence.') def __init__(self): super(FixedPointIterator, self).__init__() self.history = zeros(0) self.current_iteration = 0 self.workflow = CyclicWorkflow() def execute(self): """Perform the iteration.""" # perform an initial run self.pre_iteration() self.run_iteration() self.post_iteration() self.current_iteration = 0 # Find dimension of our problem. self.workflow.initialize_residual() # Get and save the intial value of the input parameters val0 = self.workflow.get_independents() nvar = len(val0) history = zeros([self.max_iteration, nvar]) delta = zeros(nvar) history[0, :] = self.workflow.get_dependents() if self.norm_order == 'Infinity': order = float('inf') else: order = self.norm_order unconverged = True while unconverged: if self._stop: self.raise_exception('Stop requested', RunStopped) # check max iteration if self.current_iteration >= self.max_iteration-1: self.history = history[:self.current_iteration+1, :] self._logger.warning('Max iterations exceeded without ' 'convergence.') return # Pass output to input val0 += history[self.current_iteration, :] self.workflow.set_independents(val0) # run the workflow self.pre_iteration() self.run_iteration() self.post_iteration() self.record_case() self.current_iteration += 1 # check convergence delta[:] = self.workflow.get_dependents() history[self.current_iteration] = delta if norm(delta, order) < self.tolerance: break # relative tolerance -- problematic around 0 #if abs( (val1-val0)/val0 ) < self.tolerance: # break self.history = history[:self.current_iteration+1, :] def check_config(self): """Make sure the problem is set up right.""" # We need to figure our severed edges before querying. self.workflow._get_topsort() n_dep = len(self.workflow.get_dependents()) n_indep = len(self.workflow.get_independents()) if n_dep == 0: msg = "FixedPointIterator requires a constraint equation or a cyclic workflow." self.raise_exception(msg, RuntimeError) if n_indep == 0: msg = "FixedPointIterator requires an input parameter or a cyclic workflow." self.raise_exception(msg, RuntimeError) if n_dep != n_indep: msg = "The number of input parameters must equal the number of" \ " output constraint equations in FixedPointIterator." self.raise_exception(msg, RuntimeError)