def __init__(self, regul, param, isprint=False):
        """
        Arguments:
            regul = regularization for inversion parameters
            param = inversion parameters (either 'a' or 'b')
            isprint = boolean
        """
        self.param = param
        if self.param == 'a':
            self.regul1 = regul
            self.regul2 = ZeroRegularization(regul.Vm)
        elif self.param == 'b':
            self.regul1 = ZeroRegularization(regul.Vm)
            self.regul2 = regul
        else:
            if isprint:
                print "[SingleRegularization] *** Error: argument 'param' must be 'a' or 'b'"
                sys.exit(1)
        self.isprint = isprint

        Vm = regul.Vm
        self.VmVm = createMixedFS(Vm, Vm)
        self.ab = Function(self.VmVm)
        bd = BlockDiagonal(Vm, Vm, Vm.mesh().mpi_comm())
        self.saa = bd.saa

        if isprint:
            print '[SingleRegularization] inversion parameter {}'.format(
                self.param)
            if self.isPD():
                print '[SingleRegularization] Using primal-dual TV'
    def __init__(self, mpicomm_global, acousticwavePDE, sources, \
    sourcesindex, timestepsindex, \
    invparam='ab', regularization=None):
        """ 
        Input:
            acousticwavePDE should be an instantiation from class AcousticWave
        """
        self.mpicomm_global = mpicomm_global

        self.PDE = acousticwavePDE
        self.PDE.exact = None
        self.obsop = None   # Observation operator
        self.dd = None  # observations
        self.fwdsource = sources
        self.srcindex = sourcesindex
        self.tsteps = timestepsindex
        self.PDEcount = 0

        self.inverta = False
        self.invertb = False
        if 'a' in invparam:
            self.inverta = True
        if 'b' in invparam:
            self.invertb = True
        assert self.inverta + self.invertb > 0

        Vm = self.PDE.Vm
        V = self.PDE.V
        VmVm = createMixedFS(Vm, Vm)
        self.ab = Function(VmVm)   # used for conversion (Vm,Vm)->VmVm
        self.invparam = invparam
        self.MG = Function(VmVm)
        self.MGv = self.MG.vector()
        self.Grad = Function(VmVm)
        self.srchdir = Function(VmVm)
        self.delta_m = Function(VmVm)
        self.m_bkup = Function(VmVm)
        LinearOperator.__init__(self, self.MGv, self.MGv)
        self.GN = False

        if regularization == None:  
            print '[ObjectiveAcoustic] *** Warning: Using zero regularization'
            self.regularization = ZeroRegularization(Vm)
        else:   
            self.regularization = regularization
            self.PD = self.regularization.isPD()
        self.alpha_reg = 1.0

        self.p, self.q = Function(V), Function(V)
        self.phat, self.qhat = Function(V), Function(V)
        self.ahat, self.bhat = Function(Vm), Function(Vm)
        self.ptrial, self.ptest = TrialFunction(V), TestFunction(V)
        self.mtest, self.mtrial = TestFunction(Vm), TrialFunction(Vm)
        if self.PDE.parameters['lumpM']:
            self.Mprime = LumpedMassMatrixPrime(Vm, V, self.PDE.M.ratio)
            self.get_gradienta = self.get_gradienta_lumped
            self.get_hessiana = self.get_hessiana_lumped
            self.get_incra = self.get_incra_lumped
        else:
            self.wkformgrada = inner(self.mtest*self.p, self.q)*dx
            self.get_gradienta = self.get_gradienta_full
            self.wkformhessa = inner(self.phat*self.mtest, self.q)*dx \
            + inner(self.p*self.mtest, self.qhat)*dx
            self.wkformhessaGN = inner(self.p*self.mtest, self.qhat)*dx
            self.get_hessiana = self.get_hessiana_full
            self.wkformrhsincra = inner(self.ahat*self.ptrial, self.ptest)*dx
            self.get_incra = self.get_incra_full
        self.wkformgradb = inner(self.mtest*nabla_grad(self.p), nabla_grad(self.q))*dx
        self.wkformgradbout = assemble(self.wkformgradb)
        self.wkformrhsincrb = inner(self.bhat*nabla_grad(self.ptrial), nabla_grad(self.ptest))*dx
        self.wkformhessb = inner(nabla_grad(self.phat)*self.mtest, nabla_grad(self.q))*dx \
        + inner(nabla_grad(self.p)*self.mtest, nabla_grad(self.qhat))*dx
        self.wkformhessbGN = inner(nabla_grad(self.p)*self.mtest, nabla_grad(self.qhat))*dx

        # Mass matrix:
        self.mmtest, self.mmtrial = TestFunction(VmVm), TrialFunction(VmVm)
        weak_m =  inner(self.mmtrial, self.mmtest)*dx
        self.Mass = assemble(weak_m)
        self.solverM = PETScKrylovSolver("cg", "jacobi")
        self.solverM.parameters["maximum_iterations"] = 2000
        self.solverM.parameters["absolute_tolerance"] = 1e-24
        self.solverM.parameters["relative_tolerance"] = 1e-24
        self.solverM.parameters["report"] = False
        self.solverM.parameters["error_on_nonconvergence"] = True 
        self.solverM.parameters["nonzero_initial_guess"] = False # True?
        self.solverM.set_operator(self.Mass)

        # Time-integration factors
        self.factors = np.ones(self.PDE.times.size)
        self.factors[0], self.factors[-1] = 0.5, 0.5
        self.factors *= self.PDE.Dt
        self.invDt = 1./self.PDE.Dt

        # Absorbing BCs
        if self.PDE.parameters['abc']:
            assert not self.PDE.parameters['lumpD']

            self.wkformgradaABC = inner(
            self.mtest*sqrt(self.PDE.b/self.PDE.a)*self.p, 
            self.q)*self.PDE.ds(1)
            self.wkformgradbABC = inner(
            self.mtest*sqrt(self.PDE.a/self.PDE.b)*self.p, 
            self.q)*self.PDE.ds(1)
            self.wkformgradaABCout = assemble(self.wkformgradaABC)
            self.wkformgradbABCout = assemble(self.wkformgradbABC)

            self.wkformincrrhsABC = inner(
            (self.ahat*sqrt(self.PDE.b/self.PDE.a)
             + self.bhat*sqrt(self.PDE.a/self.PDE.b))*self.ptrial,
            self.ptest)*self.PDE.ds(1)

            self.wkformhessaABC = inner(
            (self.bhat/sqrt(self.PDE.a*self.PDE.b) - 
            self.ahat*sqrt(self.PDE.b/(self.PDE.a*self.PDE.a*self.PDE.a)))
            *self.p*self.mtest, self.q)*self.PDE.ds(1)
            self.wkformhessbABC = inner(
            (self.ahat/sqrt(self.PDE.a*self.PDE.b) - 
            self.bhat*sqrt(self.PDE.a/(self.PDE.b*self.PDE.b*self.PDE.b)))
            *self.p*self.mtest, self.q)*self.PDE.ds(1)