Esempio n. 1
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'):
                     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)
Esempio n. 2
0
    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
Esempio n. 3
0
    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
Esempio n. 4
0
    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
Esempio n. 5
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()
Esempio n. 6
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:
                    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
Esempio n. 7
0
    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)
Esempio n. 8
0
    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
Esempio n. 9
0
    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
Esempio n. 10
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
Esempio n. 11
0
    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.
Esempio n. 12
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
Esempio n. 13
0
 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)
Esempio n. 14
0
    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)
Esempio n. 15
0
    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
Esempio n. 16
0
 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()
Esempio n. 17
0
    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)
Esempio n. 18
0
    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)
Esempio n. 19
0
    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)
Esempio n. 20
0
    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.
Esempio n. 21
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)
Esempio n. 22
0
    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')
Esempio n. 23
0
    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)
Esempio n. 24
0
    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
Esempio n. 25
0
    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
Esempio n. 26
0
    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
Esempio n. 27
0
    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
Esempio n. 28
0
 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
Esempio n. 29
0
    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()
Esempio n. 30
0
    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