def _solve(self): """ Run the iterative solver. """ maxiter = self.options['maxiter'] atol = self.options['atol'] rtol = self.options['rtol'] iprint = self.options['iprint'] self._mpi_print_header() self._iter_count = 0 norm0, norm = self._iter_initialize() self._norm0 = norm0 self._mpi_print(self._iter_count, norm, norm / norm0) while self._iter_count < maxiter and norm > atol and norm / norm0 > rtol: with Recording(type(self).__name__, self._iter_count, self) as rec: self._single_iteration() self._iter_count += 1 self._run_apply() norm = self._iter_get_norm() # With solvers, we want to record the norm AFTER the call, but the call needs to # be wrapped in the with for stack purposes, so we locally assign norm & norm0 # into the class. rec.abs = norm if norm0 == 0: norm0 = 1 rec.rel = norm / norm0 self._mpi_print(self._iter_count, norm, norm / norm0) system = self._system() if system.comm.rank == 0 or os.environ.get('USE_PROC_FILES'): prefix = self._solver_info.prefix + self.SOLVER # Solver terminated early because a Nan in the norm doesn't satisfy the while-loop # conditionals. if np.isinf(norm) or np.isnan(norm): msg = "Solver '{}' on system '{}': residuals contain 'inf' or 'NaN' after {} " + \ "iterations." if iprint > -1: print(prefix + msg.format(self.SOLVER, system.pathname, self._iter_count)) # Raise AnalysisError if requested. if self.options['err_on_non_converge']: raise AnalysisError( msg.format(self.SOLVER, system.pathname, self._iter_count)) # Solver hit maxiter without meeting desired tolerances. elif (norm > atol and norm / norm0 > rtol): msg = "Solver '{}' on system '{}' failed to converge in {} iterations." if iprint > -1: print(prefix + msg.format(self.SOLVER, system.pathname, self._iter_count)) # Raise AnalysisError if requested. if self.options['err_on_non_converge']: raise AnalysisError( msg.format(self.SOLVER, system.pathname, self._iter_count)) # Solver converged elif iprint == 1: print(prefix + ' Converged in {} iterations'.format(self._iter_count)) elif iprint == 2: print(prefix + ' Converged')
def _run_iterator(self): """ Run the iterative solver. Returns ------- boolean Failure flag; True if failed to converge, False is successful. float absolute error. float relative error. """ maxiter = self.options['maxiter'] atol = self.options['atol'] rtol = self.options['rtol'] iprint = self.options['iprint'] self._mpi_print_header() self._iter_count = 0 norm0, norm = self._iter_initialize() self._norm0 = norm0 self._mpi_print(self._iter_count, norm, norm / norm0) while self._iter_count < maxiter and \ norm > atol and norm / norm0 > rtol: with Recording(type(self).__name__, self._iter_count, self) as rec: self._iter_execute() self._iter_count += 1 self._run_apply() norm = self._iter_get_norm() # With solvers, we want to record the norm AFTER the call, but the call needs to # be wrapped in the with for stack purposes, so we locally assign norm & norm0 # into the class. rec.abs = norm rec.rel = norm / norm0 if norm0 == 0: norm0 = 1 self._mpi_print(self._iter_count, norm, norm / norm0) fail = (np.isinf(norm) or np.isnan(norm) or (norm > atol and norm / norm0 > rtol)) if self._system.comm.rank == 0 or os.environ.get('USE_PROC_FILES'): prefix = self._solver_info.prefix + self.SOLVER if fail: if iprint > -1: msg = ' Failed to Converge in {} iterations'.format( self._iter_count) print(prefix + msg) # Raise AnalysisError if requested. if self.options['err_on_maxiter']: msg = "Solver '{}' on system '{}' failed to converge." raise AnalysisError( msg.format(self.SOLVER, self._system.pathname)) elif iprint == 1: print(prefix + ' Converged in {} iterations'.format(self._iter_count)) elif iprint == 2: print(prefix + ' Converged') return fail, norm, norm / norm0
def solve_nonlinear(self, inputs, outputs): solver = self.options['solver'] ap = self.options['ap'] if self._do_solve: self._set_ap(inputs) self._set_geo(inputs, update_jacobian=False) ap.solveFailed = False # might need to clear this out? ap.fatalFail = False solver(ap) if ap.fatalFail: if self.comm.rank == 0: print( '###############################################################' ) print('# Solve Fatal Fail. Analysis Error') print( '###############################################################' ) raise AnalysisError('ADFLOW Solver Fatal Fail') if ap.solveFailed: # the mesh was fine, but it didn't converge # if the previous iteration was already a clean restart, dont try again if self.cleanRestart: print( '###############################################################' ) print( '# This was a clean restart. Will not try another one.' ) print( '###############################################################' ) solver.resetFlow(ap) self.cleanRestart = True raise AnalysisError('ADFLOW Solver Fatal Fail') # the previous iteration restarted from another solution, so we can try again # with a re-set flowfield for the initial guess. else: if self.comm.rank == 0: print( '###############################################################' ) print('# Solve Failed, attempting a clean restart!') print( '###############################################################' ) ap.solveFailed = False ap.fatalFail = False solver.resetFlow(ap) solver(ap) if ap.solveFailed or ap.fatalFail: # we tried, but there was no saving it print( '###############################################################' ) print( '# Clean Restart failed. There is no saving this one!' ) print( '###############################################################' ) # re-set the flow for the next iteration: solver.resetFlow(ap) # set the reset flow flag self.cleanRestart = True raise AnalysisError('ADFLOW Solver Fatal Fail') # see comment for the same flag below else: self.cleanRestart = False # solve did not fail, therefore we will re-use this converged flowfield for the next iteration. # change the flag so that if the next iteration fails with current initial guess, it can retry # with a clean restart else: self.cleanRestart = False outputs['states'] = solver.getStates()
def run_component(self, command=None): """ Run this component. User should call this method from their overriden compute method. Parameters ---------- command : List Optional command. Otherwise use the command in self.options['command']. """ comp = self._comp if not command: command = comp.options['command'] comp.return_code = -12345678 if not command: raise ValueError('Empty command list') if comp.options['fail_hard']: err_class = RuntimeError else: err_class = AnalysisError return_code = None try: missing = self._check_for_files( comp.options['external_input_files']) if missing: raise err_class("The following input files are missing: %s" % sorted(missing)) return_code, error_msg = self._execute_local(command) if return_code is None: raise AnalysisError('Timed out after %s sec.' % comp.options['timeout']) elif return_code not in comp.options['allowed_return_codes']: if isinstance(comp.stderr, str): if os.path.exists(comp.stderr): with open(comp.stderr, 'r') as stderrfile: error_desc = stderrfile.read() err_fragment = "\nError Output:\n%s" % error_desc else: err_fragment = "\n[stderr %r missing]" % comp.stderr else: err_fragment = error_msg raise err_class('return_code = %d%s' % (return_code, err_fragment)) missing = self._check_for_files( comp.options['external_output_files']) if missing: raise err_class("The following output files are missing: %s" % sorted(missing)) finally: comp.return_code = -999999 if return_code is None else return_code
def _solve(self): """ Run the iterative solver. """ maxiter = self.options['maxiter'] atol = self.options['atol'] rtol = self.options['rtol'] iprint = self.options['iprint'] stall_limit = self.options['stall_limit'] stall_tol = self.options['stall_tol'] self._mpi_print_header() self._iter_count = 0 norm0, norm = self._iter_initialize() self._norm0 = norm0 self._mpi_print(self._iter_count, norm, norm / norm0) stalled = False if stall_limit > 0: stall_count = 0 stall_norm = norm0 while self._iter_count < maxiter and norm > atol and norm / norm0 > rtol and not stalled: with Recording(type(self).__name__, self._iter_count, self) as rec: self._single_iteration() self._iter_count += 1 self._run_apply() norm = self._iter_get_norm() # Save the norm values in the context manager so they can also be recorded. rec.abs = norm if norm0 == 0: norm0 = 1 rec.rel = norm / norm0 # Check if convergence is stalled. if stall_limit > 0: rel_norm = rec.rel norm_diff = np.abs(stall_norm - rel_norm) if norm_diff <= stall_tol: stall_count += 1 if stall_count >= stall_limit: stalled = True else: stall_count = 0 stall_norm = rel_norm self._mpi_print(self._iter_count, norm, norm / norm0) system = self._system() if system.comm.rank == 0 or os.environ.get('USE_PROC_FILES'): prefix = self._solver_info.prefix + self.SOLVER # Solver terminated early because a Nan in the norm doesn't satisfy the while-loop # conditionals. if np.isinf(norm) or np.isnan(norm): msg = "Solver '{}' on system '{}': residuals contain 'inf' or 'NaN' after {} " + \ "iterations." if iprint > -1: print(prefix + msg.format(self.SOLVER, system.pathname, self._iter_count)) # Raise AnalysisError if requested. if self.options['err_on_non_converge']: raise AnalysisError(msg.format(self.SOLVER, system.pathname, self._iter_count)) # Solver hit maxiter without meeting desired tolerances. # Or solver stalled. elif (norm > atol and norm / norm0 > rtol) or stalled: if stalled: msg = "Solver '{}' on system '{}' stalled after {} iterations." else: msg = "Solver '{}' on system '{}' failed to converge in {} iterations." if iprint > -1: print(prefix + msg.format(self.SOLVER, system.pathname, self._iter_count)) # Raise AnalysisError if requested. if self.options['err_on_non_converge']: raise AnalysisError(msg.format(self.SOLVER, system.pathname, self._iter_count)) # Solver converged elif iprint == 1: print(prefix + ' Converged in {} iterations'.format(self._iter_count)) elif iprint == 2: print(prefix + ' Converged')
def _solve(self): """ Run the iterative solver. """ maxiter = self.options['maxiter'] atol = self.options['atol'] rtol = self.options['rtol'] iprint = self.options['iprint'] self._mpi_print_header() self._iter_count = 0 norm0, norm = self._iter_initialize() self._norm0 = norm0 self._mpi_print(self._iter_count, norm, norm / norm0) while self._iter_count < maxiter and norm > atol and norm / norm0 > rtol: with Recording(type(self).__name__, self._iter_count, self) as rec: self._single_iteration() self._iter_count += 1 self._run_apply() norm = self._iter_get_norm() # Save the norm values in the context manager so they can also be recorded. rec.abs = norm if norm0 == 0: norm0 = 1 rec.rel = norm / norm0 self._mpi_print(self._iter_count, norm, norm / norm0) system = self._system() # flag for the print statements. we only print on root if USE_PROC_FILES is not set to True print_flag = system.comm.rank == 0 or os.environ.get('USE_PROC_FILES') prefix = self._solver_info.prefix + self.SOLVER # Solver terminated early because a Nan in the norm doesn't satisfy the while-loop # conditionals. if np.isinf(norm) or np.isnan(norm): msg = "Solver '{}' on system '{}': residuals contain 'inf' or 'NaN' after {} " + \ "iterations." if iprint > -1 and print_flag: print(prefix + msg.format(self.SOLVER, system.pathname, self._iter_count)) # Raise AnalysisError if requested. if self.options['err_on_non_converge']: raise AnalysisError(msg.format(self.SOLVER, system.pathname, self._iter_count)) # Solver hit maxiter without meeting desired tolerances. elif (norm > atol and norm / norm0 > rtol): msg = "Solver '{}' on system '{}' failed to converge in {} iterations." if iprint > -1 and print_flag: print(prefix + msg.format(self.SOLVER, system.pathname, self._iter_count)) # Raise AnalysisError if requested. if self.options['err_on_non_converge']: raise AnalysisError(msg.format(self.SOLVER, system.pathname, self._iter_count)) # Solver converged elif iprint == 1 and print_flag: print(prefix + ' Converged in {} iterations'.format(self._iter_count)) elif iprint == 2 and print_flag: print(prefix + ' Converged')
def _solve(self): """ Run the iterative solver. """ maxiter = self.options['maxiter'] atol = self.options['atol'] rtol = self.options['rtol'] iprint = self.options['iprint'] stall_limit = self.options['stall_limit'] stall_tol = self.options['stall_tol'] self._mpi_print_header() self._iter_count = 0 norm0, norm = self._iter_initialize() self._norm0 = norm0 self._mpi_print(self._iter_count, norm, norm / norm0) stalled = False stall_count = 0 if stall_limit > 0: stall_norm = norm0 while self._iter_count < maxiter and norm > atol and norm / norm0 > rtol and not stalled: with Recording(type(self).__name__, self._iter_count, self) as rec: if stall_count == 3 and not self.linesearch.options['print_bound_enforce']: self.linesearch.options['print_bound_enforce'] = True if self._system().pathname: pathname = f"{self._system().pathname}." else: pathname = "" msg = (f"Your model has stalled three times and may be violating the bounds. " f"In the future, turn on print_bound_enforce in your solver options " f"here: \n{pathname}nonlinear_solver.linesearch.options" f"['print_bound_enforce']=True. " f"\nThe bound(s) being violated now are:\n") simple_warning(msg) self._single_iteration() self.linesearch.options['print_bound_enforce'] = False else: self._single_iteration() self._iter_count += 1 self._run_apply() norm = self._iter_get_norm() # Save the norm values in the context manager so they can also be recorded. rec.abs = norm if norm0 == 0: norm0 = 1 rec.rel = norm / norm0 # Check if convergence is stalled. if stall_limit > 0: rel_norm = rec.rel norm_diff = np.abs(stall_norm - rel_norm) if norm_diff <= stall_tol: stall_count += 1 if stall_count >= stall_limit: stalled = True else: stall_count = 0 stall_norm = rel_norm self._mpi_print(self._iter_count, norm, norm / norm0) system = self._system() # flag for the print statements. we only print on root if USE_PROC_FILES is not set to True print_flag = system.comm.rank == 0 or os.environ.get('USE_PROC_FILES') prefix = self._solver_info.prefix + self.SOLVER # Solver terminated early because a Nan in the norm doesn't satisfy the while-loop # conditionals. if np.isinf(norm) or np.isnan(norm): msg = "Solver '{}' on system '{}': residuals contain 'inf' or 'NaN' after {} " + \ "iterations." if iprint > -1 and print_flag: print(prefix + msg.format(self.SOLVER, system.pathname, self._iter_count)) # Raise AnalysisError if requested. if self.options['err_on_non_converge']: raise AnalysisError(msg.format(self.SOLVER, system.pathname, self._iter_count)) # Solver hit maxiter without meeting desired tolerances. # Or solver stalled. elif (norm > atol and norm / norm0 > rtol) or stalled: if stalled: msg = "Solver '{}' on system '{}' stalled after {} iterations." else: msg = "Solver '{}' on system '{}' failed to converge in {} iterations." if iprint > -1 and print_flag: print(prefix + msg.format(self.SOLVER, system.pathname, self._iter_count)) # Raise AnalysisError if requested. if self.options['err_on_non_converge']: raise AnalysisError(msg.format(self.SOLVER, system.pathname, self._iter_count)) # Solver converged elif iprint == 1 and print_flag: print(prefix + ' Converged in {} iterations'.format(self._iter_count)) elif iprint == 2 and print_flag: print(prefix + ' Converged')
def _solve(self): """ Run the iterative solver. Overrides opendmao/solvers/solver.py to implement _is_rtol_converged """ maxiter = self.options["maxiter"] atol = self.options["atol"] iprint = self.options["iprint"] self._mpi_print_header() self._iter_count = 0 norm0, norm = self._iter_initialize() self._norm0 = norm0 self._mpi_print(self._iter_count, norm, norm / norm0) is_rtol_converged = self._is_rtol_converged(norm, norm0) while self._iter_count < maxiter and norm > atol and not is_rtol_converged: with Recording(type(self).__name__, self._iter_count, self) as rec: self._single_iteration() self._iter_count += 1 self._run_apply() norm = self._iter_get_norm() # With solvers, we want to record the norm AFTER the call, but the call needs to # be wrapped in the with for stack purposes, so we locally assign norm & norm0 # into the class. rec.abs = norm rec.rel = norm / norm0 if norm0 == 0: norm0 = 1 self._mpi_print(self._iter_count, norm, norm / norm0) is_rtol_converged = self._is_rtol_converged(norm, norm0) if version.parse(OPENMDAO_VERSION) > version.parse("2.9.1"): system = self._system() else: system = self._system if system.comm.rank == 0 or os.environ.get("USE_PROC_FILES"): prefix = self._solver_info.prefix + self.SOLVER is_rtol_converged = self._is_rtol_converged(norm, norm0) # Solver terminated early because a Nan in the norm doesn't satisfy the while-loop # conditionals. if np.isinf(norm) or np.isnan(norm): msg = ( "Solver '{}' on system '{}': residuals contain 'inf' or 'NaN' after {} " + "iterations." ) if iprint > -1: print( prefix + msg.format(self.SOLVER, system.pathname, self._iter_count) ) # Raise AnalysisError if requested. if self.options["err_on_non_converge"]: raise AnalysisError( msg.format(self.SOLVER, system.pathname, self._iter_count) ) # Solver hit maxiter without meeting desired tolerances. elif norm > atol and not is_rtol_converged: msg = "Solver '{}' on system '{}' failed to converge in {} iterations." if iprint > -1: print( prefix + msg.format(self.SOLVER, system.pathname, self._iter_count) ) # Raise AnalysisError if requested. if version.parse(OPENMDAO_VERSION) > version.parse("2.9.1"): if self.options["err_on_non_converge"]: raise AnalysisError( msg.format(self.SOLVER, system.pathname, self._iter_count) ) else: if self.options["err_on_maxiter"]: raise AnalysisError( msg.format(self.SOLVER, system.pathname, self._iter_count) ) # Solver converged elif iprint == 1: print(prefix + " Converged in {} iterations".format(self._iter_count)) elif iprint == 2: print(prefix + " Converged")
def _solve(self): # type: () -> None """ Run the iterative solver. """ maxiter = self.options['maxiter'] atol = self.options['atol'] rtol = self.options['rtol'] iprint = self.options['iprint'] self._mpi_print_header() self._iter_count = 0 norm0, norm = self._iter_initialize() self._norm0 = norm0 self._objectives = [] self._mpi_print(self._iter_count, norm, norm0) while self._iter_count < maxiter and \ (norm > atol or isnan(norm)) and (norm0 > rtol or isnan(norm0)): with Recording(type(self).__name__, self._iter_count, self) as rec: self._single_iteration() self._iter_count += 1 norm0, norm = self._iter_get_norm() # With solvers, we want to record the norm AFTER the call, but the call needs to # be wrapped in the with for stack purposes, so we locally assign norm & norm0 # into the class. rec.abs = norm rec.rel = norm0 self._mpi_print(self._iter_count, norm, norm0) self._save_history() if self.options['print_last_iteration']: self._print_last_iteration() if self.options['plot_history']: self._plot_history() self._iter_apply_new_bounds() self._untrain_surrogates() fail = (np.isinf(norm) or np.isnan(norm) or (norm > atol and norm0 > rtol)) if self._system.comm.rank == 0 or os.environ.get('USE_PROC_FILES'): prefix = self._solver_info.prefix + self.SOLVER if fail: if iprint > -1: msg = ' Failed to Converge in {} iterations'.format( self._iter_count) print(prefix + msg) # Raise AnalysisError if requested. if self.options['err_on_maxiter']: msg = "Solver '{}' on system '{}' failed to converge." raise AnalysisError( msg.format(self.SOLVER, self._system.pathname)) elif iprint == 1: print(prefix + ' Converged in {} iterations'.format(self._iter_count)) elif iprint == 2: print(prefix + ' Converged')