@verbose
def make_inverse_operator(info, forward, noise_cov, loose=0.2, depth=0.8,
                          fixed=False, limit_depth_chs=True, rank=None,
                          verbose=None):
    """Assemble inverse operator

    Parameters
    ----------
    info : dict
        The measurement info to specify the channels to include.
        Bad channels in info['bads'] are not used.
    forward : dict
        Forward operator.
    noise_cov : instance of Covariance
        The noise covariance matrix.
    loose : None | float in [0, 1]
        Value that weights the source variances of the dipole components
        defining the tangent space of the cortical surfaces. Requires surface-
        based, free orientation forward solutions.
    depth : None | float in [0, 1]
        Depth weighting coefficients. If None, no depth weighting is performed.
    fixed : bool
        Use fixed source orientations normal to the cortical mantle. If True,
        the loose parameter is ignored.
    limit_depth_chs : bool
        If True, use only grad channels in depth weighting (equivalent to MNE
        C code). If grad chanels aren't present, only mag channels will be
        used (if no mag, then eeg). If False, use all channels.
    rank : None | int | dict
        Specified rank of the noise covariance matrix. If None, the rank is
        detected automatically. If int, the rank is specified for the MEG
        channels. A dictionary with entries 'eeg' and/or 'meg' can be used
        to specify the rank for each modality.
    verbose : bool, str, int, or None
        If not None, override default verbose level (see mne.verbose).

    Returns
    -------
    inv : instance of InverseOperator
        Inverse operator.

    Notes
    -----
    For different sets of options (**loose**, **depth**, **fixed**) to work,
    the forward operator must have been loaded using a certain configuration
    (i.e., with **force_fixed** and **surf_ori** set appropriately). For
    example, given the desired inverse type (with representative choices
    of **loose** = 0.2 and **depth** = 0.8 shown in the table in various
    places, as these are the defaults for those parameters):

        +---------------------+-----------+-----------+-----------+-----------------+--------------+
        | Inverse desired                             | Forward parameters allowed                 |
        +=====================+===========+===========+===========+=================+==============+
        |                     | **loose** | **depth** | **fixed** | **force_fixed** | **surf_ori** |
        +---------------------+-----------+-----------+-----------+-----------------+--------------+
        | | Loose constraint, | 0.2       | 0.8       | False     | False           | True         |
        | | Depth weighted    |           |           |           |                 |              |
        +---------------------+-----------+-----------+-----------+-----------------+--------------+
        | | Loose constraint  | 0.2       | None      | False     | False           | True         |
        +---------------------+-----------+-----------+-----------+-----------------+--------------+
        | | Free orientation, | None      | 0.8       | False     | False           | True         |
        | | Depth weighted    |           |           |           |                 |              |
        +---------------------+-----------+-----------+-----------+-----------------+--------------+
        | | Free orientation  | None      | None      | False     | False           | True | False |
        +---------------------+-----------+-----------+-----------+-----------------+--------------+
        | | Fixed constraint, | None      | 0.8       | True      | False           | True         |
        | | Depth weighted    |           |           |           |                 |              |
        +---------------------+-----------+-----------+-----------+-----------------+--------------+
        | | Fixed constraint  | None      | None      | True      | True            | True         |
        +---------------------+-----------+-----------+-----------+-----------------+--------------+

    Also note that, if the source space (as stored in the forward solution)
    has patch statistics computed, these are used to improve the depth
    weighting. Thus slightly different results are to be expected with
    and without this information.
    """  # noqa
    is_fixed_ori = is_fixed_orient(forward)

    if fixed and loose is not None:
        warn('When invoking make_inverse_operator with fixed=True, the loose '
             'parameter is ignored.')
        loose = None

    if is_fixed_ori and not fixed:
        raise ValueError('Forward operator has fixed orientation and can only '
                         'be used to make a fixed-orientation inverse '
                         'operator.')
    if fixed:
        if depth is not None:
            if is_fixed_ori or not forward['surf_ori']:
                raise ValueError('For a fixed orientation inverse solution '
                                 'with depth weighting, the forward solution '
                                 'must be free-orientation and in surface '
                                 'orientation')
        elif forward['surf_ori'] is False:
            raise ValueError('For a fixed orientation inverse solution '
                             'without depth weighting, the forward solution '
                             'must be in surface orientation')

    # depth=None can use fixed fwd, depth=0<x<1 must use free ori
    if depth is not None:
        if not (0 < depth <= 1):
            raise ValueError('depth should be a scalar between 0 and 1')
        if is_fixed_ori:
            raise ValueError('You need a free-orientation, surface-oriented '
                             'forward solution to do depth weighting even '
                             'when calculating a fixed-orientation inverse.')
        if not forward['surf_ori']:
            forward = convert_forward_solution(forward, surf_ori=True)
        assert forward['surf_ori']
    if loose is not None:
        if not (0 <= loose <= 1):
            raise ValueError('loose value should be smaller than 1 and bigger '
                             'than 0, or None for not loose orientations.')
        if loose < 1 and not forward['surf_ori']:
            raise ValueError('Forward operator is not oriented in surface '
                             'coordinates. A loose inverse operator requires '
                             'a surface-based, free orientation forward '
                             'operator.')

    #
    # 1. Read the bad channels
    # 2. Read the necessary data from the forward solution matrix file
    # 3. Load the projection data
    # 4. Load the sensor noise covariance matrix and attach it to the forward
    #

    gain_info, gain, noise_cov, whitener, n_nzero = \
        _prepare_forward(forward, info, noise_cov, rank=rank)
    forward['info']._check_consistency()

    #
    # 5. Compose the depth-weighting matrix
    #

    if depth is not None:
        patch_areas = forward.get('patch_areas', None)
        depth_prior = compute_depth_prior(gain, gain_info, is_fixed_ori,
                                          exp=depth, patch_areas=patch_areas,
                                          limit_depth_chs=limit_depth_chs)
    else:
        depth_prior = np.ones(gain.shape[1], dtype=gain.dtype)

    # Deal with fixed orientation forward / inverse
    if fixed:
        if depth is not None:
            # Convert the depth prior into a fixed-orientation one
            logger.info('    Picked elements from a free-orientation '
                        'depth-weighting prior into the fixed-orientation one')
        if not is_fixed_ori:
            # Convert to the fixed orientation forward solution now
            depth_prior = depth_prior[2::3]
            forward = convert_forward_solution(
                forward, surf_ori=forward['surf_ori'], force_fixed=True)
            is_fixed_ori = is_fixed_orient(forward)
            gain_info, gain, noise_cov, whitener, n_nzero = \
                _prepare_forward(forward, info, noise_cov, verbose=False)

    logger.info("Computing inverse operator with %d channels."
                % len(gain_info['ch_names']))

    #
    # 6. Compose the source covariance matrix
    #

    logger.info('Creating the source covariance matrix')
    source_cov = depth_prior.copy()
    depth_prior = dict(data=depth_prior, kind=FIFF.FIFFV_MNE_DEPTH_PRIOR_COV,
                       bads=[], diag=True, names=[], eig=None,
                       eigvec=None, dim=depth_prior.size, nfree=1,
                       projs=[])

    # apply loose orientations
    if not is_fixed_ori:
        orient_prior = compute_orient_prior(forward, loose=loose)
        source_cov *= orient_prior
        orient_prior = dict(data=orient_prior,
                            kind=FIFF.FIFFV_MNE_ORIENT_PRIOR_COV,
                            bads=[], diag=True, names=[], eig=None,
                            eigvec=None, dim=orient_prior.size, nfree=1,
                            projs=[])
    else:
        orient_prior = None

    # 7. Apply fMRI weighting (not done)

    #
    # 8. Apply the linear projection to the forward solution
    # 9. Apply whitening to the forward computation matrix
    #
    logger.info('Whitening the forward solution.')
    gain = np.dot(whitener, gain)

    # 10. Exclude the source space points within the labels (not done)

    #
    # 11. Do appropriate source weighting to the forward computation matrix
    #

    # Adjusting Source Covariance matrix to make trace of G*R*G' equal
    # to number of sensors.
    logger.info('Adjusting source covariance matrix.')
    source_std = np.sqrt(source_cov)
    gain *= source_std[None, :]
    trace_GRGT = linalg.norm(gain, ord='fro') ** 2
    scaling_source_cov = n_nzero / trace_GRGT
    source_cov *= scaling_source_cov
    gain *= sqrt(scaling_source_cov)

    source_cov = dict(data=source_cov, dim=source_cov.size,
                      kind=FIFF.FIFFV_MNE_SOURCE_COV, diag=True,
                      names=[], projs=[], eig=None, eigvec=None,
                      nfree=1, bads=[])

    # now np.trace(np.dot(gain, gain.T)) == n_nzero
    # logger.info(np.trace(np.dot(gain, gain.T)), n_nzero)

    #
    # 12. Decompose the combined matrix
    #

    logger.info('Computing SVD of whitened and weighted lead field '
                'matrix.')
    eigen_fields, sing, eigen_leads = linalg.svd(gain, full_matrices=False)
    logger.info('    largest singular value = %g' % np.max(sing))
    logger.info('    scaling factor to adjust the trace = %g' % trace_GRGT)

    eigen_fields = dict(data=eigen_fields.T, col_names=gain_info['ch_names'],
                        row_names=[], nrow=eigen_fields.shape[1],
                        ncol=eigen_fields.shape[0])
    eigen_leads = dict(data=eigen_leads.T, nrow=eigen_leads.shape[1],
                       ncol=eigen_leads.shape[0], row_names=[],
                       col_names=[])
    nave = 1.0

    # Handle methods
    has_meg = False
    has_eeg = False
    ch_idx = [k for k, c in enumerate(info['chs'])
              if c['ch_name'] in gain_info['ch_names']]
    for idx in ch_idx:
        ch_type = channel_type(info, idx)
        if ch_type == 'eeg':
            has_eeg = True
        if (ch_type == 'mag') or (ch_type == 'grad'):
            has_meg = True
    if has_eeg and has_meg:
        methods = FIFF.FIFFV_MNE_MEG_EEG
    elif has_meg:
        methods = FIFF.FIFFV_MNE_MEG
    else:
        methods = FIFF.FIFFV_MNE_EEG

    # We set this for consistency with mne C code written inverses
    if depth is None:
        depth_prior = None
    inv_op = dict(eigen_fields=eigen_fields, eigen_leads=eigen_leads,
                  sing=sing, nave=nave, depth_prior=depth_prior,
                  source_cov=source_cov, noise_cov=noise_cov,
                  orient_prior=orient_prior, projs=deepcopy(info['projs']),
                  eigen_leads_weighted=False, source_ori=forward['source_ori'],
                  mri_head_t=deepcopy(forward['mri_head_t']),
                  methods=methods, nsource=forward['nsource'],
                  coord_frame=forward['coord_frame'],
                  source_nn=forward['source_nn'].copy(),
                  src=deepcopy(forward['src']), fmri_prior=None)
    inv_info = deepcopy(forward['info'])
    inv_info['bads'] = [bad for bad in info['bads']
                        if bad in inv_info['ch_names']]
    inv_info._check_consistency()
    inv_op['units'] = 'Am'
    inv_op['info'] = inv_info

    return InverseOperator(inv_op)
dataset/ETHPy150Open mne-tools/mne-python/mne/minimum_norm/inverse.py/make_inverse_operator/original