Esempio n. 1
0
    def get_strandberg_I(self):
        u = self.unit_registry
        h = u('1 planck_constant')
        c = u('1 speed_of_light')
        kT = self.pdd.kT
        mu = self.pdd.mesh_util

        n_r = 1
        K = (8 * dolfin.pi * n_r **2) / (h**3 * c**2)

        E_L, E_U = self.get_absorption_bounds()

        # equivalent to flipping integration bounds if E_U < E_L
        sign = dolfin.conditional(dolfin.gt(
            E_U.magnitude,
            E_L.m_as(E_U.units)), +1, -1)

        # antiderivative of `E^2 exp(E/kT)`
        def F(E):
            return -kT*(2*kT**2 + 2*E*kT + E**2) * mu.exp(-E/kT)

        I = F(E_U) - F(E_L)

        ans = K * I * sign

        # to evaluate integrals
        # ans = (ans.m((0.0, 0.0)) * ans.units).to("1 / centimeter ** 2 / second")
        # print(self.src_band.key, self.dst_band.key, ans)

        return ans
Esempio n. 2
0
def nu_PWC_arit(phi, cc):
    A = df.conditional(df.gt(phi, 0.975), 1.0, 0.0)
    B = df.conditional(df.lt(phi, 0.025), 1.0, 0.0)
    nu = A * cc[r"\nu_1"]\
       + B * cc[r"\nu_2"]\
       + (1.0 - A - B) * 0.5 * (cc[r"\nu_1"] + cc[r"\nu_2"])
    return nu
Esempio n. 3
0
def nu_PWC_harm(phi, cc):
    A = df.conditional(df.gt(phi, 0.975), 1.0, 0.0)
    B = df.conditional(df.lt(phi, 0.025), 1.0, 0.0)
    nu = A * cc[r"\nu_1"]\
       + B * cc[r"\nu_2"]\
       + (1.0 - A - B) * 2.0 / (1.0 / cc[r"\nu_1"] + 1.0 / cc[r"\nu_2"])
    return nu
Esempio n. 4
0
def main():
    fsr = FunctionSubspaceRegistry()

    deg = 2
    mesh = dolfin.UnitSquareMesh(100, 3)
    muc = mesh.ufl_cell()
    el_w = dolfin.FiniteElement('DG', muc, deg - 1)
    el_j = dolfin.FiniteElement('BDM', muc, deg)
    el_DG0 = dolfin.FiniteElement('DG', muc, 0)
    el = dolfin.MixedElement([el_w, el_j])
    space = dolfin.FunctionSpace(mesh, el)
    DG0 = dolfin.FunctionSpace(mesh, el_DG0)
    fsr.register(space)
    facet_normal = dolfin.FacetNormal(mesh)
    xyz = dolfin.SpatialCoordinate(mesh)

    trial = dolfin.Function(space)
    test = dolfin.TestFunction(space)

    w, c = dolfin.split(trial)
    v, phi = dolfin.split(test)

    sympy_exprs = derive_exprs()
    exprs = {
        k: sympy_dolfin_printer.to_ufl(sympy_exprs['R'], mesh, v)
        for k, v in sympy_exprs['quantities'].items()
    }

    f = exprs['f']
    w0 = dolfin.project(dolfin.conditional(dolfin.gt(xyz[0], 0.5), 1.0, 0.3),
                        DG0)
    w_BC = exprs['w']

    dx = dolfin.dx()
    form = (+v * dolfin.div(c) * dx - v * f * dx +
            dolfin.exp(w + w0) * dolfin.dot(phi, c) * dx +
            dolfin.div(phi) * w * dx -
            (w_BC - w0) * dolfin.dot(phi, facet_normal) * dolfin.ds() -
            (w0('-') - w0('+')) * dolfin.dot(phi('+'), facet_normal('+')) *
            dolfin.dS())

    solver = NewtonSolver(form,
                          trial, [],
                          parameters=dict(relaxation_parameter=1.0,
                                          maximum_iterations=15,
                                          extra_iterations=10,
                                          relative_tolerance=1e-6,
                                          absolute_tolerance=1e-7))

    solver.solve()

    with closing(XdmfPlot("out/qflop_test.xdmf", fsr)) as X:
        CG1 = dolfin.FunctionSpace(mesh, dolfin.FiniteElement('CG', muc, 1))
        X.add('w0', 1, w0, CG1)
        X.add('w_c', 1, w + w0, CG1)
        X.add('w_e', 1, exprs['w'], CG1)
        X.add('f', 1, f, CG1)
        X.add('cx_c', 1, c[0], CG1)
        X.add('cx_e', 1, exprs['c'][0], CG1)
Esempio n. 5
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
Esempio n. 6
0
    def _setup_dg1_projection_2D(self, w, incompressibility_flux_type, D12,
                                 use_bcs):
        """
        Implement the projection where the result is BDM embeded in a DG1 function
        """
        sim = self.simulation
        k = 1
        gdim = 2
        mesh = w[0].function_space().mesh()
        V = VectorFunctionSpace(mesh, 'DG', k)
        W = FunctionSpace(mesh, 'DGT', k)
        n = FacetNormal(mesh)

        v1 = TestFunction(W)
        u = TrialFunction(V)

        # The same fluxes that are used in the incompressibility equation
        if incompressibility_flux_type == 'central':
            u_hat_dS = dolfin.avg(w)
        elif incompressibility_flux_type == 'upwind':
            w_nU = (dot(w, n) + abs(dot(w, n))) / 2.0
            switch = dolfin.conditional(dolfin.gt(w_nU('+'), 0.0), 1.0, 0.0)
            u_hat_dS = switch * w('+') + (1 - switch) * w('-')

        if D12 is not None:
            u_hat_dS += dolfin.Constant([D12, D12]) * dolfin.jump(w, n)

        # Equation 1 - flux through the sides
        a = L = 0
        for R in '+-':
            a += dot(u(R), n(R)) * v1(R) * dS
            L += dot(u_hat_dS, n(R)) * v1(R) * dS

        # Eq. 1 cont. - flux through external boundaries
        a += dot(u, n) * v1 * ds
        if use_bcs:
            for d in range(gdim):
                dirichlet_bcs = sim.data['dirichlet_bcs']['u%d' % d]
                neumann_bcs = sim.data['neumann_bcs'].get('u%d' % d, [])
                robin_bcs = sim.data['robin_bcs'].get('u%d' % d, [])
                outlet_bcs = sim.data['outlet_bcs']

                for dbc in dirichlet_bcs:
                    u_bc = dbc.func()
                    L += u_bc * n[d] * v1 * dbc.ds()

                for nbc in neumann_bcs + robin_bcs + outlet_bcs:
                    if nbc.enforce_zero_flux:
                        pass  # L += 0
                    else:
                        L += w[d] * n[d] * v1 * nbc.ds()

            for sbc in sim.data['slip_bcs'].get('u', []):
                pass  # L += 0
        else:
            L += dot(w, n) * v1 * ds

        # Equation 2 - internal shape   :   empty for DG1
        # Equation 3 - BDM Phi          :   empty for DG1

        return a, L, V
Esempio n. 7
0
    def _setup_projection_nedelec(self, w, incompressibility_flux_type, D12,
                                  use_bcs, pdeg, gdim):
        """
        Implement the BDM-like projection using Nedelec elements in the test function
        """
        sim = self.simulation
        k = pdeg
        mesh = w[0].function_space().mesh()
        V = VectorFunctionSpace(mesh, 'DG', k)
        n = FacetNormal(mesh)

        # The mixed function space of the projection test functions
        e1 = FiniteElement('DGT', mesh.ufl_cell(), k)
        e2 = FiniteElement('N1curl', mesh.ufl_cell(), k - 1)
        em = MixedElement([e1, e2])
        W = FunctionSpace(mesh, em)
        v1, v2 = TestFunctions(W)
        u = TrialFunction(V)

        # The same fluxes that are used in the incompressibility equation
        if incompressibility_flux_type == 'central':
            u_hat_dS = dolfin.avg(w)
        elif incompressibility_flux_type == 'upwind':
            w_nU = (dot(w, n) + abs(dot(w, n))) / 2.0
            switch = dolfin.conditional(dolfin.gt(w_nU('+'), 0.0), 1.0, 0.0)
            u_hat_dS = switch * w('+') + (1 - switch) * w('-')

        if D12 is not None:
            u_hat_dS += dolfin.Constant([D12] * gdim) * dolfin.jump(w, n)

        # Equation 1 - flux through the sides
        a = L = 0
        for R in '+-':
            a += dot(u(R), n(R)) * v1(R) * dS
            L += dot(u_hat_dS, n(R)) * v1(R) * dS

        # Eq. 1 cont. - flux through external boundaries
        a += dot(u, n) * v1 * ds
        if use_bcs:
            for d in range(gdim):
                dirichlet_bcs = sim.data['dirichlet_bcs'].get('u%d' % d, [])
                neumann_bcs = sim.data['neumann_bcs'].get('u%d' % d, [])
                robin_bcs = sim.data['robin_bcs'].get('u%d' % d, [])
                outlet_bcs = sim.data['outlet_bcs']

                for dbc in dirichlet_bcs:
                    u_bc = dbc.func()
                    L += u_bc * n[d] * v1 * dbc.ds()

                for nbc in neumann_bcs + robin_bcs + outlet_bcs:
                    if nbc.enforce_zero_flux:
                        pass  # L += 0
                    else:
                        L += w[d] * n[d] * v1 * nbc.ds()

            for sbc in sim.data['slip_bcs'].get('u', []):
                pass  # L += 0
        else:
            L += dot(w, n) * v1 * ds

        # Equation 2 - internal shape using 'Nedelec 1st kind H(curl)' elements
        a += dot(u, v2) * dx
        L += dot(w, v2) * dx

        return a, L, V
Esempio n. 8
0
    def _setup_dg2_projection_2D(self, w, incompressibility_flux_type, D12,
                                 use_bcs):
        """
        Implement the projection where the result is BDM embeded in a DG2 function
        """
        sim = self.simulation
        k = 2
        gdim = 2
        mesh = w[0].function_space().mesh()
        V = VectorFunctionSpace(mesh, 'DG', k)
        n = FacetNormal(mesh)

        # The mixed function space of the projection test functions
        e1 = FiniteElement('DGT', mesh.ufl_cell(), k)
        e2 = VectorElement('DG', mesh.ufl_cell(), k - 2)
        e3 = FiniteElement('Bubble', mesh.ufl_cell(), 3)
        em = MixedElement([e1, e2, e3])
        W = FunctionSpace(mesh, em)
        v1, v2, v3b = TestFunctions(W)
        u = TrialFunction(V)

        # The same fluxes that are used in the incompressibility equation
        if incompressibility_flux_type == 'central':
            u_hat_dS = dolfin.avg(w)
        elif incompressibility_flux_type == 'upwind':
            w_nU = (dot(w, n) + abs(dot(w, n))) / 2.0
            switch = dolfin.conditional(dolfin.gt(w_nU('+'), 0.0), 1.0, 0.0)
            u_hat_dS = switch * w('+') + (1 - switch) * w('-')

        if D12 is not None:
            u_hat_dS += dolfin.Constant([D12, D12]) * dolfin.jump(w, n)

        # Equation 1 - flux through the sides
        a = L = 0
        for R in '+-':
            a += dot(u(R), n(R)) * v1(R) * dS
            L += dot(u_hat_dS, n(R)) * v1(R) * dS

        # Eq. 1 cont. - flux through external boundaries
        a += dot(u, n) * v1 * ds
        if use_bcs:
            for d in range(gdim):
                dirichlet_bcs = sim.data['dirichlet_bcs']['u%d' % d]
                neumann_bcs = sim.data['neumann_bcs'].get('u%d' % d, [])
                robin_bcs = sim.data['robin_bcs'].get('u%d' % d, [])
                outlet_bcs = sim.data['outlet_bcs']

                for dbc in dirichlet_bcs:
                    u_bc = dbc.func()
                    L += u_bc * n[d] * v1 * dbc.ds()

                for nbc in neumann_bcs + robin_bcs + outlet_bcs:
                    if nbc.enforce_zero_flux:
                        pass  # L += 0
                    else:
                        L += w[d] * n[d] * v1 * nbc.ds()

            for sbc in sim.data['slip_bcs'].get('u', []):
                pass  # L += 0
        else:
            L += dot(w, n) * v1 * ds

        # Equation 2 - internal shape
        a += dot(u, v2) * dx
        L += dot(w, v2) * dx

        # Equation 3 - BDM Phi
        v3 = as_vector([v3b.dx(1), -v3b.dx(0)])  # Curl of [0, 0, v3b]
        a += dot(u, v3) * dx
        L += dot(w, v3) * dx

        return a, L, V
Esempio n. 9
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
Esempio n. 10
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 = []
        sigmas, taus = [], []
        for d in range(sim.ndim):
            ulist.append(uc[d])
            vlist.append(vc[d])
            indices = list(
                range(1 + sim.ndim * (d + 1), 1 + sim.ndim * (d + 2)))
            sigmas.append([uc[i] for i in indices])
            taus.append([vc[i] for i in indices])

        u = dolfin.as_vector(ulist)
        v = dolfin.as_vector(vlist)
        p = uc[sim.ndim]
        q = vc[sim.ndim]
        sigma = dolfin.as_tensor(sigmas)
        tau = dolfin.as_tensor(taus)

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

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

        # 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
        u_uw_s = dolfin.conditional(dolfin.gt(dot(u_conv, n), 0.0), 1.0,
                                    0.0)('+')
        u_uw = u_uw_s * u('+') + (1 - u_uw_s) * u('-')

        # LDG penalties
        # kappa_0 = Constant(4.0)
        # kappa = mu*kappa_0/h
        C11 = avg(mu / h)
        D11 = avg(h / mu)
        C12 = 0.2 * n('+')
        D12 = 0.2 * n('+')

        def ojump(v, n):
            return outer(v, n)('+') + outer(v, n)('-')

        # Interior facet fluxes
        # u_hat_dS = avg(u)
        # sigma_hat_dS = avg(sigma) - avg(kappa)*ojump(u, n)
        # p_hat_dS = avg(p)
        u_hat_s_dS = avg(u) + dot(ojump(u, n), C12)
        u_hat_p_dS = avg(u) + D11 * jump(p, n) + D12 * jump(u, n)
        sigma_hat_dS = avg(sigma) - C11 * ojump(u, n) - outer(
            jump(sigma, n), C12)
        p_hat_dS = avg(p) - dot(D12, jump(p, n))

        # Time derivative
        up = sim.data['up']
        upp = sim.data['upp']
        eq = rho * dot(c1 * u + c2 * up + c3 * upp, v) / dt * dx

        # LDG equation 1
        eq += inner(sigma, tau) * dx
        eq += dot(u, div(mu * tau)) * dx
        eq -= dot(u_hat_s_dS, jump(mu * tau, n)) * dS

        # LDG equation 2
        eq += (inner(sigma, grad(v)) - p * div(v)) * dx
        eq -= (inner(sigma_hat_dS, ojump(v, n)) - p_hat_dS * jump(v, n)) * dS
        eq -= dot(u, div(outer(v, rho * u_conv))) * dx
        eq += rho('+') * dot(u_conv('+'), n('+')) * dot(u_uw, v('+')) * dS
        eq += rho('-') * dot(u_conv('-'), n('-')) * dot(u_uw, v('-')) * dS
        momentum_sources = sim.data['momentum_sources'] + [rho * g]
        eq -= dot(sum(momentum_sources), v) * dx

        # LDG equation 3
        eq -= dot(u, grad(q)) * dx
        eq += dot(u_hat_p_dS, jump(q, n)) * dS

        # Dirichlet boundary
        dirichlet_bcs = get_collected_velocity_bcs(sim, 'dirichlet_bcs')
        for ds, u_bc in dirichlet_bcs.items():
            # sigma_hat_ds = sigma - kappa*outer(u, n)
            sigma_hat_ds = sigma - C11 * outer(u - u_bc, n)
            u_hat_ds = u_bc
            p_hat_ds = p

            # LDG equation 1
            eq -= dot(u_hat_ds, dot(mu * tau, n)) * ds

            # LDG equation 2
            eq -= (inner(sigma_hat_ds, outer(v, n)) -
                   p_hat_ds * dot(v, n)) * ds
            eq += rho * w_nU * dot(u, v) * ds
            eq += rho * w_nD * dot(u_bc, v) * ds

            # LDG equation 3
            eq += dot(u_hat_ds, q * n) * ds

        # Neumann boundary
        neumann_bcs = get_collected_velocity_bcs(sim, 'neumann_bcs')
        assert not neumann_bcs
        for ds, du_bc in neumann_bcs.items():
            # Divergence free criterion
            if self.use_grad_q_form:
                eq += q * dot(u, n) * ds
            else:
                eq -= q * dot(u, n) * ds

            # Convection
            eq += rho * w_nU * dot(u, v) * ds

            # Diffusion
            u_hat_ds = u
            sigma_hat_ds = outer(du_bc, n) / mu
            eq -= dot(u_hat_ds, dot(mu * tau, n)) * ds
            eq -= inner(sigma_hat_ds, outer(v, n)) * ds

            # Pressure
            if not self.use_grad_p_form:
                eq += p * dot(v, n) * ds

        a, L = dolfin.system(eq)
        self.form_lhs = a
        self.form_rhs = L
        self.tensor_lhs = None
        self.tensor_rhs = None
Esempio n. 11
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
        sigma, tau = [], []
        for d in range(ndim):
            ulist.append(uc[d])
            vlist.append(vc[d])
            indices = list(range(1 + ndim * (d + 1), 1 + ndim * (d + 2)))
            sigma.append(dolfin.as_vector([uc[i] for i in indices]))
            tau.append(dolfin.as_vector([vc[i] for i in indices]))

        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)

        # 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

        # LDG penalties
        C11 = Constant(1.0 + sim.ndim)
        switch = dolfin.conditional(dolfin.gt(w_nU('+'), 0.0), n('+'), n('-'))
        C12 = 0.5 * switch

        # Start building the coupled equations
        eq = 0

        # 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
            u_hat_p = avg(u[d])
            if self.use_grad_q_form:
                eq -= u[d] * q.dx(d) * dx
                eq += u_hat_p * jump(q) * n[d]('+') * dS
            else:
                eq += q * u[d].dx(d) * dx
                eq -= avg(q) * 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

            # Diffusion:
            # -∇⋅∇u
            u_hat_dS = avg(u[d]) - dot(C12, jump(u[d], n))
            sigma_hat_dS = avg(
                sigma[d]) - C11 * jump(u[d], n) + C12 * jump(sigma[d], n)
            eq += dot(sigma[d], tau[d]) * dx
            eq += u[d] * div(mu * tau[d]) * dx
            eq -= u_hat_dS * jump(mu * tau[d], n) * dS
            eq += dot(sigma[d], grad(v[d])) * dx
            eq -= dot(sigma_hat_dS, jump(v[d], n)) * dS

            # Pressure
            # ∇p
            if self.use_grad_p_form:
                eq += v[d] * p.dx(d) * dx
                eq -= avg(v[d]) * jump(p) * n[d]('+') * dS
            else:
                eq -= p * v[d].dx(d) * dx
                eq += avg(p) * jump(v[d]) * n[d]('+') * 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

            # Dirichlet boundary
            dirichlet_bcs = sim.data['dirichlet_bcs'].get('u%d' % d, [])
            for dbc in dirichlet_bcs:
                u_bc = dbc.func()

                # Divergence free criterion
                if self.use_grad_q_form:
                    eq += q * u_bc * n[d] * dbc.ds()
                else:
                    eq -= q * u[d] * n[d] * dbc.ds()
                    eq += q * u_bc * n[d] * dbc.ds()

                # Convection
                eq += rho * u[d] * w_nU * v[d] * dbc.ds()
                eq += rho * u_bc * w_nD * v[d] * dbc.ds()

                # Diffusion
                u_hat_ds = u_bc
                sigma_hat_ds = sigma[d] - C11 * (u[d] - u_bc) * n
                eq -= u_hat_ds * mu * dot(tau[d], n) * dbc.ds()
                eq -= dot(sigma_hat_ds, n) * v[d] * dbc.ds()

                # Pressure
                if not self.use_grad_p_form:
                    eq += p * v[d] * n[d] * dbc.ds()

            # Neumann boundary
            neumann_bcs = sim.data['neumann_bcs'].get('u%d' % d, [])
            for nbc in neumann_bcs:
                # Divergence free criterion
                if self.use_grad_q_form:
                    eq += q * u[d] * n[d] * nbc.ds()
                else:
                    eq -= q * u[d] * n[d] * nbc.ds()

                # Convection
                eq += rho * u[d] * w_nU * v[d] * nbc.ds()

                # Diffusion
                u_hat_ds = u[d]
                sigma_hat_ds = nbc.func() / mu * n
                eq -= u_hat_ds * mu * dot(tau[d], n) * nbc.ds()
                eq -= dot(sigma_hat_ds, n) * v[d] * nbc.ds()

                # Pressure
                if not self.use_grad_p_form:
                    eq += p * v[d] * n[d] * nbc.ds()

        a, L = dolfin.system(eq)
        self.form_lhs = a
        self.form_rhs = L
        self.tensor_lhs = None
        self.tensor_rhs = None
    hdf.read(h_eff0, "h_eff")
    assigner_s.assign(T, [B0, Qs0, h_s0, h_s_0, h_eff0])
    assigner_g.assign(U, [ubar0, udef0, H0, H0_])

# Save the time series
hdf = HDF5File(mesh.mpi_comm(), out_file + ".h5", "w")
hdf.write(mesh, "mesh")

t = t_start
# Loop over time
while t < t_end:
    ax[0].set_title(t)

    try:  # If the solvers don't converge, reduce the time step and try again.
        bmelt = -20.0
        bdot = df.conditional(df.gt(H, np.abs(bmelt)), bmelt,
                              -H) * (1 - grounded)

        P = None
        if climate in "ltop":
            P = get_adot_from_orog_precip(ltop_constants)
            adot.vector().set_local(P)
        print(t, dt_float, H0.vector().max(), df.assemble(h_s0 * df.dx))

        assigner_s.assign(T, [B0, Qs0, h_s0, h_s_0, h_eff0])
        assigner_g.assign(U, [ubar0, udef0, H0, H0_])

        # Solve for water flux
        df.solve(A_Qw == b_Qw, Qw)

        # Solve for sediment variables