def _assemble_jacobian(self, rhs, mode):
        """ Assemble Jacobian.

        Args
        ----
        rhs : ndarray
            An ndarray containomg the right-hand side for this linear
            solve.

        system : `System`
            Parent `System` object.

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

        Returns
        -------
        ndarray : Jacobian Matrix
        """
        system = self.system

        # OpenMDAO does matrix vector product.
        if self.options['jacobian_method'] == 'MVP':

            self.mode = mode

            n_edge = len(rhs)
            ident = np.eye(n_edge)

            partials = np.empty((n_edge, n_edge))

            for i in range(n_edge):
                partials[:, i] = self.mult(ident[:, i])

        # Assemble the Jacobian
        else:

            # Must clear the jacobian if we switch modes
            if self.mode != mode:
                self.setup(system)
            self.mode = mode

            sys_name = system.name + '.'
            partials = self.jacobian
            u_vec = system.unknowns
            icache = self.icache
            conn = system.connections
            sys_prom_name = system._sysdata.to_prom_name

            for sub in system.components(recurse=True, include_self=True):

                jac = sub._jacobian_cache

                # This method won't work on components where apply_linear
                # is overridden.
                if jac is None:
                    msg = "The 'assemble' jacobian_method is not supported when " + \
                         "'apply_linear' is used on a component (%s)." % sub.pathname
                    raise RuntimeError(msg)

                sub_u = sub.unknowns
                sub_name = sub.pathname

                for key in jac:
                    o_var, i_var = key
                    key2 = (sub_name, key)

                    # We cache the location of each variable in our jacobian
                    if key2 not in icache:

                        o_var_abs = '.'.join((sub_name, o_var))
                        i_var_abs = '.'.join((sub_name, i_var))
                        i_var_pro = sys_prom_name[i_var_abs]
                        o_var_pro = sys_prom_name[o_var_abs]

                        # States are fine ...
                        if i_var in sub.states:
                            pass

                        #... but inputs need to find their source.
                        elif i_var_pro not in u_vec:

                            # Param is not relevant
                            if i_var_abs not in conn:
                                continue

                            i_var_src = conn[i_var_abs][0]
                            i_var_pro = sys_prom_name[i_var_src]

                        o_start, o_end = u_vec._dat[o_var_pro].slice
                        i_start, i_end = u_vec._dat[i_var_pro].slice

                        icache[key2] = (o_start, o_end, i_start, i_end)

                    else:
                        (o_start, o_end, i_start, i_end) = icache[key2]

                    if mode=='fwd':
                        partials[o_start:o_end, i_start:i_end] = jac[o_var, i_var]
                    else:
                        partials[i_start:i_end, o_start:o_end] = jac[o_var, i_var].T

        return partials
dataset/ETHPy150Open OpenMDAO/OpenMDAO/openmdao/solvers/ln_direct.py/DirectSolver._assemble_jacobian/original