Ejemplo n.º 1
0
def NormalCurve(mesh, outside=None, tol=1E-2):
    '''In plane we can get things by rotating the tangent to get unit normal'''
    # The idea is to use a given point to figure out wind number and orient
    # accordingly
    if outside is None:
        outside = np.max(mesh.coordinates(), axis=0) + np.ones(2)
    assert outside.shape == (2, )

    n, = wind_number(mesh, np.array([outside]))
    if abs(n) < tol:
        # Orient with
        R = df.Constant(((0, 1), (-1, 0)))
    else:
        R = df.Constant(((0, -1), (1, 0)))

    t = TangentCurve(mesh)
    V = t.function_space()
    v = df.TestFunction(V)

    n = df.Function(V)
    # DG0 project the rotated tangent
    df.assemble(df.inner(df.dot(R, t) / df.CellVolume(mesh), v) * df.dx,
                tensor=n.vector())

    return n
Ejemplo n.º 2
0
def efield_DG0(mesh, phi):
    Q = df.VectorFunctionSpace(mesh, 'DG', 0)
    q = df.TestFunction(Q)

    M = (1.0 / df.CellVolume(mesh)) * df.inner(-df.grad(phi), q) * df.dx
    E_dg0 = df.assemble(M)
    return df.Function(Q, E_dg0)
Ejemplo n.º 3
0
    def _construct(self, field_inp):
        # Read the input
        self.name = field_inp.get_value('name', required_type='string')
        self.var_name = field_inp.get_value('variable_name', 'phi', 'string')
        self.stationary = field_inp.get_value('stationary', False, 'bool')
        self.radius = field_inp.get_value('radius', required_type='float')
        self.plot = field_inp.get_value('plot', False, 'bool')

        # Show the input
        sim = self.simulation
        sim.log.info('Creating a free surface zone field %r' % self.name)
        sim.log.info('    Variable: %r' % self.var_name)
        sim.log.info('    Stationary: %r' % self.stationary)

        # Create the level set model
        mesh = sim.data['mesh']
        func_name = '%s_%s' % (self.name, self.var_name)
        self.V = dolfin.FunctionSpace(mesh, 'DG', 0)
        self.function = dolfin.Function(self.V)
        self.function.rename(func_name, func_name)
        sim.data[func_name] = self.function

        # Get the level set view
        level_set_view = sim.multi_phase_model.get_level_set_view()
        level_set_view.add_update_callback(self.update)

        # Form to compute the cell average distance to the free surface
        v = dolfin.TestFunction(self.V)
        ls = level_set_view.level_set_function
        cv = dolfin.CellVolume(self.V.mesh())
        self.dist_form = dolfin.Form(ls * v / cv * dolfin.dx)

        if self.plot:
            sim.io.add_extra_output_function(self.function)
Ejemplo n.º 4
0
def CellCentroid(mesh):
    '''[DG0]^d function that evals on cell to its center of mass'''
    V = df.VectorFunctionSpace(mesh, 'DG', 0)
    v = df.TestFunction(V)

    hK = df.CellVolume(mesh)
    x = df.SpatialCoordinate(mesh)

    c = df.Function(V)
    df.assemble((1 / hK) * df.inner(x, v) * df.dx, tensor=c.vector())

    return c
Ejemplo n.º 5
0
    def _interp(self, name, expr=None, func=None):
        """
        Interpolate the expression into the given function
        """
        sim = self.simulation

        # Determine the function space
        V = self.V
        quad_degree = None
        if name == 'c' and self.colour_projection_degree >= 0:
            # Perform projection for c instead of interpolation to better
            # capture the discontinuous nature of the colour field
            if 'Vc' not in sim.data:
                ocellaris_error(
                    'Error in wave field %r input' % self.name,
                    'Cannot specify colour_to_dg_degree when c is '
                    'not used in the multiphase_solver.',
                )
            V = sim.data['Vc']
            quad_degree = self.colour_projection_degree

        # Get the expression
        if expr is None:
            expr = self._get_expression(name, quad_degree)

        # Get the function
        if func is None:
            if name not in self._functions:
                self._functions[name] = dolfin.Function(V)
            func = self._functions[name]

        if quad_degree is not None:
            if self.colour_projection_form is None:
                # Ensure that we can use the DG0 trick of dividing by the mass
                # matrix diagonal to get the projected value
                if V.ufl_element().degree() != 0:
                    ocellaris_error(
                        'Error in wave field %r input' % self.name,
                        'The colour_to_dg_degree projection is '
                        'currently only implemented when c is DG0',
                    )
                v = dolfin.TestFunction(V)
                dx = dolfin.dx(metadata={'quadrature_degree': quad_degree})
                d = dolfin.CellVolume(V.mesh())  # mass matrix diagonal
                form = expr * v / d * dx
                self.colour_projection_form = dolfin.Form(form)

            # Perform projection by assembly (DG0 only!)
            dolfin.assemble(self.colour_projection_form, tensor=func.vector())
        else:
            # Perform standard interpolation
            func.interpolate(expr)
Ejemplo n.º 6
0
    def get_variable(self, name):
        if not name == self.var_name:
            ocellaris_error(
                'Scalar field does not define %r' % name,
                'This scalar field defines %r' % self.var_name,
            )

        if self.func is not None:
            return self.func

        if self.colour_projection_degree >= 0:
            quad_degree = self.colour_projection_degree
            degree = None
        else:
            quad_degree = None
            degree = self.polydeg

        expr = OcellarisCppExpression(
            self.simulation,
            self.cpp_code,
            'Scalar field %r' % self.name,
            degree=degree,
            update=False,
            quad_degree=quad_degree,
        )
        self.func = dolfin.Function(self.V)

        if quad_degree is not None:

            # Ensure that we can use the DG0 trick of dividing by the mass
            # matrix diagonal to get the projected value
            if self.V.ufl_element().degree() != 0:
                ocellaris_error(
                    'Error in wave field %r input' % self.name,
                    'The colour_to_dg_degree projection is '
                    'currently only implemented when c is DG0',
                )
            v = dolfin.TestFunction(self.V)
            dx = dolfin.dx(metadata={'quadrature_degree': quad_degree})
            d = dolfin.CellVolume(self.V.mesh())  # mass matrix diagonal
            form = expr * v / d * dx
            compiled_form = dolfin.Form(form)

            # Perform projection by assembly (DG0 only!)
            dolfin.assemble(compiled_form, tensor=self.func.vector())
        else:
            # Perform standard interpolation
            self.func.interpolate(expr)

        return self.func
Ejemplo n.º 7
0
    def compute(self, inputs, outputs):
        pde_problem = self.options['pde_problem']
        # form = self.options['form']
        rho = self.options['rho']
        expression = self.options['expression']

        self._set_values(inputs)
        von_Mises_max = df.project(
            expression,
            self.density_function_space).vector().get_local().max()

        self.form = (1 / df.CellVolume(self.mesh) *
                     df.exp(rho * (expression - von_Mises_max))) * df.dx
        outputs['von_mises_max'] = 1 / rho * df.ln(df.assemble(
            self.form)) + von_Mises_max
Ejemplo n.º 8
0
    def update_mesh_data(self, connectivity_changed=True):
        """
        Some precomputed values must be calculated before the timestepping
        and updated every time the mesh changes
        """
        if connectivity_changed:
            init_connectivity(self)
        precompute_cell_data(self)
        precompute_facet_data(self)

        # Work around missing consensus on what CellDiameter is for bendy cells
        mesh = self.data['mesh']
        if mesh.ufl_coordinate_element().degree() > 1:
            h = dolfin.CellVolume(mesh)**(1 / mesh.topology().dim())
        else:
            h = dolfin.CellDiameter(mesh)
        self.data['h'] = h
Ejemplo n.º 9
0
    def compute_derivative(self, inputs):
        pde_problem = self.options['pde_problem']
        expression = self.options['expression']
        self._set_values(inputs)

        von_Mises_max = df.project(
            expression,
            self.density_function_space).vector().get_local().max()
        rho = self.options['rho']
        self.form = (1 / df.CellVolume(self.mesh) *
                     df.exp(rho * (expression - von_Mises_max))) * df.dx
        print('von Mises max:--------', von_Mises_max)
        derivative_form_s = df.derivative(
            self.form, pde_problem.states_dict['mixed_states']['function'])
        derivative_numpy_s = 1 / (rho * df.assemble(
            self.form)) * df.assemble(derivative_form_s).get_local()

        derivative_form_d = df.derivative(
            self.form, pde_problem.inputs_dict['density']['function'])
        derivative_form_d = 1 / (rho * df.assemble(
            self.form)) * df.assemble(derivative_form_d).get_local()
        return derivative_numpy_s, derivative_form_d
Ejemplo n.º 10
0
    def __init__(self, mesh, arithmetic_mean=False):
        assert df.parameters['linear_algebra_backend'] == 'PETSc'
        self.arithmetic_mean = arithmetic_mean
        tdim = mesh.topology().dim()
        gdim = mesh.geometry().dim()
        self.cv = df.CellVolume(mesh)

        self.W = df.VectorFunctionSpace(mesh, 'CG', 1)
        Q = df.VectorFunctionSpace(mesh, 'DG', 0)
        p, self.q = df.TrialFunction(Q), df.TestFunction(Q)
        v = df.TestFunction(self.W)

        ones = df.assemble((1. / self.cv) * df.inner(df.Constant(
            (1, ) * gdim), self.q) * df.dx)

        dX = df.dx(
            metadata={
                'form_compiler_parameters': {
                    'quadrature_degree': 1,
                    'quadrature_scheme': 'vertex'
                }
            })

        if self.arithmetic_mean:
            A = df.assemble(
                (1. / self.cv) * df.Constant(tdim + 1) * df.inner(p, v) * dX)
        else:
            A = df.assemble(df.Constant(tdim + 1) * df.inner(p, v) * dX)

        Av = df.Function(self.W).vector()
        A.mult(ones, Av)
        Av = df.as_backend_type(Av).vec()
        Av.reciprocal()
        mat = df.as_backend_type(A).mat()
        mat.diagonalScale(L=Av)

        self.A = A
Ejemplo n.º 11
0
    def define_pressure_equation(self):
        """
        Setup the pressure Poisson equation

        This implementation assembles the full LHS and RHS each time they are needed
        """
        sim = self.simulation
        Vp = sim.data['Vp']
        p_star = sim.data['p']
        u_star = sim.data['u']

        # Trial and test functions
        p = dolfin.TrialFunction(Vp)
        q = dolfin.TestFunction(Vp)

        c1 = sim.data['time_coeffs'][0]
        dt = sim.data['dt']
        mesh = sim.data['mesh']
        n = dolfin.FacetNormal(mesh)

        # Fluid properties
        mpm = sim.multi_phase_model
        mu = mpm.get_laminar_dynamic_viscosity(0)
        rho = sim.data['rho']

        # Lagrange multiplicator to remove the pressure null space
        # ∫ p dx = 0
        assert not self.use_lagrange_multiplicator, 'NOT IMPLEMENTED YET'

        # Weak form of the Poisson eq. with discontinuous elements
        # -∇⋅∇p = - γ_1/Δt ρ ∇⋅u^*
        K = 1.0 / rho
        a = K * dot(grad(p), grad(q)) * dx
        L = K * dot(grad(p_star), grad(q)) * dx

        # RHS, ∇⋅u^*
        if self.incompressibility_flux_type == 'central':
            u_flux = avg(u_star)
        elif self.incompressibility_flux_type == 'upwind':
            switch = dolfin.conditional(
                dolfin.gt(abs(dot(u_star, n))('+'), 0.0), 1.0, 0.0
            )
            u_flux = switch * u_star('+') + (1 - switch) * u_star('-')
        L += c1 / dt * dot(u_star, grad(q)) * dx
        L -= c1 / dt * dot(u_flux, n('+')) * jump(q) * dS

        # Symmetric Interior Penalty method for -∇⋅∇p
        a -= dot(n('+'), avg(K * grad(p))) * jump(q) * dS
        a -= dot(n('+'), avg(K * grad(q))) * jump(p) * dS

        # Symmetric Interior Penalty method for -∇⋅∇p^*
        L -= dot(n('+'), avg(K * grad(p_star))) * jump(q) * dS
        L -= dot(n('+'), avg(K * grad(q))) * jump(p_star) * dS

        # Weak continuity
        penalty_dS, penalty_ds = self.calculate_penalties()

        # Symmetric Interior Penalty coercivity term
        a += penalty_dS * jump(p) * jump(q) * dS
        # L += penalty_dS*jump(p_star)*jump(q)*dS

        # Collect Dirichlet and outlet boundary values
        dirichlet_vals_and_ds = []
        for dbc in sim.data['dirichlet_bcs'].get('p', []):
            dirichlet_vals_and_ds.append((dbc.func(), dbc.ds()))
        for obc in sim.data['outlet_bcs']:
            p_ = mu * dot(dot(grad(u_star), n), n)
            dirichlet_vals_and_ds.append((p_, obc.ds()))

        # Apply Dirichlet boundary conditions
        for p_bc, dds in dirichlet_vals_and_ds:
            # SIPG for -∇⋅∇p
            a -= dot(n, K * grad(p)) * q * dds
            a -= dot(n, K * grad(q)) * p * dds
            L -= dot(n, K * grad(q)) * p_bc * dds

            # SIPG for -∇⋅∇p^*
            L -= dot(n, K * grad(p_star)) * q * dds
            L -= dot(n, K * grad(q)) * p_star * dds

            # Weak Dirichlet
            a += penalty_ds * p * q * dds
            L += penalty_ds * p_bc * q * dds

            # Weak Dirichlet for p^*
            # L += penalty_ds*p_star*q*dds
            # L -= penalty_ds*p_bc*q*dds

        # Neumann boundary conditions
        neumann_bcs = sim.data['neumann_bcs'].get('p', [])
        for nbc in neumann_bcs:
            # Neumann boundary conditions on p and p_star cancel
            # L += (nbc.func() - dot(n, grad(p_star)))*q*nbc.ds()
            pass

        # Use boundary conditions for the velocity for the
        # term from integration by parts of div(u_star)
        for d in range(sim.ndim):
            dirichlet_bcs = sim.data['dirichlet_bcs'].get('u%d' % d, [])
            neumann_bcs = sim.data['neumann_bcs'].get('u%d' % d, [])
            for dbc in dirichlet_bcs:
                u_bc = dbc.func()
                L -= c1 / dt * u_bc * n[d] * q * dbc.ds()
            for nbc in neumann_bcs:
                L -= c1 / dt * u_star[d] * n[d] * q * nbc.ds()

        # ALE mesh velocities
        if sim.mesh_morpher.active:
            cvol_new = dolfin.CellVolume(mesh)
            cvol_old = sim.data['cvolp']

            # Divergence of u should balance expansion/contraction of the cell K
            # ∇⋅u = -∂K/∂t       (See below for definition of the ∇⋅u term)
            L -= (cvol_new - cvol_old) / dt * q * dx

        self.form_lhs = a
        self.form_rhs = L
Ejemplo n.º 12
0
# sigm = lambda_*df.div(displacements_function)* I + 2*mu*w_ij
# s = sigm - (1./3)*df.tr(sigm)*I
# von_Mises = df.sqrt(3./2*df.inner(s, s))
# von_Mises_form = (1/df.CellVolume(mesh)) * von_Mises * df.TestFunction(density_function_space) * df.dx

# T = df.TensorFunctionSpace(mesh, "CG", 1)
# T.vector.set_local()
T_00 = df.Constant(20)
w_ij = 0.5 * (df.grad(displacements_function) + df.grad(
    displacements_function).T) - C * ALPHA * I * (temperature_function - T_00)
sigm = lambda_ * df.div(displacements_function) * I + 2 * mu * w_ij
s = sigm - (1. / 3) * df.tr(sigm) * I
scalar_ = 5e8
# scalar_ = 5e5
von_Mises = df.sqrt(3. / 2 * df.inner(s / scalar_, s / scalar_))
von_Mises_form = (1 / df.CellVolume(mesh)) * von_Mises * df.TestFunction(
    density_function_space) * df.dx
# von_Mises_form =  von_Mises * df.TestFunction(density_function_space) /volume * df.dx
pde_problem.add_field_output('von_Mises', von_Mises_form, 'mixed_states',
                             'density')

x
'''
4. 3. Add bcs
'''

bc_displacements = df.DirichletBC(
    mixed_fs.sub(0).sub(0), df.Constant((0.0)), MidVBoundary())
bc_displacements_1 = df.DirichletBC(
    mixed_fs.sub(0).sub(1), df.Constant((0.0)), MidHBoundary())
Ejemplo n.º 13
0
def define_dg_equations(
    u,
    v,
    p,
    q,
    lm_trial,
    lm_test,
    simulation,
    include_hydrostatic_pressure,
    incompressibility_flux_type,
    use_grad_q_form,
    use_grad_p_form,
    use_stress_divergence_form,
    velocity_continuity_factor_D12=0,
    pressure_continuity_factor=0,
):
    """
    Define the coupled equations. Also used by the SIMPLE and IPCS-A solvers

    Weak form of the Navier-Stokes eq. with discontinuous elements

    :type simulation: ocellaris.Simulation
    """
    sim = simulation
    show = sim.log.info
    show('    Creating DG weak form with BCs')
    show('        include_hydrostatic_pressure = %r' %
         include_hydrostatic_pressure)
    show('        incompressibility_flux_type = %s' %
         incompressibility_flux_type)
    show('        use_grad_q_form = %r' % use_grad_q_form)
    show('        use_grad_p_form = %r' % use_grad_p_form)
    show('        use_stress_divergence_form = %r' %
         use_stress_divergence_form)
    show('        velocity_continuity_factor_D12 = %r' %
         velocity_continuity_factor_D12)
    show('        pressure_continuity_factor = %r' %
         pressure_continuity_factor)

    mpm = sim.multi_phase_model
    mesh = sim.data['mesh']
    u_conv = sim.data['u_conv']
    dx = dolfin.dx(domain=mesh)
    dS = dolfin.dS(domain=mesh)

    c1, c2, c3 = sim.data['time_coeffs']
    dt = sim.data['dt']
    g = sim.data['g']
    n = dolfin.FacetNormal(mesh)
    x = dolfin.SpatialCoordinate(mesh)

    # Fluid properties
    rho = mpm.get_density(0)
    nu = mpm.get_laminar_kinematic_viscosity(0)
    mu = mpm.get_laminar_dynamic_viscosity(0)

    # Hydrostatic pressure correction
    if include_hydrostatic_pressure:
        p += sim.data['p_hydrostatic']

    # Start building the coupled equations
    eq = 0

    # ALE mesh velocities
    if sim.mesh_morpher.active:
        u_mesh = sim.data['u_mesh']

        # Either modify the convective velocity or just include the mesh
        # velocity on cell integral form. Only activate one of the lines below
        # PS: currently the UFL form splitter (used in e.g. IPCS-A) has a
        #     problem with line number 2, but the Coupled solver handles
        #     both options with approximately the same resulting convergence
        #     errors on the Taylor-Green test case (TODO: fix form splitter)
        u_conv -= u_mesh
        # eq -= dot(div(rho * dolfin.outer(u, u_mesh)), v) * dx

        # Divergence of u should balance expansion/contraction of the cell K
        # ∇⋅u = -∂x/∂t       (See below for definition of the ∇⋅u term)
        # THIS IS SOMEWHAT EXPERIMENTAL
        cvol_new = dolfin.CellVolume(mesh)
        cvol_old = sim.data['cvolp']
        eq += (cvol_new - cvol_old) / dt * q * dx

    # Elliptic penalties
    penalty_dS, penalty_ds, D11, D12 = navier_stokes_stabilization_penalties(
        sim, nu, velocity_continuity_factor_D12, pressure_continuity_factor)
    yh = 1 / penalty_ds

    # Upwind and downwind velocities
    w_nU = (dot(u_conv, n) + abs(dot(u_conv, n))) / 2.0
    w_nD = (dot(u_conv, n) - abs(dot(u_conv, n))) / 2.0

    # Lagrange multiplicator to remove the pressure null space
    # ∫ p dx = 0
    if lm_trial is not None:
        eq = (p * lm_test + q * lm_trial) * dx

    # Momentum equations
    for d in range(sim.ndim):
        up = sim.data['up%d' % d]
        upp = sim.data['upp%d' % d]

        # Divergence free criterion
        # ∇⋅u = 0
        if incompressibility_flux_type == 'central':
            u_hat_p = avg(u[d])
        elif incompressibility_flux_type == 'upwind':
            assert use_grad_q_form, 'Upwind only implemented for grad_q_form'
            switch = dolfin.conditional(dolfin.gt(w_nU('+'), 0.0), 1.0, 0.0)
            u_hat_p = switch * u[d]('+') + (1 - switch) * u[d]('-')

        if use_grad_q_form:
            eq -= u[d] * q.dx(d) * dx
            eq += (u_hat_p + D12[d] * jump(u, n)) * jump(q) * n[d]('+') * dS
        else:
            eq += q * u[d].dx(d) * dx
            eq -= (avg(q) - dot(D12, jump(q, n))) * jump(u[d]) * n[d]('+') * dS

        # Time derivative
        # ∂(ρu)/∂t
        eq += rho * (c1 * u[d] + c2 * up + c3 * upp) / dt * v[d] * dx

        # Convection:
        # -w⋅∇(ρu)
        flux_nU = u[d] * w_nU
        flux = jump(flux_nU)
        eq -= u[d] * dot(grad(rho * v[d]), u_conv) * dx
        eq += flux * jump(rho * v[d]) * dS

        # Stabilizing term when w is not divergence free
        eq += 1 / 2 * div(u_conv) * u[d] * v[d] * dx

        # Diffusion:
        # -∇⋅μ∇u
        eq += mu * dot(grad(u[d]), grad(v[d])) * dx

        # Symmetric Interior Penalty method for -∇⋅μ∇u
        eq -= avg(mu) * dot(n('+'), avg(grad(u[d]))) * jump(v[d]) * dS
        eq -= avg(mu) * dot(n('+'), avg(grad(v[d]))) * jump(u[d]) * dS

        # Symmetric Interior Penalty coercivity term
        eq += penalty_dS * jump(u[d]) * jump(v[d]) * dS

        # -∇⋅μ(∇u)^T
        if use_stress_divergence_form:
            eq += mu * dot(u.dx(d), grad(v[d])) * dx
            eq -= avg(mu) * dot(n('+'), avg(u.dx(d))) * jump(v[d]) * dS
            eq -= avg(mu) * dot(n('+'), avg(v.dx(d))) * jump(u[d]) * dS

        # Pressure
        # ∇p
        if use_grad_p_form:
            eq += v[d] * p.dx(d) * dx
            eq -= (avg(v[d]) + D12[d] * jump(v, n)) * jump(p) * n[d]('+') * dS
        else:
            eq -= p * v[d].dx(d) * dx
            eq += (avg(p) - dot(D12, jump(p, n))) * jump(v[d]) * n[d]('+') * dS

        # Pressure continuity stabilization. Needed for equal order discretization
        if D11 is not None:
            eq += D11 * dot(jump(p, n), jump(q, n)) * dS

        # Body force (gravity)
        # ρ g
        eq -= rho * g[d] * v[d] * dx

        # Other sources
        for f in sim.data['momentum_sources']:
            eq -= f[d] * v[d] * dx

        # Penalty forcing zones
        for fz in sim.data['forcing_zones'].get('u', []):
            eq += fz.penalty * fz.beta * (u[d] - fz.target[d]) * v[d] * dx

        # Boundary conditions that do not couple the velocity components
        # The BCs are imposed for each velocity component u[d] separately

        eq += add_dirichlet_bcs(sim, d, u, p, v, q, rho, mu, n, w_nU, w_nD,
                                penalty_ds, use_grad_q_form, use_grad_p_form)

        eq += add_neumann_bcs(sim, d, u, p, v, q, rho, mu, n, w_nU, w_nD,
                              penalty_ds, use_grad_q_form, use_grad_p_form)

        eq += add_robin_bcs(sim, d, u, p, v, q, rho, mu, n, w_nU, w_nD, yh,
                            use_grad_q_form, use_grad_p_form)

        eq += add_outlet_bcs(sim, d, u, p, v, q, rho, mu, n, w_nU, w_nD, g, x,
                             use_grad_q_form, use_grad_p_form)

    # Boundary conditions that couple the velocity components
    # Decomposing the velocity into wall normal and parallel parts

    eq += add_slip_bcs(sim, u, p, v, q, rho, mu, n, w_nU, w_nD, penalty_ds,
                       use_grad_q_form, use_grad_p_form)

    return eq
Ejemplo n.º 14
0
def compute_cell_values(f):
    mesh = f.function_space().mesh()
    V = dolfin.FunctionSpace(mesh, "DG", 0)
    v = dolfin.TestFunction(V)
    h = dolfin.CellVolume(mesh)
    return dolfin.assemble(f * v / h * dolfin.dx).array()
Ejemplo n.º 15
0
    def __init__(self, mesh, orientation):
        if orientation is None:
            # We assume convex domain and take center as ...
            orientation = mesh.coordinates().mean(axis=0)

        if isinstance(orientation, df.Mesh):
            # We set surface normal as outer with respect to orientation mesh
            assert orientation.id() in mesh.parent_entity_map

            n = df.FacetNormal(orientation)
            hA = df.FacetArea(orientation)
            # Project normal, we have a function on mesh
            DLT = df.VectorFunctionSpace(orientation,
                                         'Discontinuous Lagrange Trace', 0)
            n_ = df.Function(DLT)
            df.assemble((1 / hA) * df.inner(n, df.TestFunction(DLT)) * df.ds,
                        tensor=n_.vector())

            # Now we get it to manifold
            dx_ = df.Measure('dx', domain=mesh)
            V = df.VectorFunctionSpace(mesh, 'DG', 0)

            df.Function.__init__(self, V)

            hK = df.CellVolume(mesh)
            n_vec = xii.ii_convert(
                xii.ii_assemble(
                    (1 / hK) *
                    df.inner(xii.Trace(n_, mesh), df.TestFunction(V)) * dx_))

            self.vector()[:] = n_vec

            return None

        # Manifold assumption
        assert 1 <= mesh.topology().dim() < mesh.geometry().dim()
        gdim = mesh.geometry().dim()

        # Orientation from inside point
        if isinstance(orientation, (list, np.ndarray, tuple)):
            assert len(orientation) == gdim

            kwargs = {'x0%d' % i: val for i, val in enumerate(orientation)}
            orientation = ['x[%d] - x0%d' % (i, i) for i in range(gdim)]
            orientation = df.Expression(orientation, degree=1, **kwargs)

        assert orientation.ufl_shape == (gdim, )

        V = df.VectorFunctionSpace(mesh, 'DG', 0, gdim)
        df.Function.__init__(self, V)
        n_values = self.vector().get_local()

        X = mesh.coordinates()

        dd = X[np.argmin(X[:, 0])] - X[np.argmax(X[:, 0])]

        values = []
        R = np.array([[0, -1], [1, 0]])

        for cell in df.cells(mesh):
            n = cell.cell_normal().array()[:gdim]

            x = cell.midpoint().array()[:gdim]
            # Disagree?
            if np.inner(orientation(x), n) < 0:
                n *= -1.
            values.append(n / np.linalg.norm(n))

        values = np.array(values)

        for sub in range(gdim):
            dofs = V.sub(sub).dofmap().dofs()
            n_values[dofs] = values[:, sub]
        self.vector().set_local(n_values)
        self.vector().apply('insert')
Ejemplo n.º 16
0
    def initialize_variables(self):
        r"""
		Initialize the model variables to default values.  The variables
		defined here are:

		Various things :

		* ``self.element``    -- the finite-element
		* ``self.top_dim``    -- the topological dimension
		* ``self.dofmap``     -- :class:`~dolfin.cpp.fem.DofMap` for converting between vertex to nodal indicies
		* ``self.h``          -- Cell diameter formed by calling :func:`~dolfin.functions.specialfunctions.CellDiameter` with ``self.mesh``

		Grid velocity vector :math:`\mathbf{u}_i = [u\ v\ w]^{\intercal}`:

		* ``self.U_mag``      -- velocity vector magnitude
		* ``self.U3``         -- velocity vector
		* ``self.u``          -- :math:`x`-component of velocity vector
		* ``self.v``          -- :math:`y`-component of velocity vector
		* ``self.w``          -- :math:`z`-component of velocity vector

		Grid acceleration vector :math:`\mathbf{a}_i = [a_x\ a_y\ a_z]^{\intercal}`:

		* ``self.a_mag``      -- acceleration vector magnitude
		* ``self.a3``         -- acceleration vector
		* ``self.a_x``        -- :math:`x`-component of acceleration vector
		* ``self.a_y``        -- :math:`y`-component of acceleration vector
		* ``self.a_z``        -- :math:`z`-component of acceleration vector

		Grid internal force vector :math:`\mathbf{f}_i^{\mathrm{int}} = [f_x^{\mathrm{int}}\ f_y^{\mathrm{int}}\ f_z^{\mathrm{int}}]^{\intercal}`:

		* ``self.f_int_mag``  -- internal force vector magnitude
		* ``self.f_int``      -- internal force vector
		* ``self.f_int_x``    -- :math:`x`-component of internal force vector
		* ``self.f_int_y``    -- :math:`y`-component of internal force vector
		* ``self.f_int_z``    -- :math:`z`-component of internal force vector

		Grid mass :math:`m_i`:

		* ``self.m``          -- mass :math:`m_i`
		* ``self.m0``         -- inital mass :math:`m_i^0`
		"""
        s = "::: initializing grid variables :::"
        print_text(s, cls=self.this)

        # the finite-element used :
        self.element = self.Q.element()

        # topological dimension :
        self.top_dim = self.element.geometric_dimension()

        # map from verticies to nodes :
        self.dofmap = self.Q.dofmap()

        # for finding vertices sitting on boundary :
        self.d2v = dl.dof_to_vertex_map(self.Q)

        # list of arrays of vertices and bcs set by self.set_boundary_conditions() :
        self.bc_vrt = None
        self.bc_val = None

        # cell diameter :
        self.h = dl.project(dl.CellDiameter(self.mesh), self.Q)

        # cell volume :
        self.Ve = dl.project(dl.CellVolume(self.mesh), self.Q)

        # grid velocity :
        self.U_mag = dl.Function(self.Q, name='U_mag')
        self.U3 = dl.Function(self.Q3, name='U3')
        u, v, w = self.U3.split()
        u.rename('u', '')
        v.rename('v', '')
        w.rename('w', '')
        self.u = u
        self.v = v
        self.w = w

        # grid acceleration :
        self.a_mag = dl.Function(self.Q, name='a_mag')
        self.a3 = dl.Function(self.Q3, name='a3')
        a_x, a_y, a_z = self.a3.split()
        a_x.rename('a_x', '')
        a_y.rename('a_y', '')
        a_z.rename('a_z', '')
        self.a_x = a_x
        self.a_y = a_y
        self.a_z = a_z

        # grid internal force vector :
        self.f_int_mag = dl.Function(self.Q, name='f_int_mag')
        self.f_int = dl.Function(self.Q3, name='f_int')
        f_int_x, f_int_y, f_int_z = self.f_int.split()
        f_int_x.rename('f_int_x', '')
        f_int_y.rename('f_int_y', '')
        f_int_z.rename('f_int_z', '')
        self.f_int_x = f_int_x
        self.f_int_y = f_int_y
        self.f_int_z = f_int_z

        # grid mass :
        self.m = dl.Function(self.Q, name='m')
        self.m0 = dl.Function(self.Q, name='m0')

        # function assigners speed assigning up :
        self.assu = dl.FunctionAssigner(self.u.function_space(), self.Q)
        self.assv = dl.FunctionAssigner(self.v.function_space(), self.Q)
        self.assw = dl.FunctionAssigner(self.w.function_space(), self.Q)
        self.assa_x = dl.FunctionAssigner(self.a_x.function_space(), self.Q)
        self.assa_y = dl.FunctionAssigner(self.a_y.function_space(), self.Q)
        self.assa_z = dl.FunctionAssigner(self.a_z.function_space(), self.Q)
        self.assf_int_x = dl.FunctionAssigner(self.f_int_x.function_space(),
                                              self.Q)
        self.assf_int_y = dl.FunctionAssigner(self.f_int_y.function_space(),
                                              self.Q)
        self.assf_int_z = dl.FunctionAssigner(self.f_int_z.function_space(),
                                              self.Q)
        self.assm = dl.FunctionAssigner(self.m.function_space(), self.Q)

        # save the number of degrees of freedom :
        self.dofs = self.m.vector().size()
Ejemplo n.º 17
0
import dolfin as df
# from punc import load_mesh

fname = "/home/diako/Documents/cpp/punc/mesh/2D/circle_in_square_res1"
mesh = df.Mesh(fname + ".xml")

tdim = mesh.topology().dim()
gdim = mesh.geometry().dim()
cv = df.CellVolume(mesh)

V = df.FunctionSpace(mesh, 'CG', 1)
Q = df.FunctionSpace(mesh, 'DG', 0)
p, q = df.TrialFunction(Q), df.TestFunction(Q)
v = df.TestFunction(V)

ones = df.assemble((1. / cv) * df.inner(df.Constant(1), q) * df.dx)

dX = df.dx(
    metadata={
        'form_compiler_parameters': {
            'quadrature_degree': 1,
            'quadrature_scheme': 'vertex'
        }
    })

A = df.assemble(df.Constant(tdim + 1) * df.inner(p, v) * dX)

Av = df.Function(V).vector()
A.mult(ones, Av)

print(Av.size())
Ejemplo n.º 18
0
    def define_coupled_equation(self):
        """
        Setup the coupled Navier-Stokes equation

        This implementation assembles the full LHS and RHS each time they are needed
        """
        sim = self.simulation
        mpm = sim.multi_phase_model
        mesh = sim.data['mesh']
        Vcoupled = sim.data['Vcoupled']
        u_conv = sim.data['u_conv']

        # Unpack the coupled trial and test functions
        uc = dolfin.TrialFunction(Vcoupled)
        vc = dolfin.TestFunction(Vcoupled)
        ulist = []
        vlist = []
        ndim = self.simulation.ndim
        for d in range(ndim):
            ulist.append(uc[d])
            vlist.append(vc[d])

        u = dolfin.as_vector(ulist)
        v = dolfin.as_vector(vlist)
        p = uc[ndim]
        q = vc[ndim]

        c1, c2, c3 = sim.data['time_coeffs']
        dt = sim.data['dt']
        g = sim.data['g']
        n = dolfin.FacetNormal(mesh)

        # Fluid properties
        rho = mpm.get_density(0)
        mu = mpm.get_laminar_dynamic_viscosity(0)

        # Hydrostatic pressure correction
        if self.include_hydrostatic_pressure:
            p += sim.data['p_hydrostatic']

        # Start building the coupled equations
        eq = 0

        # ALE mesh velocities
        if sim.mesh_morpher.active:
            u_mesh = sim.data['u_mesh']

            # Either modify the convective velocity or just include the mesh
            # velocity on cell integral form. Only activate one of these lines
            # u_conv -= u_mesh
            eq -= dot(div(rho * dolfin.outer(u, u_mesh)), v) * dx

            # Divergence of u should balance expansion/contraction of the cell K
            # ∇⋅u = -∂x/∂t       (See below for definition of the ∇⋅u term)
            cvol_new = dolfin.CellVolume(mesh)
            cvol_old = sim.data['cvolp']
            eq += (cvol_new - cvol_old) / dt * q * dx

        # Lagrange multiplicator to remove the pressure null space
        # ∫ p dx = 0
        if self.use_lagrange_multiplicator:
            lm_trial = uc[ndim + 1]
            lm_test = vc[ndim + 1]
            eq = (p * lm_test + q * lm_trial) * dx

        # Momentum equations
        for d in range(sim.ndim):
            up = sim.data['up%d' % d]
            upp = sim.data['upp%d' % d]

            # Divergence free criterion
            # ∇⋅u = 0
            eq += u[d].dx(d) * q * dx

            # Time derivative
            # ∂u/∂t
            eq += rho * (c1 * u[d] + c2 * up + c3 * upp) / dt * v[d] * dx

            # Convection
            # ∇⋅(ρ u ⊗ u_conv)
            eq += rho * dot(u_conv, grad(u[d])) * v[d] * dx

            # Diffusion
            # -∇⋅μ(∇u)
            eq += mu * dot(grad(u[d]), grad(v[d])) * dx

            # -∇⋅μ(∇u)^T
            if self.use_stress_divergence_form:
                eq += mu * dot(u.dx(d), grad(v[d])) * dx

            # Pressure
            # ∇p
            eq -= v[d].dx(d) * p * dx

            # Body force (gravity)
            # ρ g
            eq -= rho * g[d] * v[d] * dx

            # Other sources
            for f in sim.data['momentum_sources']:
                eq -= f[d] * v[d] * dx

            # Neumann boundary conditions
            neumann_bcs_pressure = sim.data['neumann_bcs'].get('p', [])
            for nbc in neumann_bcs_pressure:
                eq += p * v[d] * n[d] * nbc.ds()

            # Outlet boundary
            for obc in sim.data['outlet_bcs']:
                # Diffusion
                mu_dudn = p * n[d]
                eq -= mu_dudn * v[d] * obc.ds()

                # Pressure
                p_ = mu * dot(dot(grad(u), n), n)
                eq += p_ * v[d] * n[d] * obc.ds()

        a, L = dolfin.system(eq)
        self.form_lhs = a
        self.form_rhs = L
        self.tensor_lhs = None
        self.tensor_rhs = None