def apply(self, x, mode):
        self._check_mode(mode=mode)
        if mode == self.TIMES:
            x_tau_beta = x.val['tau_beta']

            # (delta_{zz'} beta.del_B_inv_z.beta + smoothing_beta)
            field_for_diagonal = nifty5.Field.from_local_data(
                domain=self.p_space,
                arr=np.array([
                    self.beta.vdot(del_B_inv.times(self.beta))
                    for del_B_inv in self.del_B_inv_list
                ]))
            delta_beta_del_B_inv_beta = nifty5.DiagonalOperator(
                domain=self.p_space, diagonal=field_for_diagonal)
            term_tau_beta_1 = delta_beta_del_B_inv_beta.times(x_tau_beta)
            term_tau_beta_2 = self.smoothness_operator_beta.times(x_tau_beta)

            result_fields = {
                'beta': nifty5.Field.zeros(domain=self.s_space),
                'tau_beta': term_tau_beta_1 + term_tau_beta_2,
            }

            result = global_newton.MultiField(domain=x.domain,
                                              val=result_fields)
            return result
    def apply(self, x, mode):
        self._check_mode(mode=mode)
        if mode == self.TIMES:
            x_tau_beta = x.val['tau_beta']

            # -beta.del_B_inv applied to tau_beta
            term_beta = nifty5.Field.from_global_data(
                domain=self.s_space,
                arr=np.array([
                    nifty5.Field.from_global_data(
                        domain=self.p_space,
                        arr=np.array([
                            B_inv.adjoint_times(self.beta).val[i]
                            for B_inv in self.del_B_inv_list
                        ])).vdot(x_tau_beta)
                    for i in range(self.s_space.shape[0])
                ]))

            result_fields = {
                'beta': term_beta,
                'tau_beta': nifty5.Field.zeros(domain=self.p_space)
            }

            result = global_newton.MultiField(domain=x.domain,
                                              val=result_fields)
            return result
    def gradient(self):

        if self.mode == 'multifield':
            gradient_beta = sum(self.get_gradient_beta_terms())
            gradient_tau_beta = sum(self.get_gradient_tau_beta_terms())

            gradients = {
                    'beta': gradient_beta,
                    'tau_beta': gradient_tau_beta,
                    }
            gradient = global_newton.MultiField(
                    self.position.domain, val=gradients)
        elif self.mode == 'beta':
            gradient = sum(self.get_gradient_beta_terms())
        elif self.mode == 'tau_beta':
            gradient = sum(self.get_gradient_tau_beta_terms())
        else:
            print('invalid mode')

        return gradient
    def apply(self, x, mode):
        self._check_mode(mode=mode)
        if mode == self.TIMES:
            x_beta = x.val['beta']

            # application of operator to beta field
            term_beta_1 = self.B_inv.times(x_beta)

            rho_exp_beta = np.zeros(self.len_s_space)
            for i, pos in enumerate(self.grid):
                rho_exp_beta[pos] = (self.rho * np.exp(self.beta.val[pos]))
            rho_exp_beta_field = nifty5.Field.from_global_data(
                domain=self.s_space, arr=rho_exp_beta)
            term_beta_2 = rho_exp_beta_field * x_beta

            result_fields = {
                'beta': term_beta_1 + term_beta_2,
                'tau_beta': nifty5.Field.zeros(domain=self.p_space),
            }

            result = global_newton.MultiField(domain=x.domain,
                                              val=result_fields)
            return result