Exemplo n.º 1
0
    def merge(self, solution: df.Function) -> None:
        """
        Combine solutions from the PDE and the ODE to form a single mixed function.

        `solution` holds the solution from the PDEsolver.
        """
        v = self.vur.sub(0)
        self.merger.assign(solution.sub(0), v)
Exemplo n.º 2
0
    def merge(self, solution: df.Function) -> None:
        """Combine solutions from the PDE and the ODE to form a single mixed function.

        Arguments:
            function holding the combined result
        """
        timer = df.Timer("Merge step")
        if self._parameters["pde_solver"] == "bidomain":
            v = self.vur.sub(0)
        else:
            v = self.vur
        self.merger.assign(solution.sub(0), v)
        timer.stop()
Exemplo n.º 3
0
def assign_restart_ic(receiving_function: df.Function,
                      assigning_func_iterator: Iterable[df.Function]) -> None:
    """Assign a seriess of functions to the `receiving_function`.

    This function is indended for use when restarting simulations, using previously computed
    solutions as initial conditions.
    """
    # Get receiving function space
    mixed_function_space = receiving_function.function_space()
    assigning_function_space = df.FunctionSpace(mixed_function_space.mesh(),
                                                "CG", 1)

    for subfunc_idx, assigning_sub_function in enumerate(
            assigning_func_iterator):
        assigner = df.FunctionAssigner(mixed_function_space.sub(subfunc_idx),
                                       assigning_function_space)
        assigner.assign(receiving_function.sub(subfunc_idx),
                        assigning_sub_function)
Exemplo n.º 4
0
    class MockProblem(ParametrizedProblem):
        def __init__(self, V, **kwargs):
            # Call parent
            ParametrizedProblem.__init__(
                self,
                os.path.join("test_eim_approximation_20_tempdir",
                             expression_type, basis_generation,
                             "mock_problem"))
            # Minimal subset of a ParametrizedDifferentialProblem
            self.V = V
            self._solution = Function(V)
            self.components = ["u", "s", "p"]
            # Parametrized function to be interpolated
            x = SpatialCoordinate(V.mesh())
            mu = SymbolicParameters(self, V, (-1., -1.))
            self.f00 = 1. / sqrt(
                pow(x[0] - mu[0], 2) + pow(x[1] - mu[1], 2) + 0.01)
            self.f01 = 1. / sqrt(
                pow(x[0] - mu[0], 4) + pow(x[1] - mu[1], 4) + 0.01)
            # Inner product
            f = TrialFunction(self.V)
            g = TestFunction(self.V)
            self.inner_product = assemble(inner(f, g) * dx)
            # Collapsed vector and space
            self.V0 = V.sub(0).collapse()
            self.V00 = V.sub(0).sub(0).collapse()
            self.V1 = V.sub(1).collapse()

        def name(self):
            return "MockProblem_20_" + expression_type + "_" + basis_generation

        def init(self):
            pass

        def solve(self):
            print("solving mock problem at mu =", self.mu)
            assert not hasattr(self, "_is_solving")
            self._is_solving = True
            f00 = project(self.f00, self.V00)
            f01 = project(self.f01, self.V00)
            assign(self._solution.sub(0).sub(0), f00)
            assign(self._solution.sub(0).sub(1), f01)
            delattr(self, "_is_solving")
            return self._solution
Exemplo n.º 5
0
def new_assign_ic(receiving_function: df.Function,
                  ic_generator: NonuniformIC,
                  degree: int = 1) -> None:
    """
    Assign receiving_function(x, y) <- `ic_function`(x, y), for x, in the mesh.

    Arguments:
        receiving_function: The function which is assigned the initial condition.
        ic_function_tuple: A tuple of python callables which return the initial condition for each
            point (x, y). The number of functions must match the number of subfunctions 
            in `receiving_function`.
    """
    mixed_func_space = receiving_function.function_space()
    mesh = mixed_func_space.mesh()
    V = df.FunctionSpace(mesh, "CG", 1)  # TODO: infer this somehow

    class InitialConditionInterpolator(df.UserExpression):
        def __init__(self, **kwargs):
            super().__init__(kwargs)
            self._ic_func = None

        def set_interpolator(self, interpolation_function):
            self._ic_func = interpolation_function

        def eval(self, value, x):
            value[0] = self._ic_func(x[0])  # TODO: 1D for now

    ic_interpolator = InitialConditionInterpolator()

    # Copy functions to be able to assign to them
    functions = receiving_function.split(deepcopy=True)

    for i, (f, ic_func) in enumerate(zip(functions, ic_generator())):

        class IC(df.Expression):
            def eval(self, value, x):
                value[0] = ic_func(x[0])  # TODO: 1D for now

        ic = IC(degree=degree)
        assigner = df.FunctionAssigner(mixed_func_space.sub(i), V)
        assigner.assign(receiving_function.sub(i), df.project(ic, V))
Exemplo n.º 6
0
def assign_ic_subdomain(
        *,
        brain: CoupledBrainModel,
        vs_prev: df.Function,
        value: float,
        subdomain_id: int,
        subfunction_index: int
) -> None:
    """
    Compute a function with `value` in the subdomain corresponding to `subdomain_id`.
    Assign this function to subfunction `subfunction_index` of vs_prev.
    """
    mesh = brain._mesh
    cell_function = brain._cell_function

    dX = df.Measure("dx", domain=mesh, subdomain_data=cell_function)

    V = df.FunctionSpace(mesh, "DG", 0)
    u = df.TrialFunction(V)
    v = df.TestFunction(V)
    sol = df.Function(V)
    sol.vector().zero()     # Make sure it is initialised to zero

    F = -u*v*dX(subdomain_id) + df.Constant(value)*v*dX(subdomain_id)
    a = df.lhs(F)
    L = df.rhs(F)

    A = df.assemble(a, keep_diagonal=True)
    A.ident_zeros()
    b = df.assemble(L)
    solver = df.KrylovSolver("cg", "petsc_amg")
    solver.set_operator(A)
    solver.solve(sol.vector(), b)

    VCG = df.FunctionSpace(mesh, "CG", 1)
    v_new = df.Function(VCG)
    v_new.interpolate(sol)

    Vp = vs_prev.function_space().sub(subfunction_index)
    merger = df.FunctionAssigner(Vp, VCG)
    merger.assign(vs_prev.sub(subfunction_index), v_new)
Exemplo n.º 7
0
def interpolate_ic(time: Sequence[float],
                   data: np.ndarray,
                   receiving_function: df.Function,
                   boundaries: Iterable[np.ndarray],
                   wavespeed: float = 1.0) -> None:
    mixed_func_space = receiving_function.function_space()
    mesh = mixed_func_space.mesh()
    V = df.FunctionSpace(mesh, "CG", 1)  # TODO: infer this somehow

    class InitialConditionInterpolator(df.UserExpression):
        def __init__(self, **kwargs):
            super().__init__(kwargs)
            self._ic_func = None

            self._nearest_edge_interpolator = NearestEdgeTree(boundaries)

        def set_interpolator(self, interpolation_function):
            self._ic_func = interpolation_function

        def eval(self, value, x):
            _, r = self._nearest_edge_interpolator.query(x)
            value[0] = self._ic_func(r / wavespeed)  # TODO: 1D for now
            # value[0] = r
            # value[0] = self._ic_func(x[0]/wavespeed)    # TODO: 1D for now

    ic_interpolator = InitialConditionInterpolator()

    # Copy functions to be able to assign to them
    subfunction_copy = receiving_function.split(deepcopy=True)
    for i, f in enumerate(subfunction_copy):
        # from IPython import embed; embed()
        # assert False
        ic_interpolator.set_interpolator(
            lambda x: np.interp(x, time, data[i, :]))
        assigner = df.FunctionAssigner(mixed_func_space.sub(i), V)
        assigner.assign(receiving_function.sub(i),
                        df.project(ic_interpolator, V))
Exemplo n.º 8
0
class VTV():
    """ Define Vectorial Total Variation regularization for 2 parameters """
    def __init__(self, Vm, parameters=[]):
        """ Vm = FunctionSpace for the parameters m1, and m2 """
        self.parameters = {}
        self.parameters['k'] = 1.0
        self.parameters['eps'] = 1e-2
        self.parameters['correctcost'] = True
        self.parameters.update(parameters)
        k = self.parameters['k']
        eps = self.parameters['eps']

        self.m1 = Function(Vm)
        self.m2 = Function(Vm)
        self.m1h = Function(Vm)
        self.m2h = Function(Vm)
        VmVm = createMixedFS(Vm, Vm)
        self.m12h = Function(VmVm)
        testm = TestFunction(VmVm)
        testm1, testm2 = testm
        trialm = TrialFunction(VmVm)
        trialm1, trialm2 = trialm

        # cost function
        normm1 = inner(nabla_grad(self.m1), nabla_grad(self.m1))
        normm2 = inner(nabla_grad(self.m2), nabla_grad(self.m2))
        TVnormsq = normm1 + normm2 + Constant(eps)
        TVnorm = sqrt(TVnormsq)
        if self.parameters['correctcost']:
            meshtmp = UnitSquareMesh(Vm.mesh().mpi_comm(), 10, 10)
            Vtmp = FunctionSpace(meshtmp, 'CG', 1)
            x = SpatialCoordinate(meshtmp)
            correctioncost = 1. / assemble(sqrt(4.0 * x[0] * x[0]) * dx)
            print '[VTV] correction cost with factor={}'.format(correctioncost)
        else:
            correctioncost = 1.0
        self.wkformcost = Constant(k * correctioncost) * TVnorm * dx

        # gradient
        gradm1 = Constant(k) / TVnorm * inner(nabla_grad(self.m1),
                                              nabla_grad(testm1)) * dx
        gradm2 = Constant(k) / TVnorm * inner(nabla_grad(self.m2),
                                              nabla_grad(testm2)) * dx
        self.gradm = gradm1 + gradm2

        # Hessian
        H11 = Constant(k)/TVnorm*(inner(nabla_grad(trialm1), nabla_grad(testm1)) - \
        inner(nabla_grad(testm1),nabla_grad(self.m1))* \
        inner(nabla_grad(self.m1), nabla_grad(trialm1))/TVnormsq)*dx
        H12 = -Constant(k)/(TVnorm*TVnormsq)*(inner(nabla_grad(testm1),nabla_grad(self.m1))* \
        inner(nabla_grad(self.m2), nabla_grad(trialm2)))*dx
        H21 = -Constant(k)/(TVnorm*TVnormsq)*(inner(nabla_grad(testm2),nabla_grad(self.m2))* \
        inner(nabla_grad(self.m1), nabla_grad(trialm1)))*dx
        H22 = Constant(k)/TVnorm*(inner(nabla_grad(trialm2), nabla_grad(testm2)) - \
        inner(nabla_grad(testm2),nabla_grad(self.m2))* \
        inner(nabla_grad(self.m2), nabla_grad(trialm2))/TVnormsq)*dx
        self.hessian = H11 + H12 + H21 + H22

        # for preconditioning
        self.amgprecond = amg_solver()
        M = assemble(inner(testm, trialm) * dx)
        factM = 1e-2 * k
        self.sMass = M * factM

    def isTV(self):
        return True

    def isPD(self):
        return False

    def costab(self, m1, m2):
        """ Compute value of cost function at (m1,m2) """
        setfct(self.m1, m1)
        setfct(self.m2, m2)
        return assemble(self.wkformcost)

    def costabvect(self, m1, m2):
        return self.costab(m1, m2)

    def gradab(self, m1, m2):
        """ returns gradient at (m1,m2) as a vector """
        setfct(self.m1, m1)
        setfct(self.m2, m2)
        return assemble(self.gradm)

    def gradabvect(self, m1, m2):
        return self.gradab(m1, m2)

    def assemble_hessianab(self, m1, m2):
        """ Assemble Hessian matrix for regularization """
        setfct(self.m1, m1)
        setfct(self.m2, m2)
        self.H = assemble(self.hessian)

    def hessianab(self, m1h, m2h):
        """ m1h, m2h = Vector(V) """
        setfct(self.m1h, m1h)
        setfct(self.m2h, m2h)
        assign(self.m12h.sub(0), self.m1h)
        assign(self.m12h.sub(1), self.m2h)
        return self.H * self.m12h.vector()

    def getprecond(self):
        """ precondition by TV + small fraction of mass matrix """
        solver = PETScKrylovSolver('cg', self.amgprecond)
        solver.parameters["maximum_iterations"] = 2000
        solver.parameters["relative_tolerance"] = 1e-24
        solver.parameters["absolute_tolerance"] = 1e-24
        solver.parameters["error_on_nonconvergence"] = True
        solver.parameters["nonzero_initial_guess"] = False
        solver.set_operator(self.H + self.sMass)
        return solver
Exemplo n.º 9
0
# deep copy. If no argument is given we will get a shallow copy. We want
# a deep copy for further computations on the coefficient vectors::

# Compute solution
w = Function(W)
solve(a == L,
      w,
      bcs,
      petsc_options={
          "ksp_type": "preonly",
          "pc_type": "lu",
          "pc_factor_mat_solver_type": "mumps"
      })

# Split the mixed solution and collapse
u = w.sub(0).collapse()
p = w.sub(1).collapse()

# We can calculate the :math:`L^2` norms of u and p as follows::

print("Norm of velocity coefficient vector: %.15g" % u.vector().norm())
print("Norm of pressure coefficient vector: %.15g" % p.vector().norm())

# Check pressure norm
pnorm = p.vector().norm()
assert np.isclose(pnorm, 4147.69457577)

# Finally, we can save and plot the solutions::

# Save solution in XDMF format
with XDMFFile(MPI.comm_world, "velocity.xdmf") as ufile_xdmf:
# Set-up Stokes Solve
forms_stokes = FormsStokes(mesh, mixedL, mixedG, alpha,
                           ds=ds).forms_multiphase(rho, ustar, dt, rho * nu, f)
ssc = StokesStaticCondensation(mesh, forms_stokes['A_S'], forms_stokes['G_S'],
                               forms_stokes['B_S'], forms_stokes['Q_S'],
                               forms_stokes['S_S'])

# Loop and output
step = 0
t = 0.

# Store tstep 0
assign(rho, rho0)
xdmf_rho.write_checkpoint(rho, "rho", t)
xdmf_u.write(Uh.sub(0), t)
xdmf_p.write(Uh.sub(1), t)
p.dump2file(mesh, fname_list, property_list, 'wb')
comm.barrier()

# Save some data in txt files
nc = mesh.num_entities_global(2)
npt = p.number_of_particles()

with open(meta_data, "w") as write_file:
    write_file.write("%-12s %-12s %-15s %-20s %-15s %-15s \n" %
                     ("Time step", "Number of steps", "Number of cells",
                      "Number of particles", "Projection", "Solver"))
    write_file.write("%-12.5g %-15d %-15d %-20d %-15s %-15s \n" %
                     (float(dt), num_steps, nc, npt, projection_type, solver))
Exemplo n.º 11
0
                               forms_stokes['B_S'], forms_stokes['Q_S'],
                               forms_stokes['S_S'])

# Set pressure in upper left corner to zero
bc1 = DirichletBC(mixedG.sub(1), Constant(0), Corner(xmin, ymax), "pointwise")
bcs = [bc1]

lstsq_u = l2projection(p, W_2, 2)

# Loop and output
step = 0
t = 0.

# Store at step 0
xdmf_rho.write(rho0, t)
xdmf_u.write(Uh.sub(0), t)
xdmf_p.write(Uh.sub(1), t)

p.dump2file(mesh, fname_list, property_list, 'wb')

dump_list = [0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]
with open(pressure_table, "wb") as PT:
    pickle.dump(dump_list, PT)

timer = Timer("[P] Total time consumed")
timer.start()

while step < num_steps:
    step += 1
    t += float(dt)
Exemplo n.º 12
0
class ObjectiveAcoustic(LinearOperator):
    """
    Computes data misfit, gradient and Hessian evaluation for the seismic
    inverse problem using acoustic wave data
    """
    # CONSTRUCTORS:
    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)


    def copy(self):
        """(hard) copy constructor"""
        newobj = self.__class__(self.PDE.copy())
        setfct(newobj.MG, self.MG)
        setfct(newobj.Grad, self.Grad)
        setfct(newobj.srchdir, self.srchdir)
        newobj.obsop = self.obsop
        newobj.dd = self.dd
        newobj.fwdsource = self.fwdsource
        newobj.srcindex = self.srcindex
        newobj.tsteps = self.tsteps
        return newobj


    # FORWARD PROBLEM + COST:
    #@profile
    def solvefwd(self, cost=False):
        self.PDE.set_fwd()
        self.solfwd, self.solpfwd, self.solppfwd = [], [], [] 
        self.Bp = []

        #TODO: make fwdsource iterable to return source term
        Ricker = self.fwdsource[0]
        srcv = self.fwdsource[2]
        for sii in self.srcindex:
            ptsrc = self.fwdsource[1][sii]
            def srcterm(tt):
                srcv.zero()
                srcv.axpy(Ricker(tt), ptsrc)
                return srcv
            self.PDE.ftime = srcterm
            solfwd, solpfwd, solppfwd,_ = self.PDE.solve()
            self.solfwd.append(solfwd)
            self.solpfwd.append(solpfwd)
            self.solppfwd.append(solppfwd)

            self.PDEcount += 1

            #TODO: come back and parallellize this too (over time steps)
            Bp = np.zeros((len(self.obsop.PtwiseObs.Points),len(solfwd)))
            for index, sol in enumerate(solfwd):
                setfct(self.p, sol[0])
                Bp[:,index] = self.obsop.obs(self.p)
            self.Bp.append(Bp)

        if cost:
            assert not self.dd == None, "Provide data observations to compute cost"
            self.cost_misfit_local = 0.0
            for Bp, dd in izip(self.Bp, self.dd):
                self.cost_misfit_local += self.obsop.costfct(\
                Bp[:,self.tsteps], dd[:,self.tsteps],\
                self.PDE.times[self.tsteps], self.factors[self.tsteps])
            self.cost_misfit = MPI.sum(self.mpicomm_global, self.cost_misfit_local)
            self.cost_misfit /= len(self.fwdsource[1])
            self.cost_reg = self.regularization.costab(self.PDE.a, self.PDE.b)
            self.cost = self.cost_misfit + self.alpha_reg*self.cost_reg
            if DEBUG:   
                print 'cost_misfit={}, cost_reg={}'.format(\
                self.cost_misfit, self.cost_reg)

    def solvefwd_cost(self):    self.solvefwd(True)


    # ADJOINT PROBLEM + GRADIENT:
    #@profile
    def solveadj(self, grad=False):
        self.PDE.set_adj()
        self.soladj, self.solpadj, self.solppadj = [], [], []

        for Bp, dd in zip(self.Bp, self.dd):
            self.obsop.assemble_rhsadj(Bp, dd, self.PDE.times, self.PDE.bc)
            self.PDE.ftime = self.obsop.ftimeadj
            soladj,solpadj,solppadj,_ = self.PDE.solve()
            self.soladj.append(soladj)
            self.solpadj.append(solpadj)
            self.solppadj.append(solppadj)

            self.PDEcount += 1

        if grad:
            self.MG.vector().zero()
            MGa_local, MGb_local = self.MG.split(deepcopy=True)
            MGav_local, MGbv_local = MGa_local.vector(), MGb_local.vector()

            t0, t1 = self.tsteps[0], self.tsteps[-1]+1

            for solfwd, solpfwd, solppfwd, soladj in \
            izip(self.solfwd, self.solpfwd, self.solppfwd, self.soladj):

                for fwd, fwdp, fwdpp, adj, fact in \
                izip(solfwd[t0:t1], solpfwd[t0:t1], solppfwd[t0:t1],\
                soladj[::-1][t0:t1], self.factors[t0:t1]):
                    setfct(self.q, adj[0])
                    if self.inverta:
                        # gradient a
                        setfct(self.p, fwdpp[0])
                        MGav_local.axpy(fact, self.get_gradienta()) 
                    if self.invertb:
                        # gradient b
                        setfct(self.p, fwd[0])
                        assemble(form=self.wkformgradb, tensor=self.wkformgradbout)
                        MGbv_local.axpy(fact, self.wkformgradbout)

                    if self.PDE.parameters['abc']:
                        setfct(self.p, fwdp[0])
                        if self.inverta:
                            assemble(form=self.wkformgradaABC, tensor=self.wkformgradaABCout)
                            MGav_local.axpy(0.5*fact, self.wkformgradaABCout)
                        if self.invertb:
                            assemble(form=self.wkformgradbABC, tensor=self.wkformgradbABCout)
                            MGbv_local.axpy(0.5*fact, self.wkformgradbABCout)

            MGa, MGb = self.MG.split(deepcopy=True)
            MPIAllReduceVector(MGav_local, MGa.vector(), self.mpicomm_global)
            MPIAllReduceVector(MGbv_local, MGb.vector(), self.mpicomm_global)
            setfct(MGa, MGa.vector()/len(self.fwdsource[1]))
            setfct(MGb, MGb.vector()/len(self.fwdsource[1]))
            self.MG.vector().zero()
            if self.inverta:
                assign(self.MG.sub(0), MGa)
            if self.invertb:
                assign(self.MG.sub(1), MGb)
            if DEBUG:
                print 'grad_misfit={}, grad_reg={}'.format(\
                self.MG.vector().norm('l2'),\
                self.regularization.gradab(self.PDE.a, self.PDE.b).norm('l2'))

            self.MG.vector().axpy(self.alpha_reg, \
            self.regularization.gradab(self.PDE.a, self.PDE.b))

            try:
                self.solverM.solve(self.Grad.vector(), self.MG.vector())
            except:
                # if |G|<<1, first residuals may diverge
                # caveat: Hope that ALL processes throw an exception
                pseudoGradnorm = np.sqrt(self.MGv.inner(self.MGv))
                if pseudoGradnorm < 1e-8:
                    print '*** Warning: Increasing divergence_limit for Mass matrix solver'
                    self.solverM.parameters["divergence_limit"] = 1e6
                    self.solverM.solve(self.Grad.vector(), self.MG.vector())
                else:
                    print '*** Error: Problem with Mass matrix solver'
                    sys.exit(1)

    def solveadj_constructgrad(self):   self.solveadj(True)

    def get_gradienta_lumped(self):
        return self.Mprime.get_gradient(self.p.vector(), self.q.vector())

    def get_gradienta_full(self):
        return assemble(self.wkformgrada)


    # HESSIAN:
    #@profile
    def ftimeincrfwd(self, tt):
        """ Compute rhs for incremental forward at time tt """
        try:
            index = int(np.where(isequal(self.PDE.times, tt, 1e-14))[0])
        except:
            print 'Error in ftimeincrfwd at time {}'.format(tt)
            print np.min(np.abs(self.PDE.times-tt))
            sys.exit(0)

        # bhat: bhat*grad(p).grad(qtilde)
#        assert isequal(tt, self.solfwdi[index][1], 1e-16)
        setfct(self.p, self.solfwdi[index][0])
        self.q.vector().zero()
        self.q.vector().axpy(1.0, self.C*self.p.vector())

        # ahat: ahat*p''*qtilde:
        setfct(self.p, self.solppfwdi[index][0])
        self.q.vector().axpy(1.0, self.get_incra(self.p.vector()))

        # ABC:
        if self.PDE.parameters['abc']:
            setfct(self.phat, self.solpfwdi[index][0])
            self.q.vector().axpy(0.5, self.Dp*self.phat.vector())

        return -1.0*self.q.vector()


    #@profile
    def ftimeincradj(self, tt):
        """ Compute rhs for incremental adjoint at time tt """
        try:
            indexf = int(np.where(isequal(self.PDE.times, tt, 1e-14))[0])
            indexa = int(np.where(isequal(self.PDE.times[::-1], tt, 1e-14))[0])
        except:
            print 'Error in ftimeincradj at time {}'.format(tt)
            print np.min(np.abs(self.PDE.times-tt))
            sys.exit(0)

        # B* B phat
#        assert isequal(tt, self.solincrfwd[indexf][1], 1e-16)
        setfct(self.phat, self.solincrfwd[indexf][0])
        self.qhat.vector().zero()
        self.qhat.vector().axpy(1.0, self.obsop.incradj(self.phat, tt))

        if not self.GN:
            # bhat: bhat*grad(ptilde).grad(v)
#            assert isequal(tt, self.soladji[indexa][1], 1e-16)
            setfct(self.q, self.soladji[indexa][0])
            self.qhat.vector().axpy(1.0, self.C*self.q.vector())

            # ahat: ahat*ptilde*q'':
            setfct(self.q, self.solppadji[indexa][0])
            self.qhat.vector().axpy(1.0, self.get_incra(self.q.vector()))

            # ABC:
            if self.PDE.parameters['abc']:
                setfct(self.phat, self.solpadji[indexa][0])
                self.qhat.vector().axpy(-0.5, self.Dp*self.phat.vector())

        return -1.0*self.qhat.vector()

    def get_incra_full(self, pvector):
        return self.E*pvector

    def get_incra_lumped(self, pvector):
        return self.Mprime.get_incremental(self.ahat.vector(), pvector)

        
    #@profile
    def mult(self, abhat, y):
        """
        mult(self, abhat, y): return y = Hessian * abhat
        inputs:
            y, abhat = Function(V).vector()
        """
        setfct(self.ab, abhat)
        ahat, bhat = self.ab.split(deepcopy=True)
        setfct(self.ahat, ahat)
        setfct(self.bhat, bhat)
        if not self.inverta:
            self.ahat.vector().zero()
        if not self.invertb:
            self.bhat.vector().zero()

        self.C = assemble(self.wkformrhsincrb)
        if not self.PDE.parameters['lumpM']:    self.E = assemble(self.wkformrhsincra)
        if self.PDE.parameters['abc']:  self.Dp = assemble(self.wkformincrrhsABC)

        t0, t1 = self.tsteps[0], self.tsteps[-1]+1

        # Compute Hessian*abhat
        self.ab.vector().zero()
        yaF_local, ybF_local = self.ab.split(deepcopy=True)
        ya_local, yb_local = yaF_local.vector(), ybF_local.vector()

        # iterate over sources:
        for self.solfwdi, self.solpfwdi, self.solppfwdi, \
        self.soladji, self.solpadji, self.solppadji \
        in izip(self.solfwd, self.solpfwd, self.solppfwd, \
        self.soladj, self.solpadj, self.solppadj):
            # incr. fwd
            self.PDE.set_fwd()
            self.PDE.ftime = self.ftimeincrfwd
            self.solincrfwd,solpincrfwd,self.solppincrfwd,_ = self.PDE.solve()
            self.PDEcount += 1

            # incr. adj
            self.PDE.set_adj()
            self.PDE.ftime = self.ftimeincradj
            solincradj,_,_,_ = self.PDE.solve()
            self.PDEcount += 1

            # assemble Hessian-vect product:
            for fwd, adj, fwdp, incrfwdp, \
            fwdpp, incrfwdpp, incrfwd, incradj, fact \
            in izip(self.solfwdi[t0:t1], self.soladji[::-1][t0:t1],\
            self.solpfwdi[t0:t1], solpincrfwd[t0:t1], \
            self.solppfwdi[t0:t1], self.solppincrfwd[t0:t1],\
            self.solincrfwd[t0:t1], solincradj[::-1][t0:t1], self.factors[t0:t1]):
#                ttf, tta, ttf2 = incrfwd[1], incradj[1], fwd[1]
#                assert isequal(ttf, tta, 1e-16), 'tfwd={}, tadj={}, reldiff={}'.\
#                format(ttf, tta, abs(ttf-tta)/ttf)
#                assert isequal(ttf, ttf2, 1e-16), 'tfwd={}, tadj={}, reldiff={}'.\
#                format(ttf, ttf2, abs(ttf-ttf2)/ttf)

                setfct(self.q, adj[0])
                setfct(self.qhat, incradj[0])
                if self.invertb:
                    # Hessian b
                    setfct(self.p, fwd[0])
                    setfct(self.phat, incrfwd[0])
                    if self.GN:
                        yb_local.axpy(fact, assemble(self.wkformhessbGN))
                    else:
                        yb_local.axpy(fact, assemble(self.wkformhessb))

                if self.inverta:
                    # Hessian a
                    setfct(self.p, fwdpp[0])
                    setfct(self.phat, incrfwdpp[0])
                    ya_local.axpy(fact, self.get_hessiana())

                if self.PDE.parameters['abc']:
                    if not self.GN:
                        setfct(self.p, incrfwdp[0])
                        if self.inverta:
                            ya_local.axpy(0.5*fact, assemble(self.wkformgradaABC))
                        if self.invertb:
                            yb_local.axpy(0.5*fact, assemble(self.wkformgradbABC))

                    setfct(self.p, fwdp[0])
                    setfct(self.q, incradj[0])
                    if self.inverta:
                        ya_local.axpy(0.5*fact, assemble(self.wkformgradaABC))
                    if self.invertb:
                        yb_local.axpy(0.5*fact, assemble(self.wkformgradbABC))

                    if not self.GN:
                        setfct(self.q, adj[0])
                        if self.inverta:
                            ya_local.axpy(0.25*fact, assemble(self.wkformhessaABC))
                        if self.invertb:
                            yb_local.axpy(0.25*fact, assemble(self.wkformhessbABC))

        yaF, ybF = self.ab.split(deepcopy=True)
        MPIAllReduceVector(ya_local, yaF.vector(), self.mpicomm_global)
        MPIAllReduceVector(yb_local, ybF.vector(), self.mpicomm_global)
        self.ab.vector().zero()
        if self.inverta:
            assign(self.ab.sub(0), yaF)
        if self.invertb:
            assign(self.ab.sub(1), ybF)
        y.zero()
        y.axpy(1.0/len(self.fwdsource[1]), self.ab.vector())
        if DEBUG:
            print 'Hess_misfit={}, Hess_reg={}'.format(\
            y.norm('l2'),\
            self.regularization.hessianab(self.ahat.vector(),\
            self.bhat.vector()).norm('l2'))

        y.axpy(self.alpha_reg, \
        self.regularization.hessianab(self.ahat.vector(), self.bhat.vector()))

    def get_hessiana_full(self):
        if self.GN:
            return assemble(self.wkformhessaGN)
        else:
            return assemble(self.wkformhessa)

    def get_hessiana_lumped(self):
        if self.GN:
            return self.Mprime.get_gradient(self.p.vector(), self.qhat.vector())
        else:
            return self.Mprime.get_gradient(self.phat.vector(), self.q.vector()) +\
            self.Mprime.get_gradient(self.p.vector(), self.qhat.vector())


    def assemble_hessian(self):
        self.regularization.assemble_hessianab(self.PDE.a, self.PDE.b)



    # SETTERS + UPDATE:
    def update_PDE(self, parameters): self.PDE.update(parameters)

    def update_m(self, medparam):
        """ medparam contains both med parameters """
        setfct(self.ab, medparam)
        a, b = self.ab.split(deepcopy=True)
        self.update_PDE({'a':a, 'b':b})

    def backup_m(self): 
        """ back-up current value of med param a and b """
        assign(self.m_bkup.sub(0), self.PDE.a)
        assign(self.m_bkup.sub(1), self.PDE.b)

    def restore_m(self):    
        """ restore backed-up values of a and b """
        a, b = self.m_bkup.split(deepcopy=True)
        self.update_PDE({'a':a, 'b':b})

    def mediummisfit(self, target_medium):
        """
        Compute medium misfit at current position
        """
        assign(self.ab.sub(0), self.PDE.a)
        assign(self.ab.sub(1), self.PDE.b)
        try:
            diff = self.ab.vector() - target_medium.vector()
        except:
            diff = self.ab.vector() - target_medium
        Md = self.Mass*diff
        self.ab.vector().zero()
        self.ab.vector().axpy(1.0, Md)
        Mda, Mdb = self.ab.split(deepcopy=True)
        self.ab.vector().zero()
        self.ab.vector().axpy(1.0, diff)
        da, db = self.ab.split(deepcopy=True)
        medmisfita = np.sqrt(da.vector().inner(Mda.vector()))
        medmisfitb = np.sqrt(db.vector().inner(Mdb.vector()))
        return medmisfita, medmisfitb 

    def compare_ab_global(self):
        """
        Check that med param (a, b) are the same across all proc
        """
        assign(self.ab.sub(0), self.PDE.a)
        assign(self.ab.sub(1), self.PDE.b)
        ab_recv = self.ab.vector().copy()
        normabloc = np.linalg.norm(self.ab.vector().array())
        MPIAllReduceVector(self.ab.vector(), ab_recv, self.mpicomm_global)
        ab_recv /= MPI.size(self.mpicomm_global)
        diff = ab_recv - self.ab.vector()
        reldiff = np.linalg.norm(diff.array())/normabloc
        assert reldiff < 2e-16, 'Diff in (a,b) across proc: {:.2e}'.format(reldiff)



    # GETTERS:
    def getmbkup(self):         return self.m_bkup.vector()
    def getMG(self):            return self.MGv
    def getprecond(self):
        if self.PC == 'prior':
            return self.regularization.getprecond()
        elif self.PC == 'bfgs':
            return self.bfgsop
        else:
            print 'Wrong keyword for choice of preconditioner'
            sys.exit(1)



    # SOLVE INVERSE PROBLEM
    #@profile
    def inversion(self, initial_medium, target_medium, parameters_in=[], \
    boundsLS=None, myplot=None):
        """ 
        Solve inverse problem with that objective function 
        parameters:
            solverNS = solver for Newton system ('steepest', 'Newton', 'BFGS')
            retolgrad = relative tolerance for stopping criterion (grad)
            abstolgrad = absolute tolerance for stopping criterion (grad)
            tolcost = tolerance for stopping criterion (cost)
            maxiterNewt = max nb of Newton iterations
            nbGNsteps = nb of Newton steps with GN Hessian
            maxtolcg = max value of the tolerance for CG solver
            checkab = nb of steps in-between check of param
            inexactCG = [bool] inexact CG solver or exact CG
            isprint = [bool] print results to screen
            avgPC = [bool] average Preconditioned step over all proc in CG
            PC = choice of preconditioner ('prior', or 'bfgs')
        """
        parameters = {}
        parameters['solverNS']          = 'Newton'
        parameters['reltolgrad']        = 1e-10
        parameters['abstolgrad']        = 1e-14
        parameters['tolcost']           = 1e-24
        parameters['maxiterNewt']       = 100
        parameters['nbGNsteps']         = 10
        parameters['maxtolcg']          = 0.5
        parameters['checkab']           = 10
        parameters['inexactCG']         = True
        parameters['isprint']           = False
        parameters['avgPC']             = True
        parameters['PC']                = 'prior'
        parameters['BFGS_damping']      = 0.2
        parameters['memory_limit']      = 50
        parameters['H0inv']             = 'Rinv'

        parameters.update(parameters_in)

        solverNS = parameters['solverNS']
        isprint = parameters['isprint']
        maxiterNewt = parameters['maxiterNewt']
        reltolgrad = parameters['reltolgrad']
        abstolgrad = parameters['abstolgrad']
        tolcost = parameters['tolcost']
        nbGNsteps = parameters['nbGNsteps']
        checkab = parameters['checkab']
        avgPC = parameters['avgPC']
        if parameters['inexactCG']:
            maxtolcg = parameters['maxtolcg']
        else:
            maxtolcg = 1e-12
        if solverNS == 'BFGS':
            maxtolcg = -1.0
        self.PC = parameters['PC']
        # BFGS (preconditioner or solver):
        if self.PC == 'bfgs' or solverNS == 'BFGS':
            self.bfgsop = BFGS_operator(parameters)
            H0inv = self.bfgsop.parameters['H0inv']
        else:
            self.bfgsop = []
        self.PDEcount = 0   # reset

        if isprint:
            print '\t{:12s} {:10s} {:12s} {:12s} {:12s} {:16s}\t\t\t    {:10s} {:12s} {:10s} {:10s}'.format(\
            'iter', 'cost', 'misfit', 'reg', '|G|', 'medmisf', 'a_ls', 'tol_cg', 'n_cg', 'PDEsolves')

        a0, b0 = initial_medium.split(deepcopy=True)
        self.update_PDE({'a':a0, 'b':b0})
        self._plotab(myplot, 'init')

        Mab = self.Mass*target_medium.vector()
        self.ab.vector().zero()
        self.ab.vector().axpy(1.0, Mab)
        Ma, Mb = self.ab.split(deepcopy=True)
        at, bt = target_medium.split(deepcopy=True)
        atnorm = np.sqrt(at.vector().inner(Ma.vector()))
        btnorm = np.sqrt(bt.vector().inner(Mb.vector()))

        alpha = -1.0    # dummy value for print outputs

        self.solvefwd_cost()
        for it in xrange(maxiterNewt):
            MGv_old = self.MGv.copy()
            self.solveadj_constructgrad()
            gradnorm = np.sqrt(self.MGv.inner(self.Grad.vector()))
            if it == 0:   gradnorm0 = gradnorm

            medmisfita, medmisfitb = self.mediummisfit(target_medium)

            self._plotab(myplot, str(it))
            self._plotgrad(myplot, str(it))

            # Stopping criterion (gradient)
            if gradnorm < gradnorm0*reltolgrad or gradnorm < abstolgrad:
                print '{:12d} {:12.4e} {:12.2e} {:12.2e} {:11.4e} {:10.2e} ({:4.1f}%) {:10.2e} ({:4.1f}%)'.\
                format(it, self.cost, self.cost_misfit, self.cost_reg, gradnorm,\
                medmisfita, 100.0*medmisfita/atnorm, medmisfitb, 100.0*medmisfitb/btnorm),
                print '{:11.3f} {:12.2} {:10} {:10d}'.format(\
                alpha, "", "", self.PDEcount)
                if isprint:
                    print '\nGradient sufficiently reduced'
                    print 'Optimization converged'
                return

            # Assemble Hessian of regularization for nonlinear regularization:
            self.assemble_hessian()

            # Update BFGS approx (s, y, H0)
            if self.PC == 'bfgs' or solverNS == 'BFGS':
                if it > 0:
                    s = self.srchdir.vector() * alpha
                    y = self.MGv - MGv_old
                    theta = self.bfgsop.update(s, y)
                else:
                    theta = 1.0

                if H0inv == 'Rinv':
                    self.bfgsop.set_H0inv(self.regularization.getprecond())
                elif H0inv == 'Minv':
                    print 'H0inv = Minv? That is not a good idea'
                    sys.exit(1)

            # Compute search direction and plot
            tolcg = min(maxtolcg, np.sqrt(gradnorm/gradnorm0))
            self.GN = (it < nbGNsteps)  # use GN or full Hessian?
            # most time spent here:
            if avgPC:
                cgiter, cgres, cgid = compute_searchdirection(self,
                {'method':solverNS, 'tolcg':tolcg,\
                'max_iter':250+1250*(self.GN==False)},\
                comm=self.mpicomm_global, BFGSop=self.bfgsop)
            else:
                cgiter, cgres, cgid = compute_searchdirection(self,
                {'method':solverNS, 'tolcg':tolcg,\
                'max_iter':250+1250*(self.GN==False)}, BFGSop=self.bfgsop)

            # addt'l safety: zero-out entries of 'srchdir' corresponding to
            # param that are not inverted for
            if not self.inverta*self.invertb:
                srcha, srchb = self.srchdir.split(deepcopy=True)
                if not self.inverta:
                    srcha.vector().zero()
                    assign(self.srchdir.sub(0), srcha)
                if not self.invertb:
                    srchb.vector().zero()
                    assign(self.srchdir.sub(1), srchb)
            self._plotsrchdir(myplot, str(it))

            if isprint:
                print '{:12d} {:12.4e} {:12.2e} {:12.2e} {:11.4e} {:10.2e} ({:4.1f}%) {:10.2e} ({:4.1f}%)'.\
                format(it, self.cost, self.cost_misfit, self.cost_reg, gradnorm,\
                medmisfita, 100.0*medmisfita/atnorm, medmisfitb, 100.0*medmisfitb/btnorm),
                print '{:11.3f} {:12.2e} {:10d} {:10d}'.format(\
                alpha, tolcg, cgiter, self.PDEcount)

            # Backtracking line search
            cost_old = self.cost
            statusLS, LScount, alpha = bcktrcklinesearch(self, parameters, boundsLS)
            cost = self.cost
            # Perform line search for dual variable (TV-PD):
            if self.PD: 
                self.regularization.update_w(self.srchdir.vector(), alpha)

            if it%checkab == 0:
                self.compare_ab_global()

            # Stopping criterion (LS)
            if not statusLS:
                if isprint:
                    print '\nLine search failed'
                    print 'Optimization aborted'
                return

            # Stopping criterion (cost)
            if np.abs(cost-cost_old)/np.abs(cost_old) < tolcost:
                if isprint:
                    print '\nCost function stagnates'
                    print 'Optimization aborted'
                return

        if isprint:
            print '\nMaximum number of Newton iterations reached'
            print 'Optimization aborted'




    # PLOTS:
    def _plotab(self, myplot, index):
        """ plot media during inversion """
        if not myplot == None:
            if self.invparam == 'a' or self.invparam == 'ab':
                myplot.set_varname('a'+index)
                myplot.plot_vtk(self.PDE.a)
            if self.invparam == 'b' or self.invparam == 'ab':
                myplot.set_varname('b'+index)
                myplot.plot_vtk(self.PDE.b)

    def _plotgrad(self, myplot, index):
        """ plot grad during inversion """
        if not myplot == None:
            if self.invparam == 'a':
                myplot.set_varname('Grad_a'+index)
                myplot.plot_vtk(self.Grad)
            elif self.invparam == 'b':
                myplot.set_varname('Grad_b'+index)
                myplot.plot_vtk(self.Grad)
            elif self.invparam == 'ab':
                Ga, Gb = self.Grad.split(deepcopy=True)
                myplot.set_varname('Grad_a'+index)
                myplot.plot_vtk(Ga)
                myplot.set_varname('Grad_b'+index)
                myplot.plot_vtk(Gb)

    def _plotsrchdir(self, myplot, index):
        """ plot srchdir during inversion """
        if not myplot == None:
            if self.invparam == 'a':
                myplot.set_varname('srchdir_a'+index)
                myplot.plot_vtk(self.srchdir)
            elif self.invparam == 'b':
                myplot.set_varname('srchdir_b'+index)
                myplot.plot_vtk(self.srchdir)
            elif self.invparam == 'ab':
                Ga, Gb = self.srchdir.split(deepcopy=True)
                myplot.set_varname('srchdir_a'+index)
                myplot.plot_vtk(Ga)
                myplot.set_varname('srchdir_b'+index)
                myplot.plot_vtk(Gb)



    # SHOULD BE REMOVED:
    def set_abc(self, mesh, class_bc_abc, lumpD):  
        self.PDE.set_abc(mesh, class_bc_abc, lumpD)
    def init_vector(self, x, dim):
        self.Mass.init_vector(x, dim)
    def getmcopyarray(self):    return self.getmcopy().array()
    def getMGarray(self):       return self.MGv.array()
    def setsrcterm(self, ftime):    self.PDE.ftime = ftime
Exemplo n.º 13
0
    # Solve Stokes
    t1 = Timer("[P] Stokes assemble")
    ssc.assemble_global_system(True)
    del t1
    t1 = Timer("[P] Stokes solve")
    for bc in bcs:
        ssc.apply_boundary(bc)
    ssc.solve_problem(Uhbar.cpp_object(), Uh.cpp_object(), "mumps", "default")
    del t1

    t1 = Timer("[P] Assign and output")
    # Needed for particle advection
    assign(Udiv, Uh.sub(0))

    # Needed for constrained map
    assign(ubar0_a, Uhbar.sub(0))
    assign(u0_a, ustar)
    assign(duh00, duh0)
    assign(duh0, project(Uh.sub(0) - ustar, W_2))

    p.increment(Udiv.cpp_object(), ustar.cpp_object(),
                np.array([1, 2], dtype=np.uintp), theta_p, step)

    if step == 2:
        theta_L.assign(theta_next)

    # Probably can be combined into one file?
    xdmf_u.write(Uh.sub(0), t)
    xdmf_p.write(Uh.sub(1), t)
    del t1
Exemplo n.º 14
0
class NuclearNormformula():
    def __init__(self, mesh, parameters=[], isprint=False):
        self.parameters = {}
        self.parameters['eps'] = 0.0
        self.parameters['k'] = 1.0
        self.parameters['correctcost'] = True
        self.parameters.update(parameters)
        eps = self.parameters['eps']
        k = self.parameters['k']

        self.V = FunctionSpace(mesh, 'CG', 1)
        self.tmp1, self.tmp2 = Function(self.V), Function(self.V)

        self.VV = VectorFunctionSpace(mesh, 'CG', 1, 2)
        self.m = Function(self.VV)
        self.mtest = TestFunction(self.VV)
        self.mtrial = TrialFunction(self.VV)
        self.m1, self.m2 = split(self.m)
        self.mh = Function(self.VV)

        normg1 = inner(nabla_grad(self.m1), nabla_grad(self.m1))
        normg2 = inner(nabla_grad(self.m2), nabla_grad(self.m2))
        if self.parameters['correctcost']:
            meshtmp = UnitSquareMesh(mesh.mpi_comm(), 10, 10)
            Vtmp = FunctionSpace(meshtmp, 'CG', 1)
            x = SpatialCoordinate(meshtmp)
            self.correctioncost = 1. / assemble(sqrt(4.0 * x[0] * x[0]) * dx)
            print '[NuclearNormformula] Correction cost with factor={}'.format(
                self.correctioncost)
        else:
            self.correctioncost = 1.0
        self.cost = 1./np.sqrt(2.0) * Constant(k) * (\
        sqrt(normg1 + normg2 + Constant(np.sqrt(eps)) +
        sqrt((normg1 - normg2)**2 + Constant(eps) +
        4.0*inner(nabla_grad(self.m1), nabla_grad(self.m2))**2))
        + sqrt(normg1 + normg2 + Constant(np.sqrt(eps)*(1.0+1e-15)) -
        sqrt((normg1 - normg2)**2 + Constant(eps) +
        4.0*inner(nabla_grad(self.m1), nabla_grad(self.m2))**2)))*dx

        self.grad = derivative(self.cost, self.m, self.mtest)

        self.hessian = derivative(self.grad, self.m, self.mtrial)

        M = assemble(inner(self.mtest, self.mtrial) * dx)
        factM = 1e-2 * k
        self.sMass = M * factM

        if isprint:
            print '[NuclearNormformula] eps={}, k={}'.format(eps, k)

        self.amgprecond = amg_solver()

    def isTV(self):
        return False

    def isPD(self):
        return False

    def costab(self, m1, m2):
        assign(self.m.sub(0), m1)
        assign(self.m.sub(1), m2)
        return assemble(self.cost) * self.correctioncost

    def costabvect(self, m1, m2):
        setfct(self.tmp1, m1)
        setfct(self.tmp2, m2)
        return self.costab(self.tmp1, self.tmp2)

    def gradab(self, m1, m2):
        assign(self.m.sub(0), m1)
        assign(self.m.sub(1), m2)
        return assemble(self.grad)

    def gradabvect(self, m1, m2):
        setfct(self.tmp1, m1)
        setfct(self.tmp2, m2)
        return self.gradab(self.tmp1, self.tmp2)

    def assemble_hessianab(self, m1, m2):
        setfct(self.tmp1, m1)
        setfct(self.tmp2, m2)
        assign(self.m.sub(0), self.tmp1)
        assign(self.m.sub(1), self.tmp2)
        self.H = assemble(self.hessian)

    def hessianab(self, m1h, m2h):
        """ m1h, m2h = Vector(V) """
        setfct(self.tmp1, m1h)
        setfct(self.tmp2, m2h)
        assign(self.mh.sub(0), self.tmp1)
        assign(self.mh.sub(1), self.tmp2)
        return self.H * self.mh.vector()

    def getprecond(self):
        """ precondition by TV + small fraction of mass matrix """
        #TODO: does not appear to be a great way to apply preconditioner (DIVERGED_ITS)
        solver = PETScKrylovSolver('cg', self.amgprecond)
        solver.parameters["maximum_iterations"] = 3000
        solver.parameters["relative_tolerance"] = 1e-24
        solver.parameters["absolute_tolerance"] = 1e-24
        solver.parameters["error_on_nonconvergence"] = True
        solver.parameters["nonzero_initial_guess"] = False
        self.precond = self.H + self.sMass
        solver.set_operator(self.precond)
        return solver
Exemplo n.º 15
0
class V_TVPD():
    """ Definite Vectorial Total Variation regularization from Total Variation class """
    def __init__(self, Vm, parameters=[]):
        """ Vm = FunctionSpace for the parameters m1, and m2 """
        self.parameters = {}
        self.parameters['k'] = 1.0
        self.parameters['eps'] = 1e-2
        self.parameters['rescaledradiusdual'] = 1.0
        self.parameters['print'] = False
        self.parameters['amg'] = 'default'
        self.parameters['nb_param'] = 2
        self.parameters['use_i'] = False
        self.parameters.update(parameters)

        n = self.parameters['nb_param']
        use_i = self.parameters['use_i']
        assert ((not use_i) * (n > 2))

        Vw = FunctionSpace(Vm.mesh(), 'DG', 0)
        if not use_i:
            VmVm = createMixedFS(Vm, Vm)
            VwVw = createMixedFS(Vw, Vw)
        else:
            if self.parameters['print']:
                print '[V_TVPD] Using createMixedFSi'
            Vms, Vws = [], []
            for ii in range(n):
                Vms.append(Vm)
                Vws.append(Vw)
            VmVm = createMixedFSi(Vms)
            VwVw = createMixedFSi(Vws)
        self.parameters['Vm'] = VmVm
        self.parameters['Vw'] = VwVw

        self.regTV = TVPD(self.parameters)

        if not use_i:
            self.m1, self.m2 = Function(Vm), Function(Vm)
            self.m = Function(VmVm)

        self.w_loc = Function(VwVw)
        self.factorw = Function(Vw)
        self.factorww = Function(VwVw)

        tmp = interpolate(Constant("1.0"), Vw)
        self.one = tmp.vector()

    def isTV(self):
        return True

    def isPD(self):
        return True

    def costab(self, m1, m2):
        assign(self.m.sub(0), m1)
        assign(self.m.sub(1), m2)
        return self.regTV.cost(self.m)

    def costabvect(self, m1, m2):
        setfct(self.m1, m1)
        setfct(self.m2, m2)
        return self.costab(self.m1, self.m2)

    def costabvecti(self, m):
        return self.regTV.cost(m)

    def gradab(self, m1, m2):
        assign(self.m.sub(0), m1)
        assign(self.m.sub(1), m2)
        return self.regTV.grad(self.m)

    def gradabvect(self, m1, m2):
        setfct(self.m1, m1)
        setfct(self.m2, m2)
        return self.gradab(self.m1, self.m2)

    def gradabvecti(self, m):
        return self.regTV.grad(m)

    def assemble_hessianab(self, m1, m2):
        setfct(self.m1, m1)
        setfct(self.m2, m2)
        assign(self.m.sub(0), self.m1)
        assign(self.m.sub(1), self.m2)
        self.regTV.assemble_hessian(self.m)

    def assemble_hessianabi(self, m):
        self.regTV.assemble_hessian(m)

    def hessianab(self, m1h, m2h):
        """ m1h, m2h = Vector(V) """
        setfct(self.m1, m1h)
        setfct(self.m2, m2h)
        assign(self.m.sub(0), self.m1)
        assign(self.m.sub(1), self.m2)
        return self.regTV.hessian(self.m.vector())

    def hessianabi(self, mh):
        return self.regTV.hessian(mh)

    def getprecond(self):
        return self.regTV.getprecond()

    def compute_what(self, mhat):
        self.regTV.compute_what(mhat)

    #TODO: modify to accept n>=2
    def update_w(self, mhat, alphaLS, compute_what=True):
        """ update dual variable in direction what 
        and update re-scaled version """
        # Update wx and wy
        if compute_what: self.compute_what(mhat)
        self.regTV.wx.vector().axpy(alphaLS, self.regTV.wxhat.vector())
        self.regTV.wy.vector().axpy(alphaLS, self.regTV.wyhat.vector())

        # Update rescaled variables
        rescaledradiusdual = self.parameters['rescaledradiusdual']
        # wx**2
        as_backend_type(self.regTV.wxsq).vec().pointwiseMult(\
            as_backend_type(self.regTV.wx.vector()).vec(),\
            as_backend_type(self.regTV.wx.vector()).vec())
        # wy**2
        as_backend_type(self.regTV.wysq).vec().pointwiseMult(\
            as_backend_type(self.regTV.wy.vector()).vec(),\
            as_backend_type(self.regTV.wy.vector()).vec())
        # |w|
        self.w_loc.vector().zero()
        self.w_loc.vector().axpy(1.0, self.regTV.wxsq + self.regTV.wysq)
        normw1, normw2 = self.w_loc.split(deepcopy=True)
        normw = normw1.vector() + normw2.vector()
        as_backend_type(normw).vec().sqrtabs()
        # |w|/r
        as_backend_type(normw).vec().pointwiseDivide(\
            as_backend_type(normw).vec(),\
            as_backend_type(self.one*rescaledradiusdual).vec())
        # max(1.0, |w|/r)
        count = pointwiseMaxCount(self.factorw.vector(), normw, 1.0)
        # rescale wx and wy
        assign(self.factorww.sub(0), self.factorw)
        assign(self.factorww.sub(1), self.factorw)
        as_backend_type(self.regTV.wxrs.vector()).vec().pointwiseDivide(\
            as_backend_type(self.regTV.wx.vector()).vec(),\
            as_backend_type(self.factorww.vector()).vec())
        as_backend_type(self.regTV.wyrs.vector()).vec().pointwiseDivide(\
            as_backend_type(self.regTV.wy.vector()).vec(),\
            as_backend_type(self.factorww.vector()).vec())

        minf = self.factorw.vector().min()
        maxf = self.factorw.vector().max()
        if self.parameters['print']:
            print ('[V_TVPD] perc. dual entries rescaled={:.2f} %, ' +\
            'min(factorw)={}, max(factorw)={}').format(\
            100.*float(count)/self.factorw.vector().size(), minf, maxf)
Exemplo n.º 16
0
class V_TV():
    """ Definite Vectorial Total Variation regularization from Total Variation class """
    def __init__(self, Vm, parameters=[]):
        """ Vm = FunctionSpace for the parameters m1, and m2 """
        self.parameters = {}
        self.parameters['k'] = 1.0
        self.parameters['eps'] = 1e-2
        self.parameters['amg'] = 'default'
        self.parameters['nb_param'] = 2
        self.parameters['use_i'] = False
        self.parameters['print'] = False
        self.parameters.update(parameters)

        n = self.parameters['nb_param']
        use_i = self.parameters['use_i']
        assert not ((not use_i) * (n > 2))

        if not use_i:
            VmVm = createMixedFS(Vm, Vm)
        else:
            if self.parameters['print']:
                print '[V_TV] Using createMixedFSi'
            Vms = []
            for ii in range(n):
                Vms.append(Vm)
            VmVm = createMixedFSi(Vms)
        self.parameters['Vm'] = VmVm

        self.regTV = TV(self.parameters)

        if not use_i:
            self.m1, self.m2 = Function(Vm), Function(Vm)
            self.m = Function(VmVm)

    def isTV(self):
        return True

    def isPD(self):
        return False

    def costab(self, m1, m2):
        assign(self.m.sub(0), m1)
        assign(self.m.sub(1), m2)
        return self.regTV.cost(self.m)

    def costabvect(self, m1, m2):
        setfct(self.m1, m1)
        setfct(self.m2, m2)
        return self.costab(self.m1, self.m2)

    def costabvecti(self, m):
        return self.regTV.cost(m)

    def gradab(self, m1, m2):
        assign(self.m.sub(0), m1)
        assign(self.m.sub(1), m2)
        return self.regTV.grad(self.m)

    def gradabvect(self, m1, m2):
        setfct(self.m1, m1)
        setfct(self.m2, m2)
        return self.gradab(self.m1, self.m2)

    def gradabvecti(self, m):
        return self.regTV.grad(m)

    def assemble_hessianab(self, m1, m2):
        setfct(self.m1, m1)
        setfct(self.m2, m2)
        assign(self.m.sub(0), self.m1)
        assign(self.m.sub(1), self.m2)
        self.regTV.assemble_hessian(self.m)

    def assemble_hessianabi(self, m):
        self.regTV.assemble_hessian(m)

    def hessianab(self, m1h, m2h):
        """ m1h, m2h = Vector(V) """
        setfct(self.m1, m1h)
        setfct(self.m2, m2h)
        assign(self.m.sub(0), self.m1)
        assign(self.m.sub(1), self.m2)
        return self.regTV.hessian(self.m.vector())

    def hessianabi(self, mh):
        return self.regTV.hessian(mh)

    def getprecond(self):
        return self.regTV.getprecond()
Exemplo n.º 17
0
    def solve(self, problem):
        self.problem = problem
        doSave = problem.doSave
        save_this_step = False
        onlyVel = problem.saveOnlyVel
        dt = self.metadata['dt']

        nu = Constant(self.problem.nu)
        # TODO check proper use of watches
        self.tc.init_watch('init', 'Initialization', True, count_to_percent=False)
        self.tc.init_watch('rhs', 'Assembled right hand side', True, count_to_percent=True)
        self.tc.init_watch('updateBC', 'Updated velocity BC', True, count_to_percent=True)
        self.tc.init_watch('applybc1', 'Applied velocity BC 1st step', True, count_to_percent=True)
        self.tc.init_watch('applybc3', 'Applied velocity BC 3rd step', True, count_to_percent=True)
        self.tc.init_watch('applybcP', 'Applied pressure BC or othogonalized rhs', True, count_to_percent=True)
        self.tc.init_watch('assembleMatrices', 'Initial matrix assembly', False, count_to_percent=True)
        self.tc.init_watch('solve 1', 'Running solver on 1st step', True, count_to_percent=True)
        self.tc.init_watch('solve 2', 'Running solver on 2nd step', True, count_to_percent=True)
        self.tc.init_watch('solve 3', 'Running solver on 3rd step', True, count_to_percent=True)
        self.tc.init_watch('solve 4', 'Running solver on 4th step', True, count_to_percent=True)
        self.tc.init_watch('assembleA1', 'Assembled A1 matrix (without stabiliz.)', True, count_to_percent=True)
        self.tc.init_watch('assembleA1stab', 'Assembled A1 stabilization', True, count_to_percent=True)
        self.tc.init_watch('next', 'Next step assignments', True, count_to_percent=True)
        self.tc.init_watch('saveVel', 'Saved velocity', True)

        self.tc.start('init')

        # Define function spaces (P2-P1)
        mesh = self.problem.mesh
        self.V = VectorFunctionSpace(mesh, "Lagrange", 2)  # velocity
        self.Q = FunctionSpace(mesh, "Lagrange", 1)  # pressure
        self.PS = FunctionSpace(mesh, "Lagrange", 2)  # partial solution (must be same order as V)
        self.D = FunctionSpace(mesh, "Lagrange", 1)   # velocity divergence space
        if self.bc == 'lagrange':
            L = FunctionSpace(mesh, "R", 0)
            QL = self.Q*L

        problem.initialize(self.V, self.Q, self.PS, self.D)

        # Define trial and test functions
        u = TrialFunction(self.V)
        v = TestFunction(self.V)
        if self.bc == 'lagrange':
            (pQL, rQL) = TrialFunction(QL)
            (qQL, lQL) = TestFunction(QL)
        else:
            p = TrialFunction(self.Q)
            q = TestFunction(self.Q)

        n = FacetNormal(mesh)
        I = Identity(u.geometric_dimension())

        # Initial conditions: u0 velocity at previous time step u1 velocity two time steps back p0 previous pressure
        [u1, u0, p0] = self.problem.get_initial_conditions([{'type': 'v', 'time': -dt},
                                                          {'type': 'v', 'time': 0.0},
                                                          {'type': 'p', 'time': 0.0}])

        if doSave:
            problem.save_vel(False, u0, 0.0)
            problem.save_vel(True, u0, 0.0)

        u_ = Function(self.V)         # current tentative velocity
        u_cor = Function(self.V)         # current corrected velocity
        if self.bc == 'lagrange':
            p_QL = Function(QL)    # current pressure or pressure help function from rotation scheme
            pQ = Function(self.Q)     # auxiliary function for conversion between QL.sub(0) and Q
        else:
            p_ = Function(self.Q)         # current pressure or pressure help function from rotation scheme
        p_mod = Function(self.Q)      # current modified pressure from rotation scheme

        # Define coefficients
        k = Constant(self.metadata['dt'])
        f = Constant((0, 0, 0))

        # Define forms
        # step 1: Tentative velocity, solve to u_
        u_ext = 1.5*u0 - 0.5*u1  # extrapolation for convection term

        # Stabilisation
        h = CellSize(mesh)
        # CBC delta:
        if self.cbcDelta:
            delta = Constant(self.stabCoef)*h/(sqrt(inner(u_ext, u_ext))+h)
        else:
            delta = Constant(self.stabCoef)*h**2/(2*nu*k + k*h*inner(u_ext, u_ext)+h**2)

        if self.use_full_SUPG:
            v1 = v + delta*0.5*k*dot(grad(v), u_ext)
            parameters['form_compiler']['quadrature_degree'] = 6
        else:
            v1 = v

        def nonlinearity(function):
            if self.use_ema:
               return 2*inner(dot(sym(grad(function)), u_ext), v1) * dx + inner(div(function)*u_ext, v1) * dx
                # return 2*inner(dot(sym(grad(function)), u_ext), v) * dx + inner(div(u_ext)*function, v) * dx
                # QQ implement this way?
            else:
                return inner(dot(grad(function), u_ext), v1) * dx

        def diffusion(fce):
            if self.useLaplace:
                return nu*inner(grad(fce), grad(v1)) * dx
            else:
                form = inner(nu * 2 * sym(grad(fce)), sym(grad(v1))) * dx
                if self.bcv == 'CDN':
                    # IMP will work only if p=0 on output, or we must add term
                    # inner(p0*n, v)*problem.get_outflow_measure_form() to avoid boundary layer
                    return form
                if self.bcv == 'LAP':
                    return form - inner(nu*dot(grad(fce).T, n), v1)  * problem.get_outflow_measure_form()
                if self.bcv == 'DDN':
                    # IMP will work only if p=0 on output, or we must add term
                    # inner(p0*n, v)*problem.get_outflow_measure_form() to avoid boundary layer
                    return form  # additional term must be added to non-constant part

        def pressure_rhs():
            if self.useLaplace or self.bcv == 'LAP':
                return inner(p0, div(v1)) * dx - inner(p0*n, v1) * problem.get_outflow_measure_form()
                # NT term inner(inner(p, n), v) is 0 when p=0 on outflow
            else:
                return inner(p0, div(v1)) * dx

        a1_const = (1./k)*inner(u, v1)*dx + diffusion(0.5*u)
        a1_change = nonlinearity(0.5*u)
        if self.bcv == 'DDN':
            # IMP Problem: Does not penalize influx for current step, only for the next one
            # IMP this can lead to oscilation: DDN correct next step, but then u_ext is OK so in next step DDN is not used, leading to new influx...
            # u and u_ext cannot be switched, min_value is nonlinear function
            a1_change += -0.5*min_value(Constant(0.), inner(u_ext, n))*inner(u, v1)*problem.get_outflow_measure_form()
            # IMP works only with uflacs compiler

        L1 = (1./k)*inner(u0, v1)*dx - nonlinearity(0.5*u0) - diffusion(0.5*u0) + pressure_rhs()
        if self.bcv == 'DDN':
            L1 += 0.5*min_value(0., inner(u_ext, n))*inner(u0, v1)*problem.get_outflow_measure_form()

        # Non-consistent SUPG stabilisation
        if self.stabilize and not self.use_full_SUPG:
            # a1_stab = delta*inner(dot(grad(u), u_ext), dot(grad(v), u_ext))*dx
            a1_stab = 0.5*delta*inner(dot(grad(u), u_ext), dot(grad(v), u_ext))*dx(None, {'quadrature_degree': 6})
            # NT optional: use Crank Nicolson in stabilisation term: change RHS
            # L1 += -0.5*delta*inner(dot(grad(u0), u_ext), dot(grad(v), u_ext))*dx(None, {'quadrature_degree': 6})

        outflow_area = Constant(problem.outflow_area)
        need_outflow = Constant(0.0)
        if self.useRotationScheme:
            # Rotation scheme
            if self.bc == 'lagrange':
                F2 = inner(grad(pQL), grad(qQL))*dx + (1./k)*qQL*div(u_)*dx + pQL*lQL*dx + qQL*rQL*dx
            else:
                F2 = inner(grad(p), grad(q))*dx + (1./k)*q*div(u_)*dx
        else:
            # Projection, solve to p_
            if self.bc == 'lagrange':
                F2 = inner(grad(pQL - p0), grad(qQL))*dx + (1./k)*qQL*div(u_)*dx + pQL*lQL*dx + qQL*rQL*dx
            else:
                if self.forceOutflow and problem.can_force_outflow:
                    info('Forcing outflow.')
                    F2 = inner(grad(p - p0), grad(q))*dx + (1./k)*q*div(u_)*dx
                    for m in problem.get_outflow_measures():
                        F2 += (1./k)*(1./outflow_area)*need_outflow*q*m
                else:
                    F2 = inner(grad(p - p0), grad(q))*dx + (1./k)*q*div(u_)*dx
        a2, L2 = system(F2)

        # step 3: Finalize, solve to u_
        if self.useRotationScheme:
            # Rotation scheme
            if self.bc == 'lagrange':
                F3 = (1./k)*inner(u - u_, v)*dx + inner(grad(p_QL.sub(0)), v)*dx
            else:
                F3 = (1./k)*inner(u - u_, v)*dx + inner(grad(p_), v)*dx
        else:
            if self.bc == 'lagrange':
                F3 = (1./k)*inner(u - u_, v)*dx + inner(grad(p_QL.sub(0) - p0), v)*dx
            else:
                F3 = (1./k)*inner(u - u_, v)*dx + inner(grad(p_ - p0), v)*dx
        a3, L3 = system(F3)

        if self.useRotationScheme:
            # Rotation scheme: modify pressure
            if self.bc == 'lagrange':
                pr = TrialFunction(self.Q)
                qr = TestFunction(self.Q)
                F4 = (pr - p0 - p_QL.sub(0) + nu*div(u_))*qr*dx
            else:
                F4 = (p - p0 - p_ + nu*div(u_))*q*dx
            # TODO zkusit, jestli to nebude rychlejsi? nepocitat soustavu, ale p.assign(...), nutno project(div(u),Q) coz je pocitani podobne soustavy
            # TODO zkusit v project zadat solver_type='lu' >> primy resic by mel byt efektivnejsi
            a4, L4 = system(F4)

        # Assemble matrices
        self.tc.start('assembleMatrices')
        A1_const = assemble(a1_const)  # need to be here, so A1 stays one Python object during repeated assembly
        A1_change = A1_const.copy()  # copy to get matrix with same sparse structure (data will be overwriten)
        if self.stabilize and not self.use_full_SUPG:
            A1_stab = A1_const.copy()  # copy to get matrix with same sparse structure (data will be overwriten)
        A2 = assemble(a2)
        A3 = assemble(a3)
        if self.useRotationScheme:
            A4 = assemble(a4)
        self.tc.end('assembleMatrices')

        if self.solvers == 'direct':
            self.solver_vel_tent = LUSolver('mumps')
            self.solver_vel_cor = LUSolver('mumps')
            self.solver_p = LUSolver('umfpack')
            if self.useRotationScheme:
                self.solver_rot = LUSolver('umfpack')
        else:
            # NT not needed, chosen not to use hypre_parasails
            # if self.prec_v == 'hypre_parasails':  # in FEniCS 1.6.0 inaccessible using KrylovSolver class
            #     self.solver_vel_tent = PETScKrylovSolver('gmres')   # PETSc4py object
            #     self.solver_vel_tent.ksp().getPC().setType('hypre')
            #     PETScOptions.set('pc_hypre_type', 'parasails')
            #     # this is global setting, but preconditioners for pressure solvers are set by their constructors
            # else:
            self.solver_vel_tent = KrylovSolver('gmres', self.prec_v)   # nonsymetric > gmres
            # IMP cannot use 'ilu' in parallel (choose different default option)
            self.solver_vel_cor = KrylovSolver('cg', 'hypre_amg')   # nonsymetric > gmres
            self.solver_p = KrylovSolver('cg', self.prec_p)          # symmetric > CG
            if self.useRotationScheme:
                self.solver_rot = KrylovSolver('cg', self.prec_p)

        solver_options = {'monitor_convergence': True, 'maximum_iterations': 1000, 'nonzero_initial_guess': True}
        # 'nonzero_initial_guess': True   with  solver.solbe(A, u, b) means that
        # Solver will use anything stored in u as an initial guess

        # Get the nullspace if there are no pressure boundary conditions
        foo = Function(self.Q)     # auxiliary vector for setting pressure nullspace
        if self.bc in ['nullspace', 'nullspace_s']:
            null_vec = Vector(foo.vector())
            self.Q.dofmap().set(null_vec, 1.0)
            null_vec *= 1.0/null_vec.norm('l2')
            self.null_space = VectorSpaceBasis([null_vec])
            if self.bc == 'nullspace':
                as_backend_type(A2).set_nullspace(self.null_space)

        # apply global options for Krylov solvers
        self.solver_vel_tent.parameters['relative_tolerance'] = 10 ** (-self.precision_rel_v_tent)
        self.solver_vel_tent.parameters['absolute_tolerance'] = 10 ** (-self.precision_abs_v_tent)
        self.solver_vel_cor.parameters['relative_tolerance'] = 10E-12
        self.solver_vel_cor.parameters['absolute_tolerance'] = 10E-4
        self.solver_p.parameters['relative_tolerance'] = 10**(-self.precision_p)
        self.solver_p.parameters['absolute_tolerance'] = 10E-10
        if self.useRotationScheme:
            self.solver_rot.parameters['relative_tolerance'] = 10**(-self.precision_p)
            self.solver_rot.parameters['absolute_tolerance'] = 10E-10

        if self.solvers == 'krylov':
            for solver in [self.solver_vel_tent, self.solver_vel_cor, self.solver_p, self.solver_rot] if \
                    self.useRotationScheme else [self.solver_vel_tent, self.solver_vel_cor, self.solver_p]:
                for key, value in solver_options.items():
                    try:
                        solver.parameters[key] = value
                    except KeyError:
                        info('Invalid option %s for KrylovSolver' % key)
                        return 1
                solver.parameters['preconditioner']['structure'] = 'same'
                # matrices A2-A4 do not change, so we can reuse preconditioners

        self.solver_vel_tent.parameters['preconditioner']['structure'] = 'same_nonzero_pattern'
        # matrix A1 changes every time step, so change of preconditioner must be allowed

        if self.bc == 'lagrange':
            fa = FunctionAssigner(self.Q, QL.sub(0))

        # boundary conditions
        bcu, bcp = problem.get_boundary_conditions(self.bc == 'outflow', self.V, self.Q)
        self.tc.end('init')
        # Time-stepping
        info("Running of Incremental pressure correction scheme n. 1")
        ttime = self.metadata['time']
        t = dt
        step = 1
        while t < (ttime + dt/2.0):
            info("t = %f" % t)
            self.problem.update_time(t, step)
            if self.MPI_rank == 0:
                problem.write_status_file(t)

            if doSave:
                save_this_step = problem.save_this_step

            # DDN debug
            # u_ext_in = assemble(inner(u_ext, n)*problem.get_outflow_measure_form())
            # DDN_triggered = assemble(min_value(Constant(0.), inner(u_ext, n))*problem.get_outflow_measure_form())
            # print('DDN: u_ext*n dSout = ', u_ext_in)
            # print('DDN: negative part of u_ext*n dSout = ', DDN_triggered)

            # assemble matrix (it depends on solution)
            self.tc.start('assembleA1')
            assemble(a1_change, tensor=A1_change)  # assembling into existing matrix is faster than assembling new one
            A1 = A1_const.copy()  # we dont want to change A1_const
            A1.axpy(1, A1_change, True)
            self.tc.end('assembleA1')
            self.tc.start('assembleA1stab')
            if self.stabilize and not self.use_full_SUPG:
                assemble(a1_stab, tensor=A1_stab)  # assembling into existing matrix is faster than assembling new one
                A1.axpy(1, A1_stab, True)
            self.tc.end('assembleA1stab')

            # Compute tentative velocity step
            begin("Computing tentative velocity")
            self.tc.start('rhs')
            b = assemble(L1)
            self.tc.end('rhs')
            self.tc.start('applybc1')
            [bc.apply(A1, b) for bc in bcu]
            self.tc.end('applybc1')
            try:
                self.tc.start('solve 1')
                self.solver_vel_tent.solve(A1, u_.vector(), b)
                self.tc.end('solve 1')
                if save_this_step:
                    self.tc.start('saveVel')
                    problem.save_vel(True, u_, t)
                    self.tc.end('saveVel')
                if save_this_step and not onlyVel:
                    problem.save_div(True, u_)
                problem.compute_err(True, u_, t)
                problem.compute_div(True, u_)
            except RuntimeError as inst:
                problem.report_fail(t)
                return 1
            end()

            # DDN debug
            # u_ext_in = assemble(inner(u_, n)*problem.get_outflow_measure_form())
            # DDN_triggered = assemble(min_value(Constant(0.), inner(u_, n))*problem.get_outflow_measure_form())
            # print('DDN: u_tent*n dSout = ', u_ext_in)
            # print('DDN: negative part of u_tent*n dSout = ', DDN_triggered)

            if self.useRotationScheme:
                begin("Computing tentative pressure")
            else:
                begin("Computing pressure")
            if self.forceOutflow and problem.can_force_outflow:
                out = problem.compute_outflow(u_)
                info('Tentative outflow: %f' % out)
                n_o = -problem.last_inflow-out
                info('Needed outflow: %f' % n_o)
                need_outflow.assign(n_o)
            self.tc.start('rhs')
            b = assemble(L2)
            self.tc.end('rhs')
            self.tc.start('applybcP')
            [bc.apply(A2, b) for bc in bcp]
            if self.bc in ['nullspace', 'nullspace_s']:
                self.null_space.orthogonalize(b)
            self.tc.end('applybcP')
            try:
                self.tc.start('solve 2')
                if self.bc == 'lagrange':
                    self.solver_p.solve(A2, p_QL.vector(), b)
                else:
                    self.solver_p.solve(A2, p_.vector(), b)
                self.tc.end('solve 2')
            except RuntimeError as inst:
                problem.report_fail(t)
                return 1
            if self.useRotationScheme:
                foo = Function(self.Q)
                if self.bc == 'lagrange':
                    fa.assign(pQ, p_QL.sub(0))
                    foo.assign(pQ + p0)
                else:
                    foo.assign(p_+p0)
                problem.averaging_pressure(foo)
                if save_this_step and not onlyVel:
                    problem.save_pressure(True, foo)
            else:
                if self.bc == 'lagrange':
                    fa.assign(pQ, p_QL.sub(0))
                    problem.averaging_pressure(pQ)
                    if save_this_step and not onlyVel:
                        problem.save_pressure(False, pQ)
                else:
                    # we do not want to change p=0 on outflow, it conflicts with do-nothing conditions
                    foo = Function(self.Q)
                    foo.assign(p_)
                    problem.averaging_pressure(foo)
                    if save_this_step and not onlyVel:
                        problem.save_pressure(False, foo)
            end()

            begin("Computing corrected velocity")
            self.tc.start('rhs')
            b = assemble(L3)
            self.tc.end('rhs')
            if not self.B:
                self.tc.start('applybc3')
                [bc.apply(A3, b) for bc in bcu]
                self.tc.end('applybc3')
            try:
                self.tc.start('solve 3')
                self.solver_vel_cor.solve(A3, u_cor.vector(), b)
                self.tc.end('solve 3')
                problem.compute_err(False, u_cor, t)
                problem.compute_div(False, u_cor)
            except RuntimeError as inst:
                problem.report_fail(t)
                return 1
            if save_this_step:
                self.tc.start('saveVel')
                problem.save_vel(False, u_cor, t)
                self.tc.end('saveVel')
            if save_this_step and not onlyVel:
                problem.save_div(False, u_cor)
            end()

            # DDN debug
            # u_ext_in = assemble(inner(u_cor, n)*problem.get_outflow_measure_form())
            # DDN_triggered = assemble(min_value(Constant(0.), inner(u_cor, n))*problem.get_outflow_measure_form())
            # print('DDN: u_cor*n dSout = ', u_ext_in)
            # print('DDN: negative part of u_cor*n dSout = ', DDN_triggered)

            if self.useRotationScheme:
                begin("Rotation scheme pressure correction")
                self.tc.start('rhs')
                b = assemble(L4)
                self.tc.end('rhs')
                try:
                    self.tc.start('solve 4')
                    self.solver_rot.solve(A4, p_mod.vector(), b)
                    self.tc.end('solve 4')
                except RuntimeError as inst:
                    problem.report_fail(t)
                    return 1
                problem.averaging_pressure(p_mod)
                if save_this_step and not onlyVel:
                    problem.save_pressure(False, p_mod)
                end()

            # compute functionals (e. g. forces)
            problem.compute_functionals(u_cor,
                                        p_mod if self.useRotationScheme else (pQ if self.bc == 'lagrange' else p_), t)

            # Move to next time step
            self.tc.start('next')
            u1.assign(u0)
            u0.assign(u_cor)
            u_.assign(u_cor)  # use corretced velocity as initial guess in first step

            if self.useRotationScheme:
                p0.assign(p_mod)
            else:
                if self.bc == 'lagrange':
                    p0.assign(pQ)
                else:
                    p0.assign(p_)

            t = round(t + dt, 6)  # round time step to 0.000001
            step += 1
            self.tc.end('next')

        info("Finished: Incremental pressure correction scheme n. 1")
        problem.report()
        return 0
u = Function(ME)

V = FunctionSpace(mesh, P1)
an_int = interpolate(
    Expression(
        '((pow((x[0] - 7.5E-3), 2) + pow((x[1] - 7.5E-3), 2)) <= pow(2.5E-3, 2)) ? 0.4142 : 1.0',
        degree=1), V)
ca_int = interpolate(
    Expression(
        '((pow((x[0] - 7.5E-3), 2) + pow((x[1] - 7.5E-3), 2)) <= pow(2.5E-3, 2)) ? 2.4142 : 1.0',
        degree=1), V)
psi_int = interpolate(
    Expression(
        '((pow((x[0] - 7.5E-3), 2) + pow((x[1] - 7.5E-3), 2)) <= pow(2.5E-3, 2)) ? -22.252E-3 : 0.0',
        degree=1), V)
assign(u.sub(0), an_int)
assign(u.sub(1), ca_int)
assign(u.sub(2), psi_int)

an, ca, psi = split(u)
van, vca, vpsi = TestFunctions(ME)

Fan = D_an * (-inner(grad(an), grad(van)) * dx -
              Farad / R / Temp * z_an * an * inner(grad(psi), grad(van)) * dx)
Fca = D_ca * (-inner(grad(ca), grad(vca)) * dx -
              Farad / R / Temp * z_ca * ca * inner(grad(psi), grad(vca)) * dx)
Fpsi = inner(grad(psi), grad(vpsi)) * dx - (Farad / (eps0 * epsR)) * (
    z_an * an + z_ca * ca + z_fc * fc_function) * vpsi * dx

F = Fpsi + Fan + Fca
Exemplo n.º 19
0
def solve(
        mesh,
        W_element, P_element, Q_element,
        u0, p0, theta0,
        kappa, rho, mu, cp,
        g, extra_force,
        heat_source,
        u_bcs, p_bcs,
        theta_dirichlet_bcs,
        theta_neumann_bcs,
        dx_submesh, ds_submesh
        ):
    # First do a fixed_point iteration. This is usually quite robust and leads
    # to a point from where Newton can converge reliably.
    u0, p0, theta0 = solve_fixed_point(
        mesh,
        W_element, P_element, Q_element,
        theta0,
        kappa, rho, mu, cp,
        g, extra_force,
        heat_source,
        u_bcs, p_bcs,
        theta_dirichlet_bcs,
        theta_neumann_bcs,
        my_dx=dx_submesh,
        my_ds=ds_submesh,
        max_iter=100,
        tol=1.0e-8
        )

    WPQ = FunctionSpace(
        mesh, MixedElement([W_element, P_element, Q_element])
        )
    uptheta0 = Function(WPQ)

    # Initial guess
    assign(uptheta0.sub(0), u0)
    assign(uptheta0.sub(1), p0)
    assign(uptheta0.sub(2), theta0)

    rho_const = rho(_average(theta0))

    stokes_heat_problem = StokesHeat(
        WPQ,
        kappa, rho, rho_const, mu, cp,
        g, extra_force,
        heat_source,
        u_bcs, p_bcs,
        theta_dirichlet_bcs=theta_dirichlet_bcs,
        theta_neumann_bcs=theta_neumann_bcs,
        my_dx=dx_submesh,
        my_ds=ds_submesh
        )

    # solver = FixedPointSolver()
    from dolfin import PETScSNESSolver
    solver = PETScSNESSolver()
    # http://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/SNES/SNESType.html
    solver.parameters['method'] = 'newtonls'
    # The Jacobian system for Stokes (+heat) are hard to solve.
    # Use LU for now.
    solver.parameters['linear_solver'] = 'lu'
    solver.parameters['maximum_iterations'] = 100
    # TODO tighten tolerance. might not always work though...
    solver.parameters['absolute_tolerance'] = 1.0e-3
    solver.parameters['relative_tolerance'] = 0.0
    solver.parameters['report'] = True

    solver.solve(stokes_heat_problem, uptheta0.vector())

    # u0, p0, theta0 = split(uptheta0)
    # Create a *deep* copy of u0, p0, theta0 to be able to deal with them
    # as actually separate entities vectors.
    u0, p0, theta0 = uptheta0.split(deepcopy=True)
    return u0, p0, theta0
Exemplo n.º 20
0
def solve(mesh, W_element, P_element, Q_element, u0, p0, theta0, kappa, rho,
          mu, cp, g, extra_force, heat_source, u_bcs, p_bcs,
          theta_dirichlet_bcs, theta_neumann_bcs, dx_submesh, ds_submesh):
    # First do a fixed_point iteration. This is usually quite robust and leads
    # to a point from where Newton can converge reliably.
    u0, p0, theta0 = solve_fixed_point(mesh,
                                       W_element,
                                       P_element,
                                       Q_element,
                                       theta0,
                                       kappa,
                                       rho,
                                       mu,
                                       cp,
                                       g,
                                       extra_force,
                                       heat_source,
                                       u_bcs,
                                       p_bcs,
                                       theta_dirichlet_bcs,
                                       theta_neumann_bcs,
                                       my_dx=dx_submesh,
                                       my_ds=ds_submesh,
                                       max_iter=100,
                                       tol=1.0e-8)

    WPQ = FunctionSpace(mesh, MixedElement([W_element, P_element, Q_element]))
    uptheta0 = Function(WPQ)

    # Initial guess
    assign(uptheta0.sub(0), u0)
    assign(uptheta0.sub(1), p0)
    assign(uptheta0.sub(2), theta0)

    rho_const = rho(_average(theta0))

    stokes_heat_problem = StokesHeat(WPQ,
                                     kappa,
                                     rho,
                                     rho_const,
                                     mu,
                                     cp,
                                     g,
                                     extra_force,
                                     heat_source,
                                     u_bcs,
                                     p_bcs,
                                     theta_dirichlet_bcs=theta_dirichlet_bcs,
                                     theta_neumann_bcs=theta_neumann_bcs,
                                     my_dx=dx_submesh,
                                     my_ds=ds_submesh)

    # solver = FixedPointSolver()
    from dolfin import PETScSNESSolver
    solver = PETScSNESSolver()
    # http://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/SNES/SNESType.html
    solver.parameters['method'] = 'newtonls'
    # The Jacobian system for Stokes (+heat) are hard to solve.
    # Use LU for now.
    solver.parameters['linear_solver'] = 'lu'
    solver.parameters['maximum_iterations'] = 100
    # TODO tighten tolerance. might not always work though...
    solver.parameters['absolute_tolerance'] = 1.0e-3
    solver.parameters['relative_tolerance'] = 0.0
    solver.parameters['report'] = True

    solver.solve(stokes_heat_problem, uptheta0.vector())

    # u0, p0, theta0 = split(uptheta0)
    # Create a *deep* copy of u0, p0, theta0 to be able to deal with them
    # as actually separate entities vectors.
    u0, p0, theta0 = uptheta0.split(deepcopy=True)
    return u0, p0, theta0
Exemplo n.º 21
0
class EllipticSNFluxModule(flux_module.FluxModule):  
  """
  Flux solver based on elliptic discrete ordinates formulation
  """
  
  class AngularTensors:
    def __init__(self, angular_quad, L):
      from transport_data import angular_tensors_ext_module

      i,j,k1,k2,p,q = ufl.indices(6)

      tensors = angular_tensors_ext_module.AngularTensors(angular_quad, L)
      self.Y = ufl.as_tensor( numpy.reshape(tensors.Y(), tensors.shape_Y()) )
      self.Q = ufl.as_tensor( numpy.reshape(tensors.Q(), tensors.shape_Q()) )
      self.QT = ufl.transpose(self.Q)
      self.Qt = ufl.as_tensor( numpy.reshape(tensors.Qt(), tensors.shape_Qt()) )
      self.QtT = ufl.as_tensor( self.Qt[k1,p,i], (p,i,k1) )
      self.G = ufl.as_tensor( numpy.reshape(tensors.G(), tensors.shape_G()) )
      self.T = ufl.as_tensor( numpy.reshape(tensors.T(), tensors.shape_T()) )
      self.Wp = ufl.as_vector( angular_quad.get_pw() )
      self.W = ufl.diag(self.Wp)
      
  def __init__(self, PD, DD, verbosity):
    """
    Constructor
    :param ProblemData PD: Problem information and various mesh-region <-> xs-material mappings
    :param SNDiscretization DD: Discretization data
    :param int verbosity: Verbosity level.
    """

    self.max_group_GS_it = parameters["flux_module"]["group_GS"]["max_niter"]
    self.group_GS = self.max_group_GS_it > 0  

    try:
      PD.eigenproblem
    except AttributeError:
      PD.distribute_material_data(DD.cell_regions, DD.M)

    if PD.eigenproblem and self.group_GS:
      print "Group Gauss-Seidel for eigenproblem not yet supported - switching to all-group coupled solution method."
      self.group_GS = False

    if DD.G == 1:
      self.group_GS = True
      self.max_group_GS_it = 1

    DD.init_solution_spaces(self.group_GS)

    super(EllipticSNFluxModule, self).__init__(PD, DD, verbosity)

    if PD.fixed_source_problem:
      self.vals_Q = numpy.empty(self.DD.ndof,dtype='float64')

    if self.verb > 1: print0("Defining coefficient functions and tensors")

    if self.DD.V is self.DD.Vpsi1 or DD.G == 1:
      # shallow copies of trial/test functions - allows unified treatment of both mixed/single versions
      self.u = [self.u]*self.DD.G
      self.v = [self.v]*self.DD.G

      self.slns_mg = [self.sln]
      for g in range(1, self.DD.G):
        self.slns_mg.append(Function(self.DD.Vpsi1))

    else:
      self.u = split(self.u)
      self.v = split(self.v)

      # self.group_assigner = []
      # for g in range(self.DD.G):
      #   self.group_assigner.append(FunctionAssigner(self.DD.V.sub(g), self.DD.Vpsi1))

    # auxiliary single-group angular fluxes (used for monitoring convergence of the group GS iteration and computing
    # the true forward/adjoint angular fluxes)
    self.aux_slng = Function(self.DD.Vpsi1)

    # multigroup angular fluxes
    self.psi_mg = []
    for g in range(self.DD.G):
      self.psi_mg.append(Function(self.DD.Vpsi1))

    # multigroup adjoint angular fluxes
    self.adj_psi_mg = []
    for g in range(self.DD.G):
      self.adj_psi_mg.append(Function(self.DD.Vpsi1))

    self.D = Function(self.DD.V0)

    self.L = PD.scattering_order-1
    self.tensors = self.AngularTensors(self.DD.angular_quad, self.L)

    self.C = numpy.empty(self.L+1, Function)
    self.S = numpy.empty(self.L+1, Function)
    for l in range(self.L+1):
      self.C[l] = Function(self.DD.V0)
      self.S[l] = Function(self.DD.V0)

    for var in {"angular_flux", "adjoint_angular_flux"}:
      self.vis_files[var] = \
      [
        [
          File(os.path.join(self.vis_folder, "{}_g{}_m{}.pvd".format(var,g,m)), "compressed") for m in range(self.DD.M)
        ]
        for g in range(self.DD.G)
      ]

    self.__define_boundary_terms()

  # TODO: Reflective boundary conditions  
  # noinspection PyAttributeOutsideInit,PyUnboundLocalVariable,PyTypeChecker
  def __define_boundary_terms(self):
    if self.verb > 2: print0("Defining boundary terms")

    self.bnd_vector_form = numpy.empty(self.DD.G, dtype=object)
    self.bnd_matrix_form = numpy.empty(self.DD.G, dtype=object)

    n = FacetNormal(self.DD.mesh)
    i,p,q = ufl.indices(3)
    
    natural_boundaries = self.BC.vacuum_boundaries.union(self.BC.incoming_fluxes.keys())

    nonzero = lambda x: numpy.all(x > 0)
    nonzero_inc_flux = any(map(nonzero, self.BC.incoming_fluxes.values()))

    if nonzero_inc_flux and not self.fixed_source_problem:
      coupled_solver_error(__file__,
                   "define boundary terms",
                   "Incoming flux specified for an eigenvalue problem"+\
                   "(Q must be given whenever phi_inc is; it may possibly be zero everywhere)")

    for g in range(self.DD.G):
      self.bnd_vector_form[g] = ufl.zero()
      self.bnd_matrix_form[g] = ufl.zero()

    if natural_boundaries:
      try:
        ds = Measure("ds")[self.DD.boundaries]
      except TypeError:
        coupled_solver_error(__file__,
                             "define boundary terms",
                             "File assigning boundary indices to facets required if vacuum or incoming flux boundaries "
                             "are specified.")
          
      for bnd_idx in natural_boundaries:
        # NOTE: The following doesn't work because ufl.abs requires a function
        #
        #for g in range(self.DD.G):
        #  self.bnd_matrix_form[g] += \
        #    abs(self.tensors.G[p,q,i]*n[i])*self.u[g][q]*self.v[g][p]*ds(bnd_idx)
        #
        # NOTE: Instead, the following explicit loop has to be used; this makes tensors.G unneccessary
        #
        for pp in range(self.DD.M):
          omega_p_dot_n = self.DD.ordinates_matrix[i,pp]*n[i]

          for g in range(self.DD.G):
            self.bnd_matrix_form[g] += \
              abs(omega_p_dot_n)*self.tensors.Wp[pp]*self.u[g][pp]*self.v[g][pp]*ds(bnd_idx)
    
      if nonzero_inc_flux:
        for pp in range(self.DD.M):
          omega_p_dot_n = self.DD.ordinates_matrix[i,pp]*n[i]
          
          for bnd_idx, psi_inc in self.BC.incoming_fluxes.iteritems():
              
            if psi_inc.shape != (self.DD.M, self.DD.G):
              coupled_solver_error(__file__,
                           "define boundary terms",
                           "Incoming flux with incorrect number of groups and directions specified: "+
                           "{}, expected ({}, {})".format(psi_inc.shape, self.DD.M, self.DD.G))
            
            
            for g in range(self.DD.G):
              self.bnd_vector_form[g] += \
                ufl.conditional(omega_p_dot_n < 0,
                                omega_p_dot_n*self.tensors.Wp[pp]*psi_inc[pp,g]*self.v[g][pp]*ds(bnd_idx),
                                ufl.zero())  # FIXME: This assumes zero adjoint outgoing flux
    else: # Apply vacuum b.c. everywhere
      ds = Measure("ds")

      for pp in range(self.DD.M):
        omega_p_dot_n = self.DD.ordinates_matrix[i,pp]*n[i]

        for g in range(self.DD.G):
          self.bnd_matrix_form[g] += abs(omega_p_dot_n)*self.tensors.Wp[pp]*self.u[g][pp]*self.v[g][pp]*ds()

  def solve_group_GS(self, it=0, init_slns_ary=None):
    if self.verb > 1: print0(self.print_prefix + "Solving..." )
  
    if self.eigenproblem:  
      coupled_solver_error(__file__,
                           "solve using group GS",
                           "Group Gauss-Seidel for eigenproblem not yet supported")
    
    sol_timer = Timer("-- Complete solution")
    mat_timer = Timer("---- MTX: Complete construction")
    ass_timer = Timer("---- MTX: Assembling")
    sln_timer = Timer("---- SOL: Solving")

    # To simplify the weak forms
    u = self.u[0]
    v = self.v[0]

    if init_slns_ary is None:
      init_slns_ary = numpy.zeros((self.DD.G, self.local_sln_size))

    for g in range(self.DD.G):
      self.slns_mg[g].vector()[:] = init_slns_ary[g]

    err = 0.

    for gsi in range(self.max_group_GS_it):
    #==========================================  GAUSS-SEIDEL LOOP  ============================================
    
      if self.verb > 2: print self.print_prefix + 'Gauss-Seidel iteration {}'.format(gsi)

      for gto in range(self.DD.G):
      #=========================================  LOOP OVER GROUPS  ===============================================

        self.sln_vec = self.slns_mg[gto].vector()

        prev_slng_vec = self.aux_slng.vector()
        prev_slng_vec.zero()
        prev_slng_vec.axpy(1.0, self.sln_vec)
        prev_slng_vec.apply("insert")

        spc = self.print_prefix + "  "
        
        if self.verb > 3 and self.DD.G > 1: print spc + 'GROUP [', gto, ',', gto, '] :'
        
        #====================================  ASSEMBLE WITHIN-GROUP PROBLEM  ========================================
        
        mat_timer.start()

        pres_fiss = self.PD.get_xs('chi', self.chi, gto)
    
        self.PD.get_xs('D', self.D, gto)
        self.PD.get_xs('St', self.R, gto)
        
        i,j,p,q,k1,k2 = ufl.indices(6)
        
        form = ( self.D*self.tensors.T[p,q,i,j]*u[q].dx(j)*v[p].dx(i) +
                 self.R*self.tensors.W[p,q]*u[q]*v[p] ) * dx + self.bnd_matrix_form[gto]
        
        ass_timer.start()
    
        add_values_A = False
        add_values_Q = False

        assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)
        add_values_A = True
          
        ass_timer.stop()

        if self.fixed_source_problem:
          if self.PD.isotropic_source_everywhere:
            self.PD.get_Q(self.fixed_source, 0, gto)
            # FIXME: This assumes that adjoint source == forward source
            form = self.fixed_source*self.tensors.Wp[p]*v[p]*dx + self.bnd_vector_form[gto]
          else:
            form = ufl.zero()
            for n in range(self.DD.M):
              self.PD.get_Q(self.fixed_source, n, gto)
              # FIXME: This assumes that adjoint source == forward source
              form += self.fixed_source[n,gto] * self.tensors.Wp[n] * v[n] * dx + self.bnd_vector_form[gto]

          ass_timer.start()

          assemble(form, tensor=self.Q, finalize_tensor=False, add_values=add_values_Q)
          add_values_Q = True
          
          ass_timer.stop()
                      
        for gfrom in range(self.DD.G):
          
          if self.verb > 3 and self.DD.G > 1:
            print spc + 'GROUP [', gto, ',', gfrom, '] :'
          
          pres_Ss = False

          # TODO: Enlarge self.S and self.C to (L+1)^2 (or 1./2.*(L+1)*(L+2) in 2D) to accomodate for anisotropic
          # scattering (lines below using CC, SS are correct only for L = 0, when the following inner loop runs only
          # once.
          for l in range(self.L+1):
            for m in range(-l, l+1):
              if self.DD.angular_quad.get_D() == 2 and divmod(l+m,2)[1] == 0:
                continue

              pres_Ss |= self.PD.get_xs('Ss', self.S[l], gto, gfrom, l)
              self.PD.get_xs('C', self.C[l], gto, gfrom, l)
              
          if pres_Ss:
            Sd = ufl.diag(self.S)
            SS = self.tensors.QT[p,k1]*Sd[k1,k2]*self.tensors.Q[k2,q]
            Cd = ufl.diag(self.C)
            CC = self.tensors.QtT[p,i,k1]*Cd[k1,k2]*self.tensors.Qt[k2,q,j]
            
            ass_timer.start()
            
            if gfrom != gto:
              form = ( SS[p,q]*self.slns_mg[gfrom][q]*v[p] - CC[p,i,q,j]*self.slns_mg[gfrom][q].dx(j)*v[p].dx(i) ) * dx
              assemble(form, tensor=self.Q, finalize_tensor=False, add_values=add_values_Q)
            else:
              form = ( CC[p,i,q,j]*u[q].dx(j)*v[p].dx(i) - SS[q,p]*u[q]*v[p] ) * dx
              assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)

            ass_timer.stop()
              
          if pres_fiss:
            pres_nSf = self.PD.get_xs('nSf', self.R, gfrom)
             
            if pres_nSf:
              ass_timer.start()
              
              if gfrom != gto:
                form = self.chi*self.R/(4*numpy.pi)*\
                       self.tensors.QT[p,0]*self.tensors.Q[0,q]*self.slns_mg[gfrom][q]*v[p]*dx
                assemble(form, tensor=self.Q, finalize_tensor=False, add_values=add_values_Q)
              else:
                # NOTE: Fixed-source case (eigenproblems can currently be solved only by the coupled-group scheme)
                if self.fixed_source_problem:
                  form = -self.chi*self.R/(4*numpy.pi)*self.tensors.QT[p,0]*self.tensors.Q[0,q]*u[q]*v[p]*dx
                  assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)

              ass_timer.stop()

        #================================== END ASSEMBLE WITHIN-GROUP PROBLEM =======================================
        
        self.A.apply("add")
        self.Q.apply("add")
        
        mat_timer.stop()

        self.save_algebraic_system({'A':'A_{}'.format(gto), 'Q':'Q_{}'.format(gto)}, it)
        
        #====================================  SOLVE WITHIN-GROUP PROBLEM  ==========================================

        sln_timer.start()
        dolfin_solve(self.A, self.sln_vec, self.Q, "cg", "petsc_amg")
        sln_timer.stop()

        self.up_to_date["flux"] = False

        err = max(err, delta(self.sln_vec.array(), prev_slng_vec.array()))
          
      #==================================== END LOOP OVER GROUPS ==================================== 

      if err < self.parameters["group_GS"]["tol"]:
        break


  def assemble_algebraic_system(self):
    
    if self.verb > 1: print0(self.print_prefix + "Assembling algebraic system.")

    mat_timer = Timer("---- MTX: Complete construction")
    ass_timer = Timer("---- MTX: Assembling")
    
    add_values_A = False
    add_values_B = False
    add_values_Q = False
     
    for gto in range(self.DD.G):
    #===============================  LOOP OVER GROUPS AND ASSEMBLE  ================================
    
      spc = self.print_prefix + "  "
      
      if self.verb > 3 and self.DD.G > 1:
        print spc + 'GROUP [', gto, ',', gto, '] :'
      
      pres_fiss = self.PD.get_xs('chi', self.chi, gto)
  
      self.PD.get_xs('D', self.D, gto)
      self.PD.get_xs('St', self.R, gto)
      
      i,j,p,q,k1,k2 = ufl.indices(6)
      
      form = ( self.D*self.tensors.T[p,q,i,j]*self.u[gto][q].dx(j)*self.v[gto][p].dx(i) +
               self.R*self.tensors.W[p,q]*self.u[gto][q]*self.v[gto][p] ) * dx + self.bnd_matrix_form[gto]
      
      ass_timer.start()

      assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)
      add_values_A = True
        
      ass_timer.stop()

      if self.fixed_source_problem:
        if self.PD.isotropic_source_everywhere:
          self.PD.get_Q(self.fixed_source, 0, gto)
          # FIXME: This assumes that adjoint source == forward source
          form = self.fixed_source * self.tensors.Wp[p] * self.v[gto][p] * dx + self.bnd_vector_form[gto]
        else:
          form = ufl.zero()
          for n in range(self.DD.M):
            self.PD.get_Q(self.fixed_source, n, gto)
            # FIXME: This assumes that adjoint source == forward source
            form += self.fixed_source[n,gto] * self.tensors.Wp[n] * self.v[gto][n] * dx + self.bnd_vector_form[gto]

        ass_timer.start()

        assemble(form, tensor=self.Q, finalize_tensor=False, add_values=add_values_Q)
        add_values_Q = True

        ass_timer.stop()
                    
      for gfrom in range(self.DD.G):
        
        if self.verb > 3 and self.DD.G > 1: print spc + 'GROUP [', gto, ',', gfrom, '] :'
        
        pres_Ss = False

        # TODO: Enlarge self.S and self.C to (L+1)^2 (or 1./2.*(L+1)*(L+2) in 2D) to accomodate for anisotropic
        # scattering (lines below using CC, SS are correct only for L = 0, when the following inner loop runs only
        # once.
        for l in range(self.L+1):
          for m in range(-l, l+1):
            if self.DD.angular_quad.get_D() == 2 and divmod(l+m,2)[1] == 0:
              continue

            pres_Ss |= self.PD.get_xs('Ss', self.S[l], gto, gfrom, l)
            self.PD.get_xs('C', self.C[l], gto, gfrom, l)
            
        if pres_Ss:
          Sd = ufl.diag(self.S)
          SS = self.tensors.QT[p,k1]*Sd[k1,k2]*self.tensors.Q[k2,q]
          Cd = ufl.diag(self.C)
          CC = self.tensors.QtT[p,i,k1]*Cd[k1,k2]*self.tensors.Qt[k2,q,j]
          
          ass_timer.start()
          
          form = ( CC[p,i,q,j]*self.u[gfrom][q].dx(j)*self.v[gto][p].dx(i) - 
                   SS[q,p]*self.u[gfrom][q]*self.v[gto][p] ) * dx
          assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)

          ass_timer.stop()
            
        if pres_fiss:
          pres_nSf = self.PD.get_xs('nSf', self.R, gfrom)
           
          if pres_nSf:
            ass_timer.start()
            
            if self.fixed_source_problem:
              form = -self.chi*self.R/(4*numpy.pi)*\
                     self.tensors.QT[p,0]*self.tensors.Q[0,q]*self.u[gfrom][q]*self.v[gto][p]*dx
              assemble(form, tensor=self.A, finalize_tensor=False, add_values=add_values_A)
            else:
              form = self.chi*self.R/(4*numpy.pi)*\
                     self.tensors.QT[p,0]*self.tensors.Q[0,q]*self.u[gfrom][q]*self.v[gto][p]*dx
              assemble(form, tensor=self.B, finalize_tensor=False, add_values=add_values_B)
              add_values_B = True

            ass_timer.stop()
    
    #=============================  END LOOP OVER GROUPS AND ASSEMBLE  ===============================
                        
    self.A.apply("add")
    if self.fixed_source_problem:
      self.Q.apply("add")
    elif self.eigenproblem:
      self.B.apply("add")

                    
  def solve(self, it=0):
    if self.group_GS:
      self.solve_group_GS(it)
    else:
      super(EllipticSNFluxModule, self).solve(it)
      self.slns_mg = split(self.sln)

    i,p,q,k1,k2 = ufl.indices(5)

    sol_timer = Timer("-- Complete solution")
    aux_timer = Timer("---- SOL: Computing angular flux + adjoint")

    # TODO: Move to Discretization
    V11 = FunctionSpace(self.DD.mesh, "CG", self.DD.parameters["p"])

    for gto in range(self.DD.G):
      self.PD.get_xs('D', self.D, gto)

      form = self.D * ufl.diag_vector(ufl.as_matrix(self.DD.ordinates_matrix[i,p]*self.slns_mg[gto][q].dx(i), (p,q)))

      for gfrom in range(self.DD.G):
        pres_Ss = False

        # TODO: Enlarge self.S and self.C to (L+1)^2 (or 1./2.*(L+1)*(L+2) in 2D) to accomodate for anisotropic
        # scattering (lines below using CC, SS are correct only for L = 0, when the following inner loop runs only
        # once.
        for l in range(self.L+1):
          for m in range(-l, l+1):
            if self.DD.angular_quad.get_D() == 2 and divmod(l+m, 2)[1] == 0:
              continue

            pres_Ss |= self.PD.get_xs('Ss', self.S[l], gto, gfrom, l)
            self.PD.get_xs('C', self.C[l], gto, gfrom, l)

        if pres_Ss:
          Cd = ufl.diag(self.C)
          CC = self.tensors.Y[p,k1] * Cd[k1,k2] * self.tensors.Qt[k2,q,i]

          form += ufl.as_vector(CC[p,q,i] * self.slns_mg[gfrom][q].dx(i), p)

      # project(form, self.DD.Vpsi1, function=self.aux_slng, preconditioner_type="petsc_amg")
      # FASTER, but requires form compilation for each dir.:
      for pp in range(self.DD.M):
        assign(self.aux_slng.sub(pp), project(form[pp], V11, preconditioner_type="petsc_amg"))

      self.psi_mg[gto].assign(self.slns_mg[gto] + self.aux_slng)
      self.adj_psi_mg[gto].assign(self.slns_mg[gto] - self.aux_slng)

  def update_phi(self):
    timer = Timer("Scalar flux update")

    for g in range(self.DD.G):
      phig = self.phi_mg[g]
      phig_v = phig.vector()
      psig = self.psi_mg[g]

      for n in range(self.DD.M):
        # This doesn't work (Dolfin Issue #454)
        # assign(self.phi.sub(g), self.phi.sub(g) + self.tensors.Wp[n]*self.psi.sub(g).sub(n))
        psign = psig.sub(n, deepcopy=True)
        phig_v.axpy(float(self.tensors.Wp[n]), psign.vector())

    self.up_to_date["flux"] = True

  def eigenvalue_residual_norm(self,norm_type='l2'):
    if self.group_GS:
      warning("Residual norm can currently be computed only when the whole system is assembled.")
      return 0.
    else:
      super(EllipticSNFluxModule, self).eigenvalue_residual_norm(norm_type)

  def fixed_source_residual_norm(self,norm_type='l2'):
    if self.group_GS:
      warning("Residual norm can currently be computed only when the whole system is assembled.")
      return 0.
    else:
      super(EllipticSNFluxModule,self).fixed_source_residual_norm(norm_type)

  def visualize(self, it=0):
    super(EllipticSNFluxModule, self).visualize()

    labels = ["psi", "adj_psi"]
    functs = [self.psi_mg, self.adj_psi_mg]
    for var,lbl,fnc in zip(["angular_flux", "adjoint_angular_flux"], labels, functs):
      try:
        should_vis = divmod(it, self.parameters["visualization"][var])[1] == 0
      except ZeroDivisionError:
        should_vis = False

      if should_vis:
        for g in range(self.DD.G):
          for n in range(self.DD.M):
            fgn = fnc[g].sub(n)
            fgn.rename(lbl, "{}_g{}_{}".format(lbl, g, n))
            self.vis_files[var][g][n] << (fgn, float(it))
def test_unsteady_stokes():
    nx, ny = 15, 15
    k = 1
    nu = Constant(1.0e-0)
    dt = Constant(2.5e-2)
    num_steps = 20
    theta0 = 1.0  # Initial theta value
    theta1 = 0.5  # Theta after 1 step
    theta = Constant(theta0)

    mesh = UnitSquareMesh(nx, ny)

    # The 'unsteady version' of the benchmark in the 2012 paper by Labeur&Wells
    u_exact = Expression(
        (
            "sin(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \
                           -6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])",
            "-sin(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \
                           - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])",
        ),
        t=0,
        degree=7,
        domain=mesh,
    )
    p_exact = Expression("sin(t) * x[0]*(1.0 - x[0])",
                         t=0,
                         degree=7,
                         domain=mesh)
    du_exact = Expression(
        (
            "cos(t) * x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \
                            - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])",
            "-cos(t)* x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \
                            -6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])",
        ),
        t=0,
        degree=7,
        domain=mesh,
    )

    ux_exact = Expression(
        (
            "x[0]*x[0]*(1.0 - x[0])*(1.0 - x[0])*(2.0*x[1] \
                            - 6.0*x[1]*x[1] + 4.0*x[1]*x[1]*x[1])",
            "-x[1]*x[1]*(1.0 - x[1])*(1.0 - x[1])*(2.0*x[0] \
                            - 6.0*x[0]*x[0] + 4.0*x[0]*x[0]*x[0])",
        ),
        degree=7,
        domain=mesh,
    )

    px_exact = Expression("x[0]*(1.0 - x[0])", degree=7, domain=mesh)

    sin_ext = Expression("sin(t)", t=0, degree=7, domain=mesh)

    f = du_exact + sin_ext * div(px_exact * Identity(2) -
                                 2 * sym(grad(ux_exact)))

    Vhigh = VectorFunctionSpace(mesh, "DG", 7)
    Phigh = FunctionSpace(mesh, "DG", 7)

    # New syntax:
    V = VectorElement("DG", mesh.ufl_cell(), k)
    Q = FiniteElement("DG", mesh.ufl_cell(), k - 1)
    Vbar = VectorElement("DGT", mesh.ufl_cell(), k)
    Qbar = FiniteElement("DGT", mesh.ufl_cell(), k)

    mixedL = FunctionSpace(mesh, MixedElement([V, Q]))
    mixedG = FunctionSpace(mesh, MixedElement([Vbar, Qbar]))
    V2 = FunctionSpace(mesh, V)

    Uh = Function(mixedL)
    Uhbar = Function(mixedG)
    U0 = Function(mixedL)
    Uhbar0 = Function(mixedG)
    u0, p0 = split(U0)
    ubar0, pbar0 = split(Uhbar0)
    ustar = Function(V2)

    # Then the boundary conditions
    bc0 = DirichletBC(mixedG.sub(0), Constant((0, 0)), Gamma)
    bc1 = DirichletBC(mixedG.sub(1), Constant(0), Corner, "pointwise")
    bcs = [bc0, bc1]

    alpha = Constant(6 * k * k)
    forms_stokes = FormsStokes(mesh, mixedL, mixedG,
                               alpha).forms_unsteady(ustar, dt, nu, f)
    ssc = StokesStaticCondensation(
        mesh,
        forms_stokes["A_S"],
        forms_stokes["G_S"],
        forms_stokes["G_ST"],
        forms_stokes["B_S"],
        forms_stokes["Q_S"],
        forms_stokes["S_S"],
    )

    t = 0.0
    step = 0
    for step in range(num_steps):
        step += 1
        t += float(dt)
        if comm.Get_rank() == 0:
            print("Step " + str(step) + " Time " + str(t))

        # Set time level in exact solution
        u_exact.t = t
        p_exact.t = t

        du_exact.t = t - (1 - float(theta)) * float(dt)
        sin_ext.t = t - (1 - float(theta)) * float(dt)

        ssc.assemble_global_lhs()
        ssc.assemble_global_rhs()
        for bc in bcs:
            ssc.apply_boundary(bc)

        ssc.solve_problem(Uhbar, Uh, "none", "default")
        assign(U0, Uh)
        assign(ustar, U0.sub(0))
        assign(Uhbar0, Uhbar)
        if step == 1:
            theta.assign(theta1)

        udiv_e = sqrt(assemble(div(Uh.sub(0)) * div(Uh.sub(0)) * dx))

    u_ex_h = interpolate(u_exact, Vhigh)
    p_ex_h = interpolate(p_exact, Phigh)

    u_error = sqrt(assemble(dot(Uh.sub(0) - u_ex_h, Uh.sub(0) - u_ex_h) * dx))
    p_error = sqrt(assemble(dot(Uh.sub(1) - p_ex_h, Uh.sub(1) - p_ex_h) * dx))

    assert udiv_e < 1e-12
    assert u_error < 1.5e-4
    assert p_error < 1e-2
Exemplo n.º 23
0
class crossgradient():
    """ Define cross-gradient joint regularization """

    #TODO: introduce constant eps

    def __init__(self, VV):
        """ Input argument:
        VV = MixedFunctionSpace for both inversion parameters """
        self.ab = Function(VV)
        self.abv = self.ab.vector()
        self.MG = Function(VV)
        # cost
        self.a, self.b = self.ab.split(deepcopy=True)
        self.cost = 0.5*( inner(nabla_grad(self.a), nabla_grad(self.a))*\
        inner(nabla_grad(self.b), nabla_grad(self.b))*dx - \
        inner(nabla_grad(self.a), nabla_grad(self.b))*\
        inner(nabla_grad(self.a), nabla_grad(self.b))*dx )
        # gradient
        testa, testb = TestFunction(VV)
        grada = inner( nabla_grad(testa), \
        inner(nabla_grad(self.b), nabla_grad(self.b))*nabla_grad(self.a) - \
        inner(nabla_grad(self.a), nabla_grad(self.b))*nabla_grad(self.b) )*dx
        gradb = inner( nabla_grad(testb), \
        inner(nabla_grad(self.a), nabla_grad(self.a))*nabla_grad(self.b) - \
        inner(nabla_grad(self.a), nabla_grad(self.b))*nabla_grad(self.a) )*dx
        self.grad = grada + gradb
        # Hessian
        self.ahat, self.bhat = self.ab.split(deepcopy=True)
        self.abhat = Function(VV)
        at, bt = TestFunction(VV)
        ah, bh = TrialFunction(VV)
        wkform11 = inner( nabla_grad(at), \
        inner(nabla_grad(self.b), nabla_grad(self.b))*nabla_grad(ah) - \
        inner(nabla_grad(ah), nabla_grad(self.b))*nabla_grad(self.b) )*dx
        #
        wkform21 = inner( nabla_grad(bt), \
        2*inner(nabla_grad(self.a), nabla_grad(ah))*nabla_grad(self.b) - \
        inner(nabla_grad(self.a), nabla_grad(self.b))*nabla_grad(ah) - \
        inner(nabla_grad(ah), nabla_grad(self.b))*nabla_grad(self.a) )*dx
        #
        wkform12 = inner( nabla_grad(at), \
        2*inner(nabla_grad(self.b), nabla_grad(bh))*nabla_grad(self.a) - \
        inner(nabla_grad(self.a), nabla_grad(self.b))*nabla_grad(bh) - \
        inner(nabla_grad(self.a), nabla_grad(bh))*nabla_grad(self.b) )*dx
        #
        wkform22 = inner( nabla_grad(bt), \
        inner(nabla_grad(self.a), nabla_grad(self.a))*nabla_grad(bh) - \
        inner(nabla_grad(self.a), nabla_grad(bh))*nabla_grad(self.a) )*dx
        #
        self.hessian = wkform11 + wkform21 + wkform12 + wkform22
        self.precond = wkform11 + wkform22

    def costab(self, ma_in, mb_in):
        """ ma_in, mb_in = Function(V) """
        setfct(self.a, ma_in)
        setfct(self.b, mb_in)
        return assemble(self.cost)  # this is global (in parallel)

    def gradab(self, ma_in, mb_in):
        """ ma_in, mb_in = Function(V) """
        setfct(self.a, ma_in)
        setfct(self.b, mb_in)
        return assemble(self.grad)

    def assemble_hessianab(self, a, b):
        setfct(self.a, a)
        setfct(self.b, b)
        self.H = assemble(self.hessian)
        self.Hprecond = assemble(self.precond)

    def hessianab(self, ahat, bhat):
        """ ahat, bhat = Vector(V) """
        setfct(self.ahat, ahat)
        setfct(self.bhat, bhat)
        assign(self.abhat.sub(0), self.ahat)
        assign(self.abhat.sub(1), self.bhat)
        return self.H * self.abhat.vector()
Exemplo n.º 24
0
class TVPD(TV):
    """ Total variation using primal-dual Newton """

    def isPD(self): return True

    def updatePD(self):
        """ Update the parameters.
        parameters should be:
            - k(x) = factor inside TV
            - eps = regularization parameter
            - Vm = FunctionSpace for parameter. 
        ||f||_TV = int k(x) sqrt{|grad f|^2 + eps} dx
        """
        # primal dual variables
        self.Vw = FunctionSpace(self.Vm.mesh(), 'DG', 0)
        self.wH = Function(self.Vw*self.Vw)  # dual variable used in Hessian (re-scaled)
        #self.wH = nabla_grad(self.m)/sqrt(self.fTV) # full Hessian
        self.w = Function(self.Vw*self.Vw)  # dual variable for primal-dual, initialized at 0
        self.dm = Function(self.Vm)
        self.dw = Function(self.Vw*self.Vw)  
        self.testw = TestFunction(self.Vw*self.Vw)
        self.trialw = TrialFunction(self.Vw*self.Vw)
        # investigate convergence of dual variable
        self.dualres = self.w*sqrt(self.fTV) - nabla_grad(self.m)
        self.dualresnorm = inner(self.dualres, self.dualres)*dx
        self.normgraddm = inner(nabla_grad(self.dm), nabla_grad(self.dm))*dx
        # Hessian
        self.wkformPDhess = self.kovsq * ( \
        inner(nabla_grad(self.trial), nabla_grad(self.test)) - \
        0.5*( inner(self.wH, nabla_grad(self.test))*\
        inner(nabla_grad(self.trial), nabla_grad(self.m)) + \
        inner(nabla_grad(self.m), nabla_grad(self.test))*\
        inner(nabla_grad(self.trial), self.wH) ) / sqrt(self.fTV) \
        )*dx
        # update dual variable
        self.Mw = assemble(inner(self.trialw, self.testw)*dx)
        self.rhswwk = inner(-self.w, self.testw)*dx + \
        inner(nabla_grad(self.m)+nabla_grad(self.dm), self.testw) \
        /sqrt(self.fTV)*dx + \
        inner(-inner(nabla_grad(self.m),nabla_grad(self.dm))* \
        self.wH/sqrt(self.fTV), self.testw)*dx

    def compute_dw(self, dm):
        """ Compute dw """
        setfct(self.dm, dm)
        b = assemble(self.rhswwk)
        solve(self.Mw, self.dw.vector(), b)


    def update_w(self, alpha):
        """ update w and re-scale wH """
        self.w.vector().axpy(alpha, self.dw.vector())
        # project each w (coord-wise) onto unit sphere to get wH
        (wx, wy) = self.w.split(deepcopy=True)
        wxa, wya = wx.vector().array(), wy.vector().array()
        normw = np.sqrt(wxa**2 + wya**2)
        factorw = [max(1.0, ii) for ii in normw]
        setfct(wx, wxa/factorw)
        setfct(wy, wya/factorw)
        assign(self.wH.sub(0), wx)
        assign(self.wH.sub(1), wy)
        # check
        (wx,wy) = self.wH.split(deepcopy=True)
        wxa, wya = wx.vector().array(), wy.vector().array()
        assert np.amax(np.sqrt(wxa**2 + wya**2)) <= 1.0 + 1e-14
        # Print results
        dualresnorm = assemble(self.dualresnorm)
        normgraddm = assemble(self.normgraddm)
        print 'line search dual variable: max(|w|)={}, err(w,df)={}, |grad(dm)|={}'.\
        format(np.amax(np.sqrt(normw)), np.sqrt(dualresnorm), np.sqrt(normgraddm))
Exemplo n.º 25
0
class normalizedcrossgradient():
    """
    Defined normalized cross-gradient 
    |nabla m1 x nabla m2|^2/(|nabla m1|^2|nabla m2|^2)
    """
    def __init__(self, VV, parameters=[]):
        self.parameters = {}
        self.parameters['eps'] = 1e-4
        self.parameters['correctcost'] = True
        self.parameters.update(parameters)
        eps = Constant(self.parameters['eps'])

        self.ab = Function(VV)
        self.a, self.b = self.ab.split(deepcopy=True)
        normgrada = sqrt(inner(nabla_grad(self.a), nabla_grad(self.a)) + eps)
        ngrada = nabla_grad(self.a) / normgrada
        normgradb = sqrt(inner(nabla_grad(self.b), nabla_grad(self.b)) + eps)
        ngradb = nabla_grad(self.b) / normgradb

        # cost
        if self.parameters['correctcost']:
            meshtmp = UnitSquareMesh(VV.mesh().mpi_comm(), 10, 10)
            Vtmp = FunctionSpace(meshtmp, 'CG', 1)
            x = SpatialCoordinate(meshtmp)
            correctioncost = 1. / assemble(sqrt(4.0 * x[0] * x[0]) * dx)
            print '[NCG] Correction cost with factor={}'.format(correctioncost)
        else:
            correctioncost = 1.0
        self.cost = 0.5 * correctioncost * (
            1.0 - inner(ngrada, ngradb) * inner(ngrada, ngradb)) * dx
        # gradient
        testa, testb = TestFunction(VV)
        grada = - inner(ngrada, ngradb)* \
        (inner(ngradb/normgrada, nabla_grad(testa)) -
        inner(ngrada, ngradb)* \
        inner(ngrada/normgrada, nabla_grad(testa)))*dx
        gradb = - inner(ngrada, ngradb)* \
        (inner(ngrada/normgradb, nabla_grad(testb)) -
        inner(ngrada, ngradb)* \
        inner(ngradb/normgradb, nabla_grad(testb)))*dx
        self.grad = grada + gradb
        # Hessian
        self.ahat, self.bhat = self.ab.split(deepcopy=True)
        self.abhat = Function(VV)
        triala, trialb = TrialFunction(VV)
        wkform11 = -((inner(ngradb / normgrada, nabla_grad(testa)) - inner(
            ngrada, ngradb) * inner(ngrada / normgrada, nabla_grad(testa))) *
                     (inner(ngradb / normgrada, nabla_grad(triala)) -
                      inner(ngrada, ngradb) *
                      inner(ngrada / normgrada, nabla_grad(triala))) +
                     inner(ngrada, ngradb) *
                     (-inner(ngradb / normgrada, nabla_grad(testa)) *
                      inner(ngrada / normgrada, nabla_grad(triala)) -
                      inner(ngradb / normgrada, nabla_grad(triala)) *
                      inner(ngrada / normgrada, nabla_grad(testa)) -
                      inner(ngrada / normgrada, ngradb / normgrada) *
                      inner(nabla_grad(testa), nabla_grad(triala)) +
                      3 * inner(ngrada, ngradb) *
                      inner(ngrada / normgrada, nabla_grad(testa)) *
                      inner(ngrada / normgrada, nabla_grad(triala)))) * dx
        #
        wkform12 = -(
            (inner(ngradb / normgrada, nabla_grad(testa)) -
             inner(ngrada, ngradb) *
             inner(ngrada / normgrada, nabla_grad(testa))) *
            (inner(ngrada / normgradb, nabla_grad(trialb)) - inner(
                ngrada, ngradb) * inner(ngradb / normgradb, nabla_grad(trialb))
             ) + inner(ngrada, ngradb) *
            (inner(
                nabla_grad(testa) / normgrada,
                nabla_grad(trialb) / normgradb) -
             inner(ngradb / normgrada, nabla_grad(testa)) *
             inner(ngradb / normgradb, nabla_grad(trialb)) -
             inner(ngrada / normgrada, nabla_grad(testa)) *
             (inner(ngrada / normgradb, nabla_grad(trialb)) -
              inner(ngrada, ngradb) *
              inner(ngradb / normgradb, nabla_grad(trialb))))) * dx
        #
        wkform22 = -((inner(ngrada / normgradb, nabla_grad(testb)) - inner(
            ngrada, ngradb) * inner(ngradb / normgradb, nabla_grad(testb))) *
                     (inner(ngrada / normgradb, nabla_grad(trialb)) -
                      inner(ngrada, ngradb) *
                      inner(ngradb / normgradb, nabla_grad(trialb))) +
                     inner(ngrada, ngradb) *
                     (-inner(ngrada / normgradb, nabla_grad(testb)) *
                      inner(ngradb / normgradb, nabla_grad(trialb)) -
                      inner(ngrada / normgradb, nabla_grad(trialb)) *
                      inner(ngradb / normgradb, nabla_grad(testb)) -
                      inner(ngrada / normgradb, ngradb / normgradb) *
                      inner(nabla_grad(testb), nabla_grad(trialb)) +
                      3 * inner(ngrada, ngradb) *
                      inner(ngradb / normgradb, nabla_grad(testb)) *
                      inner(ngradb / normgradb, nabla_grad(trialb)))) * dx
        #
        wkform21 = -(
            (inner(ngrada / normgradb, nabla_grad(testb)) -
             inner(ngrada, ngradb) *
             inner(ngradb / normgradb, nabla_grad(testb))) *
            (inner(ngradb / normgrada, nabla_grad(triala)) - inner(
                ngrada, ngradb) * inner(ngrada / normgrada, nabla_grad(triala))
             ) + inner(ngrada, ngradb) *
            (inner(
                nabla_grad(testb) / normgradb,
                nabla_grad(triala) / normgrada) -
             inner(ngrada / normgradb, nabla_grad(testb)) *
             inner(ngrada / normgrada, nabla_grad(triala)) -
             inner(ngradb / normgradb, nabla_grad(testb)) *
             (inner(ngradb / normgrada, nabla_grad(triala)) -
              inner(ngrada, ngradb) *
              inner(ngrada / normgrada, nabla_grad(triala))))) * dx
        #
        self.hessian = wkform11 + wkform22 + wkform12 + wkform21
        self.precond = wkform11 + wkform22  #+ wkform12 + wkform21

    def costab(self, ma_in, mb_in):
        setfct(self.a, ma_in)
        setfct(self.b, mb_in)
        return assemble(self.cost)

    def gradab(self, ma_in, mb_in):
        """ ma_in, mb_in = Function(V) """
        setfct(self.a, ma_in)
        setfct(self.b, mb_in)
        return assemble(self.grad)

    def assemble_hessianab(self, a, b):
        setfct(self.a, a)
        setfct(self.b, b)
        self.H = assemble(self.hessian)
        self.Hprecond = assemble(self.precond)

    def hessianab(self, ahat, bhat):
        """ ahat, bhat = Vector(V) """
        setfct(self.ahat, ahat)
        setfct(self.bhat, bhat)
        assign(self.abhat.sub(0), self.ahat)
        assign(self.abhat.sub(1), self.bhat)
        return self.H * self.abhat.vector()
Exemplo n.º 26
0
# Step in time
t = 0.0

# Check if we are running on CI server and reduce run time
if "CI" in os.environ.keys():
    T = 3 * dt
else:
    T = 50 * dt

u.vector.copy(result=u0.vector)
u0.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT,
                      mode=PETSc.ScatterMode.FORWARD)

while (t < T):
    t += dt
    r = solver.solve(problem, u.vector)
    print("Step, num iterations:", int(t / dt), r[0])
    u.vector.copy(result=u0.vector)
    file.write(u.sub(0), t)

# The string ``"compressed"`` indicates that the output data should be
# compressed to reduce the file size. Within the time stepping loop, the
# solution vector associated with ``u`` is copied to ``u0`` at the
# beginning of each time step, and the nonlinear problem is solved by
# calling
# :py:func:`solver.solve(problem,u.vector)<dolfin.cpp.NewtonSolver.solve>`,
# with the new solution vector returned in
# :py:func:`u.vector<dolfin.cpp.Function.vector>`. The ``c`` component
# of the solution (the first component of ``u``) is then written to file
# at every time step.
Exemplo n.º 27
0
    pde_projection.solve_problem(ubar_a.cpp_object(), ustar.cpp_object(),
                                 lamb.cpp_object(), "mumps", "default")
    del t1

    # Solve Stokes
    t1 = Timer("[P] Stokes assemble ")
    ssc.assemble_global_system(True)
    for bc in bcs:
        ssc.apply_boundary(bc)
    del t1
    t1 = Timer("[P] Stokes solve")
    ssc.solve_problem(Uhbar.cpp_object(), Uh.cpp_object(), "mumps", "none")
    del t1

    # Needed for particle advection
    assign(Udiv, Uh.sub(0))

    # Needed for constrained map
    assign(ubar0_a, Uhbar.sub(0))
    assign(u0_a, ustar)
    assign(duh00, duh0)
    assign(duh0, project(Uh.sub(0) - ustar, W_2))

    p.increment(Udiv.cpp_object(), ustar.cpp_object(),
                np.array([1, 2], dtype=np.uintp), theta_p, step)

    if step == 2:
        theta_L.assign(theta_next)

    xdmf_u.write(Uh.sub(0), t)
    xdmf_p.write(Uh.sub(1), t)