Exemple #1
0
    def solve_nonlinear(self, params, unknowns, resids):
        """Runs the component
        """

        self.return_code = -12345678

        if not self.options['command']:
            raise ValueError('Empty command list')

        if self.options['fail_hard']:
            err_class = RuntimeError
        else:
            err_class = AnalysisError

        return_code = None

        try:
            missing = self._check_for_files(
                self.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()

            if return_code is None:
                raise AnalysisError('Timed out after %s sec.' %
                                    self.options['timeout'])

            elif return_code:
                if isinstance(self.stderr, str):
                    if os.path.exists(self.stderr):
                        stderrfile = open(self.stderr, 'r')
                        error_desc = stderrfile.read()
                        stderrfile.close()
                        err_fragment = "\nError Output:\n%s" % error_desc
                    else:
                        err_fragment = "\n[stderr %r missing]" % self.stderr
                else:
                    err_fragment = error_msg

                raise err_class('return_code = %d%s' %
                                (return_code, err_fragment))

            missing = self._check_for_files(
                self.options['external_output_files'])
            if missing:
                raise err_class("The following output files are missing: %s" %
                                sorted(missing))

        finally:
            self.return_code = -999999 if return_code is None else return_code
    def solve_nonlinear(self, params, unknowns, resids):
        if MPI:
            unknowns['case_rank'] = MPI.COMM_WORLD.rank

        if self.trace:
            print(self.pathname, "solve_nonlinear")
        try:
            super(ExecComp4Test, self).solve_nonlinear(params, unknowns,
                                                       resids)
            time.sleep(self.nl_delay)
            if self.num_nl_solves in self.fails:
                if self.critical:
                    raise RuntimeError("OMG, a critical error!")
                else:
                    raise AnalysisError("just an analysis error")
        finally:
            self.num_nl_solves += 1
    def solve_nonlinear(self, params, unknowns, resids):
        if MPI:
            myrank = unknowns['case_rank'] = MPI.COMM_WORLD.rank
        else:
            myrank = unknowns['case_rank'] = int(
                os.environ.get('OPENMDAO_WORKER_ID', '0'))

        if self.trace:
            print(self.pathname, "solve_nonlinear")
        try:
            if myrank in self.fail_rank and self.num_nl_solves in self.fails:
                if self.fail_hard:
                    raise RuntimeError("OMG, a critical error!")
                else:
                    raise AnalysisError("just an analysis error")
            super(ExecComp4Test, self).solve_nonlinear(params, unknowns,
                                                       resids)
            time.sleep(self.nl_delay)
        finally:
            self.num_nl_solves += 1
    def solve(self, params, unknowns, resids, system, metadata=None):
        """ Solves the system using Gauss Seidel.

        Args
        ----
        params : `VecWrapper`
            `VecWrapper` containing parameters. (p)

        unknowns : `VecWrapper`
            `VecWrapper` containing outputs and states. (u)

        resids : `VecWrapper`
            `VecWrapper` containing residuals. (r)

        system : `System`
            Parent `System` object.

        metadata : dict, optional
            Dictionary containing execution metadata (e.g. iteration coordinate).
        """

        atol = self.options['atol']
        rtol = self.options['rtol']
        utol = self.options['utol']
        maxiter = self.options['maxiter']
        rutol = self.options['rutol']
        iprint = self.options['iprint']
        unknowns_cache = self.unknowns_cache

        # Initial run
        self.iter_count = 1

        # Metadata setup
        local_meta = create_local_meta(metadata, system.pathname)
        system.ln_solver.local_meta = local_meta
        update_local_meta(local_meta, (self.iter_count,))

        # Initial Solve
        system.children_solve_nonlinear(local_meta)

        self.recorders.record_iteration(system, local_meta)

        # Bail early if the user wants to.
        if maxiter == 1:
            return

        resids = system.resids
        unknowns_cache = np.zeros(unknowns.vec.shape)

        # Evaluate Norm
        system.apply_nonlinear(params, unknowns, resids)
        normval = resids.norm()
        basenorm = normval if normval > atol else 1.0
        u_norm = 1.0e99
        ru_norm = 1.0e99

        if iprint == 2:
            self.print_norm(self.print_name, system, 1, normval, basenorm)

        while self.iter_count < maxiter and \
                normval > atol and \
                normval/basenorm > rtol  and \
                u_norm > utol and \
                ru_norm > rutol:

            # Metadata update
            self.iter_count += 1
            update_local_meta(local_meta, (self.iter_count,))
            unknowns_cache[:] = unknowns.vec

            # Runs an iteration
            system.children_solve_nonlinear(local_meta)
            self.recorders.record_iteration(system, local_meta)

            # Evaluate Norm
            system.apply_nonlinear(params, unknowns, resids)
            normval = resids.norm()
            u_norm = np.linalg.norm(unknowns.vec - unknowns_cache)
            ru_norm = np.linalg.norm(unknowns.vec - unknowns_cache)/np.linalg.norm(unknowns.vec)


            if self.options['use_aitken']: # If Aitken acceleration is enabled

                # This method is used by Kenway et al. in "Scalable Parallel
                # Approach for High-Fidelity Steady-State Aeroelastic Analysis
                # and Adjoint Derivative Computations" (line 22 of Algorithm 1)
                # It is based on "A version of the Aitken accelerator for
                # computer iteration" by Irons et al.

                # Use relaxation after second iteration
                # self.delta_u_n_1 is a string for the first iteration
                if (type(self.delta_u_n_1) is not str) and \
                    normval > atol and \
                    normval/basenorm > rtol  and \
                    u_norm > utol and \
                    ru_norm > rutol:

                    delta_u_n = unknowns.vec - unknowns_cache
                    delta_u_n_1 = self.delta_u_n_1

                    # Compute relaxation factor
                    self.aitken_alpha = self.aitken_alpha * \
                        (1. - np.dot((delta_u_n  - delta_u_n_1), delta_u_n) \
                        / np.linalg.norm((delta_u_n  - delta_u_n_1), 2)**2)

                    # Limit relaxation factor to desired range
                    self.aitken_alpha = max(self.options['aitken_alpha_min'],
                        min(self.options['aitken_alpha_max'], self.aitken_alpha))

                    if iprint == 1 or iprint == 2:
                        print("Aitken relaxation factor is", self.aitken_alpha)

                    self.delta_u_n_1 = delta_u_n.copy()

                    # Update unknowns vector
                    unknowns.vec[:] = unknowns_cache + self.aitken_alpha * delta_u_n

                elif (type(self.delta_u_n_1) is str): # For the first iteration
                    # Initially self.delta_u_n_1 is a string then it is replaced
                    # by the following vector
                    self.delta_u_n_1 = unknowns.vec - unknowns_cache

            if iprint == 2:
                self.print_norm(self.print_name, system, self.iter_count, normval,
                                basenorm, u_norm=u_norm)

        # Final residual print if you only want the last one
        if iprint == 1:
            self.print_norm(self.print_name, system, self.iter_count, normval,
                            basenorm, u_norm=u_norm)

        if self.iter_count >= maxiter or isnan(normval):
            msg = 'FAILED to converge after %d iterations' % self.iter_count
            fail = True
        else:
            fail = False

        if iprint > 0 or (fail and iprint > -1 ):
            if not fail:
                msg = 'Converged in %d iterations' % self.iter_count

            self.print_norm(self.print_name, system, self.iter_count, normval,
                            basenorm, msg=msg)

        if fail and self.options['err_on_maxiter']:
            raise AnalysisError("Solve in '%s': NLGaussSeidel %s" %
                                (system.pathname, msg))
Exemple #5
0
    def solve(self, rhs_mat, system, mode):
        """ Solves the linear system for the problem in self.system. The
        full solution vector is returned.

        Args
        ----
        rhs_mat : dict of ndarray
            Dictionary containing one ndarry per top level quantity of
            interest. Each array contains the right-hand side for the linear
            solve.

        system : `System`
            Parent `System` object.

        mode : string
            Derivative mode, can be 'fwd' or 'rev'.

        Returns
        -------
        dict of ndarray : Solution vectors
        """
        options = self.options
        self.mode = mode

        unknowns_mat = OrderedDict()
        maxiter = options['maxiter']
        atol = options['atol']
        rtol = options['rtol']
        iprint = self.options['iprint']

        for voi, rhs in iteritems(rhs_mat):

            ksp = self.ksp[voi]

            ksp.setTolerances(max_it=maxiter, atol=atol, rtol=rtol)

            sol_vec = np.zeros(rhs.shape)
            # Set these in the system
            if trace:  # pragma: no cover
                debug("creating sol_buf petsc vec for voi", voi)
            self.sol_buf_petsc = PETSc.Vec().createWithArray(sol_vec,
                                                             comm=system.comm)
            if trace:  # pragma: no cover
                debug("sol_buf creation DONE")
                debug("creating rhs_buf petsc vec for voi", voi)
            self.rhs_buf_petsc = PETSc.Vec().createWithArray(rhs,
                                                             comm=system.comm)
            if trace: debug("rhs_buf creation DONE")

            # Petsc can only handle one right-hand-side at a time for now
            self.voi = voi
            self.system = system
            self.iter_count = 0
            ksp.solve(self.rhs_buf_petsc, self.sol_buf_petsc)
            self.system = None

            # Final residual print if you only want the last one
            if iprint == 1:
                mon = ksp.getMonitor()[0][0]
                self.print_norm(self.print_name, system, self.iter_count,
                                mon._norm, mon._norm0, indent=1, solver='LN')

            if self.iter_count >= maxiter:
                msg = 'FAILED to converge in %d iterations' % self.iter_count
                fail = True
            else:
                msg = 'Converged in %d iterations' % self.iter_count
                fail = False

            if iprint > 0 or (fail and iprint > -1 ):
                self.print_norm(self.print_name, system,self.iter_count, 0, 0,
                                msg=msg, indent=1, solver='LN')

            unknowns_mat[voi] = sol_vec

            if fail and self.options['err_on_maxiter']:
                raise AnalysisError("Solve in '%s': PetscKSP %s" %
                                    (system.pathname, msg))

            #print system.name, 'Linear solution vec', d_unknowns

        self.system = None
        return unknowns_mat
Exemple #6
0
    def solve(self,
              params,
              unknowns,
              resids,
              system,
              solver,
              alpha,
              fnorm0,
              metadata=None):
        """ Take the gradient calculated by the parent solver and figure out
        how far to go.

        Args
        ----
        params : `VecWrapper`
            `VecWrapper` containing parameters. (p)

        unknowns : `VecWrapper`
            `VecWrapper` containing outputs and states. (u)

        resids : `VecWrapper`
            `VecWrapper` containing residuals. (r)

        system : `System`
            Parent `System` object.

        metadata : dict, optional
            Dictionary containing execution metadata (e.g. iteration coordinate).

        solver : `Solver`
            Parent solver instance.

        alpha : float
            Initial over-relaxation factor as used in parent solver.

        fnorm0 : float
            Initial norm of the residual for relative tolerance check.

        Returns
        --------
        float
            Norm of the final residual
        """

        atol = self.options['atol']
        rtol = self.options['rtol']
        maxiter = self.options['maxiter']
        result = system.dumat[None]
        local_meta = create_local_meta(metadata, system.pathname)

        # If our step will violate any upper or lower bounds, then reduce
        # alpha so that we only step to that boundary.
        alpha = unknowns.distance_along_vector_to_limit(alpha, result)

        # Apply step that doesn't violate bounds
        unknowns.vec += alpha * result.vec

        # Metadata update
        update_local_meta(local_meta, (solver.iter_count, 0))

        # Just evaluate the model with the new points
        if solver.options['solve_subsystems']:
            system.children_solve_nonlinear(local_meta)
        system.apply_nonlinear(params, unknowns, resids, local_meta)

        self.recorders.record_iteration(system, local_meta)

        # Initial execution really belongs to our parent driver's iteration,
        # so use its info.
        fnorm = resids.norm()
        if solver.options['iprint'] > 0:
            self.print_norm(solver.print_name, system.pathname,
                            solver.iter_count, fnorm, fnorm0)

        itercount = 0
        ls_alpha = alpha

        # Further backtacking if needed.
        while itercount < maxiter and \
              fnorm > atol and \
              fnorm/fnorm0 > rtol:

            ls_alpha *= 0.5
            unknowns.vec -= ls_alpha * result.vec
            itercount += 1

            # Metadata update
            update_local_meta(local_meta, (solver.iter_count, itercount))

            # Just evaluate the model with the new points
            if self.options['solve_subsystems']:
                system.children_solve_nonlinear(local_meta)
            system.apply_nonlinear(params, unknowns, resids, local_meta)

            solver.recorders.record_iteration(system, local_meta)

            fnorm = resids.norm()
            if self.options['iprint'] > 0:
                self.print_norm(self.print_name,
                                system.pathname,
                                itercount,
                                fnorm,
                                fnorm0,
                                indent=1,
                                solver='LS')

        if itercount >= maxiter and self.options['err_on_maxiter']:
            raise AnalysisError(
                "Solve in '%s': BackTracking failed to converge after %d "
                "iterations." % (system.pathname, maxiter))

        return fnorm
Exemple #7
0
    def solve(self, params, unknowns, resids, system, metadata=None):
        """ Solves the system using the Brent Method.

        Args
        ----
        params : `VecWrapper`
            `VecWrapper` containing parameters. (p)

        unknowns : `VecWrapper`
            `VecWrapper` containing outputs and states. (u)

        resids : `VecWrapper`
            `VecWrapper` containing residuals. (r)

        system : `System`
            Parent `System` object.

        metadata : dict, optional
            Dictionary containing execution metadata (e.g. iteration coordinate).
        """
        self.sys = system
        self.metadata = metadata
        self.local_meta = create_local_meta(self.metadata, self.sys.pathname)
        self.sys.ln_solver.local_meta = self.local_meta
        idx = self.options['state_var_idx']

        if self.var_lower_bound is not None:
            lower = params[self.var_lower_bound]
        else:
            lower = self.options['lower_bound']

        if self.var_upper_bound is not None:
            upper = params[self.var_upper_bound]
        else:
            upper = self.options['upper_bound']

        kwargs = {
            'maxiter': self.options['maxiter'],
            'a': lower,
            'b': upper,
            'full_output':
            False,  # False, because we don't use the info, so just wastes operations
            'args': (params, unknowns, resids)
        }

        if self.options['xtol']:
            kwargs['xtol'] = self.options['xtol']
        if self.options['rtol'] > 0:
            kwargs['rtol'] = self.options['rtol']

        # Brent's method
        self.iter_count = 0

        # initial run to compute initial_norm
        self.sys.children_solve_nonlinear(self.local_meta)
        self.recorders.record_iteration(system, self.local_meta)

        # Evaluate Norm
        self.sys.apply_nonlinear(params, unknowns, resids)
        self.basenorm = resid_norm_0 = abs(
            resids._dat[self.s_var_name].val[idx])

        failed = False
        try:
            xstar = brentq(self._eval, **kwargs)
        except RuntimeError as err:
            msg = str(err)
            if 'different signs' in msg:
                raise
            failed = True

        self.sys = None

        resid_norm = abs(resids._dat[self.s_var_name].val[idx])

        if self.options['iprint'] > 0:

            if not failed:
                msg = 'converged'

            self.print_norm(self.print_name,
                            system.pathname,
                            self.iter_count,
                            resid_norm,
                            resid_norm_0,
                            msg=msg)

        if failed and self.options['err_on_maxiter']:
            raise AnalysisError(msg)
Exemple #8
0
    def solve(self, rhs_mat, system, mode):
        """ Solves the linear system for the problem in self.system. The
        full solution vector is returned.

        Args
        ----
        rhs_mat : dict of ndarray
            Dictionary containing one ndarry per top level quantity of
            interest. Each array contains the right-hand side for the linear
            solve.

        system : `System`
            Parent `System` object.

        mode : string
            Derivative mode, can be 'fwd' or 'rev'.

        Returns
        -------
        dict of ndarray : Solution vectors
        """

        options = self.options
        self.mode = mode
        iprint = self.options['iprint']

        unknowns_mat = OrderedDict()
        for voi, rhs in iteritems(rhs_mat):

            # Scipy can only handle one right-hand-side at a time.
            self.voi = voi

            n_edge = len(rhs)
            A = LinearOperator((n_edge, n_edge), matvec=self.mult, dtype=float)

            # Support a preconditioner
            if self.preconditioner:
                M = LinearOperator((n_edge, n_edge),
                                   matvec=self._precon,
                                   dtype=float)
            else:
                M = None

            # Call GMRES to solve the linear system
            self.system = system
            self.iter_count = 0
            d_unknowns, info = gmres(A,
                                     rhs,
                                     M=M,
                                     tol=options['atol'],
                                     maxiter=options['maxiter'],
                                     restart=options['restart'],
                                     callback=self.monitor)
            self.system = None

            # Final residual print if you only want the last one
            if iprint == 1:
                self.print_norm(self.print_name,
                                system,
                                self.iter_count,
                                self._norm,
                                self._norm0,
                                indent=1,
                                solver='LN')

            if info > 0:
                msg = "Solve in '%s': ScipyGMRES failed to converge " \
                          "after %d iterations" % (system.pathname,
                                                   self.iter_count)
                #logger.error(msg, system.name, info)
                if self.options['err_on_maxiter']:
                    raise AnalysisError(msg)
                print(msg)
                msg = 'FAILED to converge after max iterations'
                failed = True
            elif info < 0:
                msg = "ERROR in solve in '{}': gmres failed with code {}"
                raise RuntimeError(msg.format(system.pathname, info))
            else:
                msg = 'Converged in %d iterations' % self.iter_count
                failed = False

            if iprint > 0 or (failed and iprint > -1):
                self.print_norm(self.print_name,
                                system,
                                self.iter_count,
                                0,
                                0,
                                msg=msg,
                                indent=1,
                                solver='LN')

            unknowns_mat[voi] = d_unknowns

            #print(system.name, 'Linear solution vec', d_unknowns)

        return unknowns_mat
Exemple #9
0
    def solve(self, params, unknowns, resids, system, metadata=None):
        """ Solves the system using a Netwon's Method.

        Args
        ----
        params : `VecWrapper`
            `VecWrapper` containing parameters. (p)

        unknowns : `VecWrapper`
            `VecWrapper` containing outputs and states. (u)

        resids : `VecWrapper`
            `VecWrapper` containing residuals. (r)

        system : `System`
            Parent `System` object.

        metadata : dict, optional
            Dictionary containing execution metadata (e.g. iteration coordinate).
        """

        atol = self.options['atol']
        rtol = self.options['rtol']
        utol = self.options['utol']
        maxiter = self.options['maxiter']
        alpha_scalar = self.options['alpha']
        iprint = self.options['iprint']
        ls = self.line_search
        unknowns_cache = self.unknowns_cache

        # Metadata setup
        self.iter_count = 0
        local_meta = create_local_meta(metadata, system.pathname)
        if self.ln_solver:
            self.ln_solver.local_meta = local_meta
        else:
            system.ln_solver.local_meta = local_meta
        update_local_meta(local_meta, (self.iter_count, 0))

        # Perform an initial run to propagate srcs to targets.
        system.children_solve_nonlinear(local_meta)
        system.apply_nonlinear(params, unknowns, resids)

        if ls:
            base_u = np.zeros(unknowns.vec.shape)

        f_norm = resids.norm()
        f_norm0 = f_norm

        if iprint == 2:
            self.print_norm(self.print_name, system, 0, f_norm, f_norm0)

        arg = system.drmat[None]
        result = system.dumat[None]
        u_norm = 1.0e99

        # Can't have the system trying to FD itself when it also contains Newton.
        save_type = system.deriv_options['type']
        system.deriv_options.locked = False
        system.deriv_options['type'] = 'user'

        while self.iter_count < maxiter and f_norm > atol and \
                f_norm/f_norm0 > rtol and u_norm > utol:

            # Linearize Model with partial derivatives
            system._sys_linearize(params, unknowns, resids, total_derivs=False)

            # Calculate direction to take step
            arg.vec[:] = -resids.vec
            with system._dircontext:
                system.solve_linear(system.dumat,
                                    system.drmat, [None],
                                    mode='fwd',
                                    solver=self.ln_solver)

            self.iter_count += 1

            # Allow different alphas for each value so we can keep moving when we
            # hit a bound.
            alpha = alpha_scalar * np.ones(len(unknowns.vec))

            # If our step will violate any upper or lower bounds, then reduce
            # alpha in just that direction so that we only step to that
            # boundary.
            alpha = unknowns.distance_along_vector_to_limit(alpha, result)

            # Cache the current norm
            if ls:
                base_u[:] = unknowns.vec
                base_norm = f_norm

            # Apply step that doesn't violate bounds
            unknowns_cache[:] = unknowns.vec
            unknowns.vec += alpha * result.vec

            # Metadata update
            update_local_meta(local_meta, (self.iter_count, 0))

            # Just evaluate (and optionally solve) the model with the new
            # points
            if self.options['solve_subsystems']:
                system.children_solve_nonlinear(local_meta)
            system.apply_nonlinear(params, unknowns, resids, local_meta)

            self.recorders.record_iteration(system, local_meta)

            f_norm = resids.norm()
            u_norm = np.linalg.norm(unknowns.vec - unknowns_cache)
            if iprint == 2:
                self.print_norm(self.print_name,
                                system,
                                self.iter_count,
                                f_norm,
                                f_norm0,
                                u_norm=u_norm)

            # Line Search to determine how far to step in the Newton direction
            if ls:
                f_norm = ls.solve(params, unknowns, resids, system, self,
                                  alpha_scalar, alpha, base_u, base_norm,
                                  f_norm, f_norm0, metadata)

        # Final residual print if you only want the last one
        if iprint == 1:
            self.print_norm(self.print_name,
                            system,
                            self.iter_count,
                            f_norm,
                            f_norm0,
                            u_norm=u_norm)

        # Return system's FD status back to what it was
        system.deriv_options['type'] = save_type
        system.deriv_options.locked = True

        if self.iter_count >= maxiter or isnan(f_norm):
            msg = 'FAILED to converge after %d iterations' % self.iter_count
            fail = True
        else:
            msg = 'Converged in %d iterations' % self.iter_count
            fail = False

        if iprint > 0 or (fail and iprint > -1):

            self.print_norm(self.print_name,
                            system,
                            self.iter_count,
                            f_norm,
                            f_norm0,
                            msg=msg)

        if fail and self.options['err_on_maxiter']:
            raise AnalysisError("Solve in '%s': Newton %s" %
                                (system.pathname, msg))
Exemple #10
0
    def solve(self,
              params,
              unknowns,
              resids,
              system,
              solver,
              alpha_scalar,
              alpha,
              base_u,
              base_norm,
              fnorm,
              fnorm0,
              metadata=None):
        """ Take the gradient calculated by the parent solver and figure out
        how far to go.

        Args
        ----
        params : `VecWrapper`
            `VecWrapper` containing parameters. (p)

        unknowns : `VecWrapper`
            `VecWrapper` containing outputs and states. (u)

        resids : `VecWrapper`
            `VecWrapper` containing residuals. (r)

        system : `System`
            Parent `System` object.

        solver : `Solver`
            Parent solver instance.

        alpha_scalar : float
            Initial over-relaxation factor as used in parent solver.

        alpha : ndarray
            Initial over-relaxation factor as used in parent solver, vector
            (so we don't re-allocate).

        base_u : ndarray
            Initial value of unknowns before the Newton step.

        base_norm : float
            Norm of the residual prior to taking the Newton step.

        fnorm : float
            Norm of the residual after taking the Newton step.

        fnorm0 : float
            Initial norm of the residual for iteration printing.

        metadata : dict, optional
            Dictionary containing execution metadata (e.g. iteration coordinate).

        Returns
        --------
        float
            Norm of the final residual
        """

        maxiter = self.options['maxiter']
        rho = self.options['rho']
        c = self.options['c']
        iprint = self.options['iprint']
        result = system.dumat[None]
        local_meta = create_local_meta(metadata, system.pathname)

        itercount = 0
        ls_alpha = alpha_scalar

        # Further backtacking 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 itercount < maxiter and (base_norm -
                                       fnorm) < c * ls_alpha * base_norm:

            ls_alpha *= rho

            # If our step will violate any upper or lower bounds, then reduce
            # alpha in just that direction so that we only step to that
            # boundary.
            unknowns.vec[:] = base_u
            alpha[:] = ls_alpha
            alpha = unknowns.distance_along_vector_to_limit(alpha, result)

            unknowns.vec += alpha * result.vec
            itercount += 1

            # Metadata update
            update_local_meta(local_meta, (solver.iter_count, itercount))

            # Just evaluate the model with the new points
            if self.options['solve_subsystems']:
                system.children_solve_nonlinear(local_meta)
            system.apply_nonlinear(params, unknowns, resids, local_meta)

            solver.recorders.record_iteration(system, local_meta)

            fnorm = resids.norm()
            if iprint == 2:
                self.print_norm(self.print_name,
                                system,
                                itercount,
                                fnorm,
                                fnorm0,
                                indent=1,
                                solver='LS')

        # Final residual print if you only want the last one
        if iprint == 1:
            self.print_norm(self.print_name,
                            system,
                            itercount,
                            fnorm,
                            fnorm0,
                            indent=1,
                            solver='LS')

        if itercount >= maxiter or isnan(fnorm):

            if self.options['err_on_maxiter']:
                msg = "Solve in '{}': BackTracking failed to converge after {} " \
                      "iterations."
                raise AnalysisError(msg.format(system.pathname, maxiter))

            msg = 'FAILED to converge after %d iterations' % itercount
            fail = True
        else:
            msg = 'Converged in %d iterations' % itercount
            fail = False

        if iprint > 0 or (fail and iprint > -1):

            self.print_norm(self.print_name,
                            system,
                            itercount,
                            fnorm,
                            fnorm0,
                            msg=msg,
                            indent=1,
                            solver='LS')

        return fnorm
Exemple #11
0
    def solve(self, rhs_mat, system, mode):
        """ Solves the linear system for the problem in self.system. The
        full solution vector is returned.

        Args
        ----
        rhs_mat : dict of ndarray
            Dictionary containing one ndarry per top level quantity of
            interest. Each array contains the right-hand side for the linear
            solve.

        system : `System`
            Parent `System` object.

        mode : string
            Derivative mode, can be 'fwd' or 'rev'.

        Returns
        -------
        dict of ndarray : Solution vectors
        """

        dumat = system.dumat
        drmat = system.drmat
        dpmat = system.dpmat
        gs_outputs = system._get_gs_outputs(mode, self._vois)
        relevance = system._probdata.relevance
        fwd = mode == 'fwd'

        system.clear_dparams()
        for voi in rhs_mat:
            dumat[voi].vec[:] = 0.0

        vois = rhs_mat.keys()
        # John starts with the following. It is not necessary, but
        # uncommenting it helps to debug when comparing print outputs to his.
        # for voi in vois:
        #    drmat[voi].vec[:] = -rhs_mat[voi]

        sol_buf = OrderedDict()

        f_norm0, f_norm = 1.0, 1.0
        self.iter_count = 0
        maxiter = self.options['maxiter']
        while self.iter_count < maxiter and f_norm > self.options['atol'] \
                  and f_norm/f_norm0 > self.options['rtol']:

            if fwd:

                for sub in itervalues(system._subsystems):

                    for voi in vois:
                        #print('pre scatter', sub.pathname, 'dp', dpmat[voi].vec,
                        #      'du', dumat[voi].vec, 'dr', drmat[voi].vec)
                        system._transfer_data(sub.name,
                                              deriv=True,
                                              var_of_interest=voi)
                        #print('pre apply', sub.pathname, 'dp', dpmat[voi].vec,
                        #      'du', dumat[voi].vec, 'dr', drmat[voi].vec)

                    # we need to loop over all subsystems in order to make
                    # the necessary collective calls to scatter, but only
                    # active subsystems do anything else
                    if not sub.is_active():
                        continue

                    # print(sub.name, sorted(gs_outputs['fwd'][sub.name][None]))

                    # Groups and all other systems just call their own
                    # apply_linear.
                    sub._sys_apply_linear(
                        mode,
                        system._do_apply,
                        vois=vois,
                        gs_outputs=gs_outputs['fwd'][sub.name])

                    # for voi in vois:
                    #    print('post apply', dpmat[voi].vec, dumat[voi].vec, drmat[voi].vec)

                    for voi in vois:
                        drmat[voi].vec *= -1.0
                        drmat[voi].vec += rhs_mat[voi]
                        dpmat[voi].vec[:] = 0.0

                    with sub._dircontext:
                        sub.solve_linear(sub.dumat, sub.drmat, vois, mode=mode)

                    # for voi in vois:
                    #    print('post solve', dpmat[voi].vec, dumat[voi].vec, drmat[voi].vec)

                for voi in vois:
                    sol_buf[voi] = dumat[voi].vec

            else:

                for sub in reversed(list(itervalues(system._subsystems))):

                    active = sub.is_active()

                    for voi in vois:
                        if active:
                            dumat[voi].vec *= 0.0

                        #print('pre scatter', sub.pathname, voi, dpmat[voi].vec, dumat[voi].vec, drmat[voi].vec)
                        system._transfer_data(sub.name,
                                              mode='rev',
                                              deriv=True,
                                              var_of_interest=voi)
                        #print('post scatter', sub.pathname, voi, dpmat[voi].vec, dumat[voi].vec, drmat[voi].vec)

                        if active:
                            dumat[voi].vec *= -1.0
                            dumat[voi].vec += rhs_mat[voi]

                    # we need to loop over all subsystems in order to make
                    # the necessary collective calls to scatter, but only
                    # active subsystems do anything else
                    if not active:
                        continue

                    with sub._dircontext:
                        sub.solve_linear(sub.dumat, sub.drmat, vois, mode=mode)
                    #for voi in vois:
                    #print('post solve', dpmat[voi].vec, dumat[voi].vec, drmat[voi].vec)

                    #print(sub.name, sorted(gs_outputs['rev'][sub.name][None]))

                    # Groups and all other systems just call their own
                    # apply_linear.
                    sub._sys_apply_linear(
                        mode,
                        system._do_apply,
                        vois=vois,
                        gs_outputs=gs_outputs['rev'][sub.name])

                    #for voi in vois:
                    #print('post apply', system.dpmat[voi].vec, dumat[voi].vec, drmat[voi].vec)

                for voi in vois:
                    sol_buf[voi] = drmat[voi].vec

            self.iter_count += 1
            if maxiter == 1:
                f_norm = 0.0
            else:
                f_norm = self._norm(system, mode, rhs_mat)

            if self.options['iprint'] > 0:
                self.print_norm(self.print_name,
                                system.pathname,
                                self.iter_count,
                                f_norm,
                                f_norm0,
                                indent=1,
                                solver='LN')

        if maxiter > 1 and self.iter_count >= maxiter:
            msg = 'FAILED to converge after %d iterations' % self.iter_count
            failed = True
        else:
            failed = False

        if self.options['iprint'] > 0:
            if not failed:
                msg = 'converged'

            self.print_norm(self.print_name,
                            system.pathname,
                            self.iter_count,
                            f_norm,
                            f_norm0,
                            indent=1,
                            solver='LN',
                            msg=msg)

        if failed and self.options['err_on_maxiter']:
            raise AnalysisError("Solve in '%s': LinearGaussSeidel %s" %
                                (system.pathname, msg))

        return sol_buf
Exemple #12
0
    def solve(self, params, unknowns, resids, system, metadata=None):
        """ Solves the system using a Netwon's Method.

        Args
        ----
        params : `VecWrapper`
            `VecWrapper` containing parameters. (p)

        unknowns : `VecWrapper`
            `VecWrapper` containing outputs and states. (u)

        resids : `VecWrapper`
            `VecWrapper` containing residuals. (r)

        system : `System`
            Parent `System` object.

        metadata : dict, optional
            Dictionary containing execution metadata (e.g. iteration coordinate).
        """

        atol = self.options['atol']
        rtol = self.options['rtol']
        maxiter = self.options['maxiter']
        alpha = self.options['alpha']

        # Metadata setup
        self.iter_count = 0
        local_meta = create_local_meta(metadata, system.pathname)
        system.ln_solver.local_meta = local_meta
        update_local_meta(local_meta, (self.iter_count, 0))

        # Perform an initial run to propagate srcs to targets.
        system.children_solve_nonlinear(local_meta)
        system.apply_nonlinear(params, unknowns, resids)

        f_norm = resids.norm()
        f_norm0 = f_norm

        if self.options['iprint'] > 0:
            self.print_norm(self.print_name, system.pathname, 0, f_norm,
                            f_norm0)

        arg = system.drmat[None]
        result = system.dumat[None]

        while self.iter_count < maxiter and f_norm > atol and \
                f_norm/f_norm0 > rtol:

            # Linearize Model with partial derivatives
            system._sys_linearize(params, unknowns, resids, total_derivs=False)

            # Calculate direction to take step
            arg.vec[:] = -resids.vec
            with system._dircontext:
                system.solve_linear(system.dumat,
                                    system.drmat, [None],
                                    mode='fwd',
                                    solver=self.ln_solver)

            # Step in that direction,
            self.iter_count += 1
            f_norm = self.line_search.solve(params, unknowns, resids, system,
                                            self, alpha, f_norm0, metadata)

        # Need to make sure the whole workflow is executed at the final
        # point, not just evaluated.
        #self.iter_count += 1
        #update_local_meta(local_meta, (self.iter_count, 0))
        #system.children_solve_nonlinear(local_meta)

        if self.iter_count >= maxiter or isnan(f_norm):
            msg = 'FAILED to converge after %d iterations' % self.iter_count
            fail = True
        else:
            fail = False

        if self.options['iprint'] > 0:

            if not fail:
                msg = 'converged'

            self.print_norm(self.print_name,
                            system.pathname,
                            self.iter_count,
                            f_norm,
                            f_norm0,
                            msg=msg)

        if fail and self.options['err_on_maxiter']:
            raise AnalysisError("Solve in '%s': Newton %s" %
                                (system.pathname, msg))
Exemple #13
0
    def solve(self, params, unknowns, resids, system, metadata=None):
        """ Solves the system using Gauss Seidel.

        Args
        ----
        params : `VecWrapper`
            `VecWrapper` containing parameters. (p)

        unknowns : `VecWrapper`
            `VecWrapper` containing outputs and states. (u)

        resids : `VecWrapper`
            `VecWrapper` containing residuals. (r)

        system : `System`
            Parent `System` object.

        metadata : dict, optional
            Dictionary containing execution metadata (e.g. iteration coordinate).
        """

        atol = self.options['atol']
        rtol = self.options['rtol']
        maxiter = self.options['maxiter']
        iprint = self.options['iprint']

        # Initial run
        self.iter_count = 1

        # Metadata setup
        local_meta = create_local_meta(metadata, system.pathname)
        system.ln_solver.local_meta = local_meta
        update_local_meta(local_meta, (self.iter_count, ))

        # Initial Solve
        system.children_solve_nonlinear(local_meta)

        self.recorders.record_iteration(system, local_meta)

        # Bail early if the user wants to.
        if maxiter == 1:
            return

        resids = system.resids

        # Evaluate Norm
        system.apply_nonlinear(params, unknowns, resids)
        normval = resids.norm()
        basenorm = normval if normval > atol else 1.0

        if self.options['iprint'] > 0:
            self.print_norm(self.print_name, system.pathname, 0, normval,
                            basenorm)

        while self.iter_count < maxiter and \
                normval > atol and \
                normval/basenorm > rtol:

            # Metadata update
            self.iter_count += 1
            update_local_meta(local_meta, (self.iter_count, ))

            # Runs an iteration
            system.children_solve_nonlinear(local_meta)
            self.recorders.record_iteration(system, local_meta)

            # Evaluate Norm
            system.apply_nonlinear(params, unknowns, resids)
            normval = resids.norm()

            if self.options['iprint'] > 0:
                self.print_norm(self.print_name, system.pathname,
                                self.iter_count, normval, basenorm)

        if self.iter_count >= maxiter or isnan(normval):
            msg = 'FAILED to converge after %d iterations' % self.iter_count
            fail = True
        else:
            fail = False

        if self.options['iprint'] > 0:
            if not fail:
                msg = 'converged'

            self.print_norm(self.print_name,
                            system.pathname,
                            self.iter_count,
                            normval,
                            basenorm,
                            msg=msg)

        if fail and self.options['err_on_maxiter']:
            raise AnalysisError("Solve in '%s': NLGaussSeidel %s" %
                                (system.pathname, msg))