Пример #1
0
    def velocity_update(self):
        """
        Update the velocity predictions with the updated pressure
        field from the pressure correction equation
        """
        if self.use_local_solver_for_update:
            # Element-wise projection
            if self.u_upd_solver is None:
                self.u_upd_solver = dolfin.LocalSolver(
                    self.eqs_vel_upd[0].form_lhs)
                self.u_upd_solver.factorize()

            Vu = self.simulation.data['Vu']
            for d in range(self.simulation.ndim):
                eq = self.eqs_vel_upd[d]
                b = eq.assemble_rhs()
                u_new = self.simulation.data['u%d' % d]
                self.u_upd_solver.solve_local(u_new.vector(), b, Vu.dofmap())
                self.niters_u_upd[d] = 0

        else:
            # Global projection
            for d in range(self.simulation.ndim):
                eq = self.eqs_vel_upd[d]

                if self.Au_upd is None:
                    self.Au_upd = eq.assemble_lhs()

                A = self.Au_upd
                b = eq.assemble_rhs()
                u_new = self.simulation.data['u%d' % d]

                self.niters_u_upd[d] = self.u_upd_solver.solve(
                    A, u_new.vector(), b)
Пример #2
0
    def _setup_divergence(self, vel, method, name='u'):
        """
        Calculate divergence and element to element velocity
        flux differences on the same edges
        """
        V = df.FunctionSpace(self.mesh, 'DG', 0)
        n = df.FacetNormal(self.mesh)
        u, v = df.TrialFunction(V), df.TestFunction(V)

        # The difference between the flux on the same facet between two different cells
        a1 = u * v * dx
        w = dot(vel('+') - vel('-'), n('+'))
        if method == 'div0':
            L1 = w * avg(v) * dS
        else:
            L1 = abs(w) * avg(v) * dS

        # The divergence internally in the cell
        a2 = u * v * dx
        if method in ('div', 'div0'):
            L2 = abs(df.div(vel)) * v * dx
        elif method == 'gradq_avg':
            L2 = dot(avg(vel), n('+')) * jump(v) * dS - dot(vel, grad(v)) * dx
        else:
            raise ValueError('Divergence type %r not supported' % method)

        # Store for usage in projection
        storage = self._div[name] = {}
        storage['dS_solver'] = df.LocalSolver(a1, L1)
        storage['dx_solver'] = df.LocalSolver(a2, L2)
        storage['div_dS'] = df.Function(V)
        storage['div_dx'] = df.Function(V)

        # Pre-factorize matrices
        storage['dS_solver'].factorize()
        storage['dx_solver'].factorize()
        storage['div_dS'].rename('Divergence_%s_dS' % name,
                                 'Divergence_%s_dS' % name)
        storage['div_dx'].rename('Divergence_%s_dx' % name,
                                 'Divergence_%s_dx' % name)
Пример #3
0
    def _setup_peclet(self, vel, nu):
        """
        Pe = a*h/(2*nu) where a = mag(vel)
        """
        V = df.FunctionSpace(self.mesh, 'DG', 0)
        h = self.simulation.data['h']
        u, v = df.TrialFunction(V), df.TestFunction(V)
        a = u * v * dx
        L = dot(vel, vel)**0.5 * h / (2 * nu) * v * dx

        # Pre-factorize matrices and store for usage in projection
        self._peclet_solver = df.LocalSolver(a, L)
        self._peclet_solver.factorize()
        self._peclet = df.Function(V)
Пример #4
0
 def __init__(self, expr, V, dxm):
     """
     expr:
         expression to project
     V:
         quadrature function space
     dxm:
         dolfin.Measure("dx") that matches V
     """
     dv = df.TrialFunction(V)
     v_ = df.TestFunction(V)
     a_proj = df.inner(dv, v_) * dxm
     b_proj = df.inner(expr, v_) * dxm
     self.solver = df.LocalSolver(a_proj, b_proj)
     self.solver.factorize()
Пример #5
0
    def _setup_courant(self, vel, dt):
        """
        Co = a*dt/h where a = mag(vel)
        """
        V = df.FunctionSpace(self.mesh, 'DG', 0)
        h = self.simulation.data['h']

        u, v = df.TrialFunction(V), df.TestFunction(V)
        a = u * v * dx
        vmag = sqrt(dot(vel, vel))
        L = vmag * dt / h * v * dx

        # Pre-factorize matrices and store for usage in projection
        self._courant_solver = df.LocalSolver(a, L)
        self._courant_solver.factorize()
        self._courant = df.Function(V)
Пример #6
0
    def solve(self, var, b):
        x = dolfin.Function(self.test_function().function_space())

        # b is a libadjoint object (form or function)
        (a, L) = (self.data, b.data)

        # First: check if L is None (meaning zero)
        if L is None:
            x_vec = adjlinalg.Vector(x)
            return x_vec

        if isinstance(L, dolfin.Function):
            b_vec = L.vector()
            L = None
        else:
            b_vec = dolfin.assemble(L)

        # Next: if necessary, create a new solver and add to dictionary
        idx = a.arguments()
        if idx not in caching.localsolvers:
            if dolfin.parameters["adjoint"]["debug_cache"]:
                dolfin.info_red("Creating new LocalSolver")
            newsolver = dolfin.LocalSolver(
                a, None, solver_type=self.solver_parameters["solver_type"])
            if self.solver_parameters["factorize"]: newsolver.factorize()
            caching.localsolvers[idx] = newsolver
        else:
            if dolfin.parameters["adjoint"]["debug_cache"]:
                dolfin.info_green("Reusing LocalSolver")

        # Get the right solver from the solver dictionary
        solver = caching.localsolvers[idx]
        solver.solve_local(x.vector(), b_vec, b.fn_space.dofmap())

        x_vec = adjlinalg.Vector(x)
        return x_vec
Пример #7
0
    def __init__(self, simulation, field_inp):
        """
        A scalar field
        """
        self.simulation = simulation
        self.read_input(field_inp)

        # Show the input data
        simulation.log.info('Creating a sharp field %r' % self.name)
        simulation.log.info('    Variable: %r' % self.var_name)
        simulation.log.info('    Local proj: %r' % self.local_projection)
        simulation.log.info('    Proj. degree: %r' % self.projection_degree)
        simulation.log.info('    Poly. degree: %r' % self.polynomial_degree)

        mesh = simulation.data['mesh']
        self.V = dolfin.FunctionSpace(mesh, 'DG', self.polynomial_degree)
        self.func = dolfin.Function(self.V)

        if self.local_projection:
            # Represent the jump using a quadrature element
            quad_elem = dolfin.FiniteElement(
                'Quadrature',
                mesh.ufl_cell(),
                self.projection_degree,
                quad_scheme="default",
            )
            xpos, ypos, zpos = self.xpos, self.ypos, self.zpos
            if simulation.ndim == 2:
                cpp0 = 'x[0] < %r and x[1] < %r' % (xpos, ypos)
            else:
                cpp0 = 'x[0] < %r and x[1] < %r and x[2] < %r' % (xpos, ypos, zpos)
            cpp = '(%s) ? %r : %r' % (cpp0, self.val_below, self.val_above)
            e = dolfin.Expression(cpp, element=quad_elem)
            dx = dolfin.dx(metadata={'quadrature_degree': self.projection_degree})

            # Perform the local projection
            u, v = dolfin.TrialFunction(self.V), dolfin.TestFunction(self.V)
            a = u * v * dolfin.dx
            L = e * v * dx
            ls = dolfin.LocalSolver(a, L)
            ls.solve_local_rhs(self.func)

            # Clip values to allowable bounds
            arr = self.func.vector().get_local()
            val_min = min(self.val_below, self.val_above)
            val_max = max(self.val_below, self.val_above)
            clipped_arr = numpy.clip(arr, val_min, val_max)
            self.func.vector().set_local(clipped_arr)
            self.func.vector().apply('insert')

        else:
            # Initialise the sharp static field
            dm = self.V.dofmap()
            arr = self.func.vector().get_local()
            above, below = self.val_above, self.val_below
            xpos, ypos, zpos = self.xpos, self.ypos, self.zpos
            for cell in dolfin.cells(simulation.data['mesh']):
                mp = cell.midpoint()[:]
                dof, = dm.cell_dofs(cell.index())
                if (
                    mp[0] < xpos
                    and mp[1] < ypos
                    and (simulation.ndim == 2 or mp[2] < zpos)
                ):
                    arr[dof] = below
                else:
                    arr[dof] = above
            self.func.vector().set_local(arr)
            self.func.vector().apply('insert')
Пример #8
0
def local_project(v, fspace, solver_method: str = "", **kwargs):
    """
    Parameters
    ----------
    v : [type]
        input field
    fspace : [type]
        [description]
    solver_method : str, optional
        "LU" or "Cholesky" factorization. LU method used by default.

    keyword arguments
    ----------
    metadata : dict, optional
        This can be used to define different quadrature degrees for different
        terms in a form, and to override other form compiler specific options
        separately for different terms. By default {}
        See UFL user manual for more information
        ** WARNING** : May be over ignored if dx argument is also used. (Non étudié)
    dx : Measure
        Impose the dx measure for the projection.
        This is for example useful to do some kind of interpolation on DG functionspaces.

    Returns
    -------
    Function

    Notes
    -----
    Source for this code:
    https://comet-fenics.readthedocs.io/en/latest/tips_and_tricks.html#efficient-projection-on-dg-or-quadrature-spaces

    """
    metadata = kwargs.get("metadata", {})
    dx = kwargs.get("dx", fe.dx(metadata=metadata))

    reuse_solver = kwargs.get(
        "reuse_solver", True
    )  # Reuse a LocalSolver that already exists
    id_function_space = (
        fspace.id()
    )  # The id is unique. https://fenicsproject.org/olddocs/dolfin/latest/cpp/d8/df0/classdolfin_1_1Variable.html#details

    dv = fe.TrialFunction(fspace)
    v_ = fe.TestFunction(fspace)
    a_proj = fe.inner(dv, v_) * dx
    b_proj = fe.inner(v, v_) * dx

    if solver_method == "LU":
        solver_type = fe.cpp.fem.LocalSolver.SolverType.LU
        solver = fe.LocalSolver(a_proj, b_proj, solver_type=solver_type)
    elif solver_method == "Cholesky":
        solver_type = fe.cpp.fem.LocalSolver.SolverType.Cholesky
        solver = fe.LocalSolver(a_proj, b_proj, solver_type=solver_type)
    else:
        solver = fe.LocalSolver(a_proj, b_proj)

    if not (reuse_solver and ((id_function_space, solver_method) in _local_solvers)):
        solver.factorize()
        # You can optionally call the factorize() method to pre-calculate the local left-hand side factorizations to speed up repeated applications of the LocalSolver with the same LHS
        # This class can be used for post-processing solutions, e.g.computing stress fields for visualisation, far more cheaply that using global projections
        # https://fenicsproject.org/olddocs/dolfin/latest/cpp/de/d86/classdolfin_1_1LocalSolver.html#details
        _local_solvers.append((id_function_space, solver_method))

    u = fe.Function(fspace)
    solver.solve_local_rhs(u)
    return u