def _solve_nonlinear(self): """ Compute outputs. The model is assumed to be in a scaled state. """ if self._nonlinear_solver is not None: with Recording(self.pathname + '._solve_nonlinear', self.iter_count, self): self._nonlinear_solver.solve() else: with self._unscaled_context(outputs=[self._outputs]): with Recording(self.pathname + '._solve_nonlinear', self.iter_count, self): with self._call_user_function('solve_nonlinear'): args = [self._inputs, self._outputs] if self._discrete_inputs or self._discrete_outputs: args += [self._discrete_inputs, self._discrete_outputs] if self._run_root_only(): if self.comm.rank == 0: self.solve_nonlinear(*args) self.comm.bcast([self._outputs.asarray(), self._discrete_outputs], root=0) else: new_res, new_disc_outs = self.comm.bcast(None, root=0) self._outputs.set_val(new_res) if new_disc_outs: for name, val in new_disc_outs.items(): self._discrete_outputs[name] = val else: self.solve_nonlinear(*args)
def _solve_nonlinear(self): """ Compute outputs. The model is assumed to be in a scaled state. Returns ------- boolean Failure flag; True if failed to converge, False is successful. float absolute error. float relative error. """ # Reconfigure if needed. super(ImplicitComponent, self)._solve_nonlinear() if self._nonlinear_solver is not None: with Recording(self.pathname + '._solve_nonlinear', self.iter_count, self): result = self._nonlinear_solver.solve() return result else: with self._unscaled_context(outputs=[self._outputs]): with Recording(self.pathname + '._solve_nonlinear', self.iter_count, self): result = self.solve_nonlinear(self._inputs, self._outputs) if result is None: return False, 0., 0. elif type(result) is bool: return result, 0., 0. else: return result
def _solve_nonlinear(self): """ Compute outputs. The model is assumed to be in a scaled state. """ # Reconfigure if needed. super(ImplicitComponent, self)._solve_nonlinear() self._inputs.read_only = True try: if self._nonlinear_solver is not None: with Recording(self.pathname + '._solve_nonlinear', self.iter_count, self): self._nonlinear_solver.solve() else: with self._unscaled_context(outputs=[self._outputs]): with Recording(self.pathname + '._solve_nonlinear', self.iter_count, self): if self._discrete_inputs or self._discrete_outputs: self.solve_nonlinear(self._inputs, self._outputs, self._discrete_inputs, self._discrete_outputs) else: self.solve_nonlinear(self._inputs, self._outputs) finally: self._inputs.read_only = False
def solve(self): """ Run the solver. Returns ------- boolean Failure flag; True if failed to converge, False is successful. float absolute error. float relative error. """ system = self._system with Recording('NLRunOnce', 0, self) as rec: # If this is a parallel group, transfer all at once then run each subsystem. if len(system._subsystems_myproc) != len(system._subsystems_allprocs): system._transfer('nonlinear', 'fwd') for subsys in system._subsystems_myproc: subsys._solve_nonlinear() system._check_reconf_update() # If this is not a parallel group, transfer for each subsystem just prior to running it. else: for isub, subsys in enumerate(system._subsystems_myproc): system._transfer('nonlinear', 'fwd', isub) subsys._solve_nonlinear() system._check_reconf_update() rec.abs = 0.0 rec.rel = 0.0 return False, 0.0, 0.0
def _iter_execute(self): """ Perform the operations in the iteration loop. """ system = self._system self._solver_info.append_subsolver() system._transfer('nonlinear', 'fwd') with Recording('NonlinearBlockJac', 0, self) as rec: # If this is a parallel group, check for analysis errors and reraise. if len(system._subsystems_myproc) != len( system._subsystems_allprocs): with multi_proc_fail_check(system.comm): for subsys in system._subsystems_myproc: subsys._solve_nonlinear() else: for subsys in system._subsystems_myproc: subsys._solve_nonlinear() system._check_reconf_update() rec.abs = 0.0 rec.rel = 0.0 self._solver_info.pop()
def _apply_nonlinear(self): """ Compute residuals. The model is assumed to be in a scaled state. """ outputs = self._outputs residuals = self._residuals with Recording(self.pathname + '._apply_nonlinear', self.iter_count, self): with self._unscaled_context(outputs=[outputs], residuals=[residuals]): residuals.set_vec(outputs) # Sign of the residual is minus the sign of the output vector. residuals *= -1.0 self._inputs.read_only = True try: if self._discrete_inputs or self._discrete_outputs: self.compute(self._inputs, self._outputs, self._discrete_inputs, self._discrete_outputs) else: self.compute(self._inputs, self._outputs) finally: self._inputs.read_only = False residuals += outputs outputs -= residuals
def _solve(self): """ Run the iterative solver. """ self._iter_count = 0 system = self._system u = system._outputs du = system._vectors['output']['linear'] self._run_apply() norm0 = self._iter_get_norm() if norm0 == 0.0: norm0 = 1.0 self._norm0 = norm0 u += du with Recording('BoundsEnforceLS', self._iter_count, self) as rec: self._enforce_bounds(step=du, alpha=1.0) 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 self._mpi_print(self._iter_count, norm, norm / norm0)
def _iter_initialize(self): """ Perform any necessary pre-processing operations. Returns ------- float initial error. float error at the first iteration. """ system = self._system # Execute guess_nonlinear if specified. system._guess_nonlinear() with Recording('Newton_subsolve', 0, self): if self.options['solve_subsystems'] and \ (self._iter_count <= self.options['max_sub_solves']): self._solver_info.append_solver() # should call the subsystems solve before computing the first residual for isub, subsys in enumerate(system._subsystems_myproc): system._transfer('nonlinear', 'fwd', isub) subsys._solve_nonlinear() system._check_reconf_update() self._solver_info.pop() self._run_apply() norm = self._iter_get_norm() norm0 = norm if norm != 0.0 else 1.0 return norm0, norm
def solve(self): """ Run the solver. """ system = self._system with Recording('NLRunOnce', 0, self) as rec: # If this is a parallel group, transfer all at once then run each subsystem. if len(system._subsystems_myproc) != len( system._subsystems_allprocs): system._transfer('nonlinear', 'fwd') with multi_proc_fail_check(system.comm): for subsys in system._subsystems_myproc: subsys._solve_nonlinear() system._check_reconf_update() # If this is not a parallel group, transfer for each subsystem just prior to running it. else: for isub, subsys in enumerate(system._subsystems_myproc): system._transfer('nonlinear', 'fwd', isub) subsys._solve_nonlinear() system._check_reconf_update() rec.abs = 0.0 rec.rel = 0.0
def _iter_initialize(self): """ Perform any necessary pre-processing operations. Returns ------- float Initial relative error in the user-specified residuals. float Initial absolute error in the user-specified residuals. """ system = self._system if self.options['debug_print']: self._err_cache['inputs'] = self._system._inputs._copy_views() self._err_cache['outputs'] = self._system._outputs._copy_views() # Convert local storage if we are under complex step. if system.under_complex_step: if np.iscomplex(self.xm[0]): self.Gm = self.Gm.astype(np.complex) self.xm = self.xm.astype(np.complex) self.fxm = self.fxm.astype(np.complex) elif np.iscomplex(self.xm[0]): self.Gm = self.Gm.real self.xm = self.xm.real self.fxm = self.fxm.real self._converge_failures = 0 self._computed_jacobians = 0 # Execute guess_nonlinear if specified. system._guess_nonlinear() # When under a complex step from higher in the hierarchy, sometimes the step is too small # to trigger reconvergence, so nudge the outputs slightly so that we always get at least # one iteration of Broyden. if system.under_complex_step and self.options['cs_reconverge']: system._outputs._data += np.linalg.norm( self._system._outputs._data) * 1e-10 # Start with initial states. self.xm = self.get_states() with Recording('Broyden', 0, self): self._solver_info.append_solver() # should call the subsystems solve before computing the first residual for isub, subsys in enumerate(system._subsystems_myproc): system._transfer('nonlinear', 'fwd', isub) subsys._solve_nonlinear() system._check_reconf_update() self._solver_info.pop() self._run_apply() norm = self._iter_get_norm() norm0 = norm if norm != 0.0 else 1.0 return norm0, norm
def _solve_nonlinear(self): """ Compute outputs. The model is assumed to be in a scaled state. Returns ------- boolean Failure flag; True if failed to converge, False is successful. float absolute error. float relative error. """ super(ExplicitComponent, self)._solve_nonlinear() with Recording(self.pathname + '._solve_nonlinear', self.iter_count, self): with self._unscaled_context(outputs=[self._outputs], residuals=[self._residuals]): self._residuals.set_const(0.0) self._inputs.read_only = True try: failed = self.compute(self._inputs, self._outputs) finally: self._inputs.read_only = False return bool(failed), 0., 0.
def _apply_nonlinear(self): """ Compute residuals. The model is assumed to be in a scaled state. """ outputs = self._outputs residuals = self._residuals with Recording(self.pathname + '._apply_nonlinear', self.iter_count, self): with self._unscaled_context(outputs=[outputs], residuals=[residuals]): residuals.set_vec(outputs) # Sign of the residual is minus the sign of the output vector. residuals *= -1.0 self._inputs.read_only = True try: self.compute(self._inputs, outputs) finally: self._inputs.read_only = False # Restore any complex views if under complex step. if outputs._vector_info._under_complex_step: outputs._remove_complex_views() residuals._remove_complex_views() residuals += outputs outputs -= residuals
def _apply_nonlinear(self): """ Compute residuals. The model is assumed to be in a scaled state. """ with self._unscaled_context(outputs=[self._outputs], residuals=[self._residuals]): with Recording(self.pathname + '._apply_nonlinear', self.iter_count, self): self.apply_nonlinear(self._inputs, self._outputs, self._residuals)
def _solve(self): """ Run the iterative solver. """ self._iter_count = 0 system = self._system() u = system._outputs du = system._vectors['output']['linear'] if not system._has_bounds: u += du return self._run_apply() norm0 = self._iter_get_norm() if norm0 == 0.0: norm0 = 1.0 self._norm0 = norm0 u += du with Recording('BoundsEnforceLS', self._iter_count, self) as rec: self._enforce_bounds(step=du, alpha=1.0) 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 rec.rel = norm / norm0 self._mpi_print(self._iter_count, norm, norm / norm0)
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'] c = self.options['c'] self._iter_count = 0 norm0, norm = self._iter_initialize() self._mpi_print(self._iter_count, norm, norm / norm0) # Further backtracking if needed. # The Armijo-Goldstein is basically a slope comparison --actual vs predicted. # We don't have an actual gradient, but we have the Newton vector that should # take us to zero, and our "runs" are the same, and we can just compare the # "rise". while self._iter_count < maxiter and (((norm0 - norm) < c * self.alpha * norm0) or self._analysis_error_raised): with Recording('ArmijoGoldsteinLS', self._iter_count, self) as rec: self._iter_execute() self._iter_count += 1 try: self._run_apply() norm = self._iter_get_norm() # With solvers, we want to report the norm AFTER # the iter_execute call, but the i_e call needs to # be wrapped in the with for stack purposes. rec.abs = norm rec.rel = norm / norm0 except AnalysisError as err: if self.options['retry_on_analysis_error']: self._analysis_error_raised = True rec.abs = np.nan rec.rel = np.nan else: exc = sys.exc_info() reraise(*exc) self._mpi_print(self._iter_count, norm, norm / norm0) self._iter_count += 1 fail = (np.isinf(norm) or np.isnan(norm) or (norm > atol and norm / norm0 > rtol)) return fail, norm, norm / norm0
def _solve_nonlinear(self): """ Compute outputs. The model is assumed to be in a scaled state. """ with Recording(self.pathname + '._solve_nonlinear', self.iter_count, self): with self._unscaled_context(outputs=[self._outputs], residuals=[self._residuals]): self._residuals.set_val(0.0) self._compute_wrapper()
def _apply_linear(self, vec_names, rel_systems, mode, scope_out=None, scope_in=None): """ Compute jac-vec product. The model is assumed to be in a scaled state. Parameters ---------- vec_names : [str, ...] list of names of the right-hand-side vectors. rel_systems : set of str Set of names of relevant systems based on the current linear solve. mode : str 'fwd' or 'rev'. scope_out : set or None Set of absolute output names in the scope of this mat-vec product. If None, all are in the scope. scope_in : set or None Set of absolute input names in the scope of this mat-vec product. If None, all are in the scope. """ for vec_name in vec_names: if vec_name not in self._rel_vec_names: continue with self._matvec_context(vec_name, scope_out, scope_in, mode) as vecs: d_inputs, d_outputs, d_residuals = vecs # Jacobian and vectors are all scaled, unitless with self.jacobian_context() as J: J._apply(d_inputs, d_outputs, d_residuals, mode) # if we're not matrix free, we can skip the bottom of # this loop because apply_linear does nothing. if not self.matrix_free: continue # Jacobian and vectors are all unscaled, dimensional with self._unscaled_context( outputs=[self._outputs, d_outputs], residuals=[d_residuals]): with Recording(self.pathname + '._apply_linear', self.iter_count, self): if d_inputs._ncol > 1: if self.has_apply_multi_linear: self.apply_multi_linear(self._inputs, self._outputs, d_inputs, d_residuals, mode) else: for i in range(d_inputs._ncol): # need to make the multivecs look like regular single vecs # since the component doesn't know about multivecs. d_inputs._icol = i d_outputs._icol = i d_residuals._icol = i self.apply_linear(self._inputs, self._outputs, d_inputs, d_outputs, d_residuals, mode) d_inputs._icol = None d_outputs._icol = None d_residuals._icol = None else: self.apply_linear(self._inputs, self._outputs, d_inputs, d_outputs, d_residuals, mode)
def _solve(self): """ Run the iterative solver. """ options = self.options maxiter = options['maxiter'] rho = options['rho'] method = options['method'] system = self._system u = system._outputs du = system._vectors['output']['linear'] # Newton step self._iter_count = 0 phi = self._iter_initialize() phi0 = self._phi0 # Further backtracking if needed. while (self._iter_count < maxiter and (not self._stopping_criteria(phi, method) or self._analysis_error_raised)): with Recording('ArmijoGoldsteinLS', self._iter_count, self) as rec: if self._iter_count > 0: alpha_old = self.alpha self._update_step_length_parameter(rho) # Moving on the line search with the difference of the old and new step length. u.add_scal_vec(self.alpha - alpha_old, du) cache = self._solver_info.save_cache() try: self._single_iteration() self._iter_count += 1 phi = self._line_search_objective() # With solvers, we want to report the norm AFTER # the iter_execute call, but the i_e call needs to # be wrapped in the with for stack purposes. rec.abs = phi rec.rel = phi / phi0 except AnalysisError as err: self._solver_info.restore_cache(cache) self._iter_count += 1 if self.options['retry_on_analysis_error']: self._analysis_error_raised = True rec.abs = np.nan rec.rel = np.nan else: exc = sys.exc_info() reraise(*exc) # self._mpi_print(self._iter_count, norm, norm / norm0) self._mpi_print(self._iter_count, phi, self.alpha)
def _solve(self): """ Run the iterative solver. """ maxiter = self.options['maxiter'] atol = self.options['atol'] rtol = self.options['rtol'] c = self.options['c'] system = self._system u = system._outputs du = system._vectors['output']['linear'] self._iter_count = 0 norm0, norm = self._iter_initialize() self._norm0 = norm0 # Further backtracking if needed. while (self._iter_count < maxiter and ((norm > norm0 - c * self.alpha * norm0) or self._analysis_error_raised)): with Recording('ArmijoGoldsteinLS', self._iter_count, self) as rec: u.add_scal_vec(-self.alpha, du) if self._iter_count > 0: self.alpha *= self.options['rho'] u.add_scal_vec(self.alpha, du) cache = self._solver_info.save_cache() try: self._single_iteration() self._iter_count += 1 norm = self._iter_get_norm() # With solvers, we want to report the norm AFTER # the iter_execute call, but the i_e call needs to # be wrapped in the with for stack purposes. rec.abs = norm rec.rel = norm / norm0 except AnalysisError as err: self._solver_info.restore_cache(cache) self._iter_count += 1 if self.options['retry_on_analysis_error']: self._analysis_error_raised = True rec.abs = np.nan rec.rel = np.nan else: exc = sys.exc_info() reraise(*exc) # self._mpi_print(self._iter_count, norm, norm / norm0) self._mpi_print(self._iter_count, norm, self.alpha)
def _solve_linear(self, vec_names, mode, rel_systems): """ Apply inverse jac product. The model is assumed to be in a scaled state. Parameters ---------- vec_names : [str, ...] list of names of the right-hand-side vectors. mode : str 'fwd' or 'rev'. rel_systems : set of str Set of names of relevant systems based on the current linear solve. Returns ------- boolean Failure flag; True if failed to converge, False is successful. float absolute error. float relative error. """ with Recording(self.pathname + '._solve_linear', self.iter_count, self): for vec_name in vec_names: if vec_name in self._rel_vec_names: d_outputs = self._vectors['output'][vec_name] d_residuals = self._vectors['residual'][vec_name] if mode == 'fwd': if self._has_resid_scaling: with self._unscaled_context(outputs=[d_outputs], residuals=[ d_residuals ]): d_outputs.set_vec(d_residuals) else: d_outputs.set_vec(d_residuals) # ExplicitComponent jacobian defined with -1 on diagonal. d_outputs *= -1.0 else: # rev if self._has_resid_scaling: with self._unscaled_context(outputs=[d_outputs], residuals=[ d_residuals ]): d_residuals.set_vec(d_outputs) else: d_residuals.set_vec(d_outputs) # ExplicitComponent jacobian defined with -1 on diagonal. d_residuals *= -1.0 return False, 0., 0.
def _solve_nonlinear(self): """ Compute outputs. The model is assumed to be in a scaled state. """ if self._nonlinear_solver is not None: with Recording(self.pathname + '._solve_nonlinear', self.iter_count, self): self._nonlinear_solver.solve() else: with self._unscaled_context(outputs=[self._outputs]): with Recording(self.pathname + '._solve_nonlinear', self.iter_count, self): with self._call_user_function('solve_nonlinear'): if self._discrete_inputs or self._discrete_outputs: self.solve_nonlinear(self._inputs, self._outputs, self._discrete_inputs, self._discrete_outputs) else: self.solve_nonlinear(self._inputs, self._outputs)
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 rec.rel = norm / norm0 if norm0 == 0: norm0 = 1 self._mpi_print(self._iter_count, norm, norm / norm0) if self._system.comm.rank == 0 or os.environ.get('USE_PROC_FILES'): prefix = self._solver_info.prefix + self.SOLVER if np.isinf(norm) or np.isnan(norm) or (norm > atol and norm / norm0 > rtol): if iprint > -1: msg = "Solver '{}' on system '{}' failed to converge in {} iterations." print(prefix + msg.format( self.SOLVER, self._system.pathname, self._iter_count)) # Raise AnalysisError if requested. if self.options['err_on_maxiter']: msg = "Solver '{}' on system '{}' failed to converge in {} iterations." raise AnalysisError( msg.format(self.SOLVER, self._system.pathname, self._iter_count)) 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. """ options = self.options maxiter = options['maxiter'] rho = options['rho'] method = options['method'] system = self._system() u = system._outputs du = system._vectors['output']['linear'] # Newton step self._iter_count = 0 phi = self._iter_initialize() phi0 = self._phi0 # Further backtracking if needed. while (self._iter_count < maxiter and (not self._stopping_criteria(phi, method) or self._analysis_error_raised)): with Recording('ArmijoGoldsteinLS', self._iter_count, self) as rec: if self._iter_count > 0: alpha_old = self.alpha self._update_step_length_parameter(rho) # Moving on the line search with the difference of the old and new step length. u.add_scal_vec(self.alpha - alpha_old, du) cache = self._solver_info.save_cache() try: self._single_iteration() self._iter_count += 1 phi = self._line_search_objective() # Save the norm values in the context manager so they can also be recorded. rec.abs = phi rec.rel = phi / phi0 except AnalysisError as err: self._solver_info.restore_cache(cache) self._iter_count += 1 if self.options['retry_on_analysis_error']: self._analysis_error_raised = True rec.abs = np.nan rec.rel = np.nan else: raise err # self._mpi_print(self._iter_count, norm, norm / norm0) self._mpi_print(self._iter_count, phi, self.alpha)
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. """ self._iter_count = 0 system = self._system u = system._outputs du = system._vectors['output']['linear'] self._run_apply() norm0 = self._iter_get_norm() if norm0 == 0.0: norm0 = 1.0 self._norm0 = norm0 u += du if self.options['print_bound_enforce']: _print_violations(u, system._lower_bounds, system._upper_bounds) with Recording('BoundsEnforceLS', self._iter_count, self) as rec: if self.options['bound_enforcement'] == 'vector': u._enforce_bounds_vector(du, 1.0, system._lower_bounds, system._upper_bounds) elif self.options['bound_enforcement'] == 'scalar': u._enforce_bounds_scalar(du, 1.0, system._lower_bounds, system._upper_bounds) elif self.options['bound_enforcement'] == 'wall': u._enforce_bounds_wall(du, 1.0, system._lower_bounds, system._upper_bounds) 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 self._mpi_print(self._iter_count, norm, norm / norm0) fail = (np.isinf(norm) or np.isnan(norm)) return fail, norm, norm / norm0
def solve(self, vec_names, mode, rel_systems=None): """ Solve the linear system for the problem in self._system. The full solution vector is returned. Parameters ---------- vec_names : list list of vector names. mode : string Derivative mode, can be 'fwd' or 'rev'. rel_systems : set of str Set of names of relevant systems based on the current linear solve. Returns ------- boolean Failure flag; True if failed to converge, False is successful. float absolute error. float relative error. """ self._vec_names = vec_names self._rel_systems = rel_systems self._mode = mode system = self._system solve = self.solve_function if solve is None: solve = system.solve_linear for vec_name in self._vec_names: self._vec_name = vec_name d_outputs = system._vectors['output'][vec_name] d_resids = system._vectors['residual'][vec_name] self._iter_count = 0 # run custom solver with system._unscaled_context(outputs=[d_outputs], residuals=[d_resids]): with Recording(type(self).__name__, self._iter_count, self) as rec: fail, abs_error, rel_error = solve(d_outputs, d_resids, mode) rec.abs = abs_error rec.rel = rel_error return fail, abs_error, rel_error
def objective_callback(self, x, icase): """ Evaluate problem objective at the requested point. Parameters ---------- x : ndarray Value of design variables. icase : int Case number, used for identification when run in parallel. Returns ------- float Objective value bool Success flag, True if successful int Case number, used for identification when run in parallel. """ model = self._problem.model success = 1 for name in self._designvars: i, j = self._desvar_idx[name] self.set_design_var(name, x[i:j]) # Execute the model with Recording('SimpleGA', self.iter_count, self) as rec: self.iter_count += 1 try: model._solve_nonlinear() # Tell the optimizer that this is a bad point. except AnalysisError: model._clear_iprint() success = 0 for name, val in iteritems(self.get_objective_values()): obj = val break # Record after getting obj to assure they have # been gathered in MPI. rec.abs = 0.0 rec.rel = 0.0 # print("Functions calculated") # print(x) # print(obj) return obj, success, icase
def _iter_execute(self): """ Perform the operations in the iteration loop. """ system = self._system self._solver_info.append_subsolver() do_subsolve = self.options['solve_subsystems'] and \ (self._iter_count < self.options['max_sub_solves']) do_sub_ln = self.linear_solver._linearize_children() # Disable local fd approx_status = system._owns_approx_jac system._owns_approx_jac = False system._vectors['residual']['linear'].set_vec(system._residuals) system._vectors['residual']['linear'] *= -1.0 my_asm_jac = self.linear_solver._assembled_jac system._linearize(my_asm_jac, sub_do_ln=do_sub_ln) if (my_asm_jac is not None and system.linear_solver._assembled_jac is not my_asm_jac): my_asm_jac._update(system) self._linearize() self.linear_solver.solve(['linear'], 'fwd') if self.linesearch: self.linesearch._do_subsolve = do_subsolve self.linesearch.solve() else: system._outputs += system._vectors['output']['linear'] self._solver_info.pop() # Hybrid newton support. if do_subsolve: with Recording('Newton_subsolve', 0, self): self._solver_info.append_solver() for isub, subsys in enumerate(system._subsystems_allprocs): system._transfer('nonlinear', 'fwd', isub) if subsys in system._subsystems_myproc: subsys._solve_nonlinear() self._solver_info.pop() # Enable local fd system._owns_approx_jac = approx_status
def _apply_nonlinear(self): """ Compute residuals. The model is assumed to be in a scaled state. """ with self._unscaled_context(outputs=[self._outputs], residuals=[self._residuals]): with Recording(self.pathname + '._apply_nonlinear', self.iter_count, self): self._inputs.read_only = self._outputs.read_only = True try: if self._discrete_inputs or self._discrete_outputs: self.apply_nonlinear(self._inputs, self._outputs, self._residuals, self._discrete_inputs, self._discrete_outputs) else: self.apply_nonlinear(self._inputs, self._outputs, self._residuals) finally: self._inputs.read_only = self._outputs.read_only = False
def _iter_execute(self): """ Perform the operations in the iteration loop. """ self._solver_info.append_subsolver() self._system._transfer('nonlinear', 'fwd') with Recording('NonlinearBlockJac', 0, self) as rec: for subsys in self._system._subsystems_myproc: subsys._solve_nonlinear() self._system._check_reconf_update() rec.abs = 0.0 rec.rel = 0.0 self._solver_info.pop()
def solve(self, vec_names, mode, rel_systems=None): """ Run the solver. Parameters ---------- vec_names : [str, ...] List of names of the right-hand-side vectors. mode : str 'fwd' or 'rev'. rel_systems : set of str Names of systems relevant to the current solve. Returns ------- float Initial error. float Error at the first iteration. """ self._vec_names = vec_names self._mode = mode self._rel_systems = rel_systems system = self._system if isinstance(system._jacobian, AssembledJacobian): raise RuntimeError("A block linear solver '%s' is being used with " "an AssembledJacobian in system '%s'" % (self.SOLVER, self._system.pathname)) # Pre-processing if self._mode == 'fwd': b_vecs = system._vectors['residual'] else: # rev b_vecs = system._vectors['output'] for vec_name in self._vec_names: if vec_name in system._rel_vec_names: self._rhs_vecs[vec_name].set_vec(b_vecs[vec_name]) with Recording('LinearRunOnce', 0, self) as rec: # Single iteration of GS self._iter_execute() rec.abs = 0.0 rec.rel = 0.0 return False, 0.0, 0.0