Пример #1
0
    def advection_term(self, q):

        if self.state.mesh.topological_dimension() == 3:
            # <w,curl(u) cross ubar + grad( u.ubar)>
            # =<curl(u),ubar cross w> - <div(w), u.ubar>
            # =<u,curl(ubar cross w)> -
            #      <<u_upwind, [[n cross(ubar cross w)cross]]>>

            both = lambda u: 2 * avg(u)

            L = (inner(q, curl(cross(self.ubar, self.test))) * dx -
                 inner(both(self.Upwind * q),
                       both(cross(self.n, cross(self.ubar, self.test)))) *
                 self.dS)

        else:

            if self.ibp == "once":
                L = (-inner(
                    self.gradperp(inner(self.test, self.perp(self.ubar))), q) *
                     dx - inner(
                         jump(inner(self.test, self.perp(self.ubar)), self.n),
                         self.perp_u_upwind(q)) * self.dS)
            else:
                L = (
                    (-inner(self.test,
                            div(self.perp(q)) * self.perp(self.ubar))) * dx -
                    inner(jump(inner(self.test, self.perp(self.ubar)), self.n),
                          self.perp_u_upwind(q)) * self.dS + jump(
                              inner(self.test, self.perp(self.ubar)) *
                              self.perp(q), self.n) * self.dS)

        L -= 0.5 * div(self.test) * inner(q, self.ubar) * dx

        return L
Пример #2
0
    def setup(self, state):
        if not self._initialised:
            space = state.spaces("Vv")
            super().setup(state, space=space)
            rho = state.fields("rho")
            rhobar = state.fields("rhobar")
            theta = state.fields("theta")
            thetabar = state.fields("thetabar")
            pi = thermodynamics.pi(state.parameters, rho, theta)
            pibar = thermodynamics.pi(state.parameters, rhobar, thetabar)

            cp = Constant(state.parameters.cp)
            n = FacetNormal(state.mesh)

            F = TrialFunction(space)
            w = TestFunction(space)
            a = inner(w, F)*dx
            L = (- cp*div((theta-thetabar)*w)*pibar*dx
                 + cp*jump((theta-thetabar)*w, n)*avg(pibar)*dS_v
                 - cp*div(thetabar*w)*(pi-pibar)*dx
                 + cp*jump(thetabar*w, n)*avg(pi-pibar)*dS_v)

            bcs = [DirichletBC(space, 0.0, "bottom"),
                   DirichletBC(space, 0.0, "top")]

            imbalanceproblem = LinearVariationalProblem(a, L, self.field, bcs=bcs)
            self.imbalance_solver = LinearVariationalSolver(imbalanceproblem)
Пример #3
0
 def form(u, v):
     return inner(div(grad(u)), div(grad(v)))*dx \
         - inner(avg(div(grad(u))), jump(grad(v), n))*dS \
         - inner(jump(grad(u), n), avg(div(grad(v))))*dS \
         + alpha/h*inner(jump(grad(u), n), jump(grad(v), n))*dS \
         - inner(div(grad(u)), inner(grad(v), n))*ds \
         - inner(inner(grad(u), n), div(grad(v)))*ds \
         + alpha/h*inner(grad(u), grad(v))*ds
Пример #4
0
def vector_invariant_form(state, test, q, ibp=IntegrateByParts.ONCE):

    Vu = state.spaces("HDiv")
    dS_ = (dS_v + dS_h) if Vu.extruded else dS
    ubar = Function(Vu)
    n = FacetNormal(state.mesh)
    Upwind = 0.5 * (sign(dot(ubar, n)) + 1)

    if state.mesh.topological_dimension() == 3:

        if ibp != IntegrateByParts.ONCE:
            raise NotImplementedError

        # <w,curl(u) cross ubar + grad( u.ubar)>
        # =<curl(u),ubar cross w> - <div(w), u.ubar>
        # =<u,curl(ubar cross w)> -
        #      <<u_upwind, [[n cross(ubar cross w)cross]]>>

        both = lambda u: 2 * avg(u)

        L = (inner(q, curl(cross(ubar, test))) * dx -
             inner(both(Upwind * q), both(cross(n, cross(ubar, test)))) * dS_)

    else:

        perp = state.perp
        if state.on_sphere:
            outward_normals = CellNormal(state.mesh)
            perp_u_upwind = lambda q: Upwind('+') * cross(
                outward_normals('+'), q('+')) + Upwind('-') * cross(
                    outward_normals('-'), q('-'))
        else:
            perp_u_upwind = lambda q: Upwind('+') * perp(q('+')) + Upwind(
                '-') * perp(q('-'))

        if ibp == IntegrateByParts.ONCE:
            L = (-inner(perp(grad(inner(test, perp(ubar)))), q) * dx -
                 inner(jump(inner(test, perp(ubar)), n), perp_u_upwind(q)) *
                 dS_)
        else:
            L = ((-inner(test,
                         div(perp(q)) * perp(ubar))) * dx -
                 inner(jump(inner(test, perp(ubar)), n), perp_u_upwind(q)) *
                 dS_ + jump(inner(test, perp(ubar)) * perp(q), n) * dS_)

    L -= 0.5 * div(test) * inner(q, ubar) * dx

    form = transporting_velocity(L, ubar)

    return transport(form, TransportEquationType.vector_invariant)
Пример #5
0
def continuity_form(state, test, q, ibp=IntegrateByParts.ONCE, outflow=False):

    if outflow and ibp == IntegrateByParts.NEVER:
        raise ValueError(
            "outflow is True and ibp is None are incompatible options")
    Vu = state.spaces("HDiv")
    dS_ = (dS_v + dS_h) if Vu.extruded else dS
    ubar = Function(Vu)

    if ibp == IntegrateByParts.ONCE:
        L = -inner(grad(test), outer(q, ubar)) * dx
    else:
        L = inner(test, div(outer(q, ubar))) * dx

    if ibp != IntegrateByParts.NEVER:
        n = FacetNormal(state.mesh)
        un = 0.5 * (dot(ubar, n) + abs(dot(ubar, n)))

        L += dot(jump(test), (un('+') * q('+') - un('-') * q('-'))) * dS_

        if ibp == IntegrateByParts.TWICE:
            L -= (inner(test('+'),
                        dot(ubar('+'), n('+')) * q('+')) +
                  inner(test('-'),
                        dot(ubar('-'), n('-')) * q('-'))) * dS_

    if outflow:
        n = FacetNormal(state.mesh)
        un = 0.5 * (dot(ubar, n) + abs(dot(ubar, n)))
        L += test * un * q * (ds_v + ds_t + ds_b)

    form = transporting_velocity(L, ubar)

    return ibp_label(transport(form, TransportEquationType.conservative), ibp)
Пример #6
0
    def __init__(self, state, linear=False):
        self.state = state

        g = state.parameters.g
        f = state.f

        Vu = state.V[0]
        W = state.W

        self.x0 = Function(W)  # copy x to here

        u0, D0 = split(self.x0)
        n = FacetNormal(state.mesh)
        un = 0.5 * (dot(u0, n) + abs(dot(u0, n)))

        F = TrialFunction(Vu)
        w = TestFunction(Vu)
        self.uF = Function(Vu)

        outward_normals = CellNormal(state.mesh)
        perp = lambda u: cross(outward_normals, u)
        a = inner(w, F) * dx
        L = (-f * inner(w, perp(u0)) + g * div(w) * D0) * dx - g * inner(
            jump(w, n), un("+") * D0("+") - un("-") * D0("-")
        ) * dS

        if not linear:
            L -= 0.5 * div(w) * inner(u0, u0) * dx

        u_forcing_problem = LinearVariationalProblem(a, L, self.uF)

        self.u_forcing_solver = LinearVariationalSolver(u_forcing_problem)
Пример #7
0
    def __init__(self, state, V, direction=[], supg_params=None):
        super(SUPGAdvection, self).__init__(state)
        dt = state.timestepping.dt
        params = supg_params.copy() if supg_params else {}
        params.setdefault('a0', dt/sqrt(15.))
        params.setdefault('a1', dt/sqrt(15.))

        gamma = TestFunction(V)
        theta = TrialFunction(V)
        self.theta0 = Function(V)

        # make SUPG test function
        taus = [params["a0"], params["a1"]]
        for i in direction:
            taus[i] = 0.0
        tau = Constant(((taus[0], 0.), (0., taus[1])))

        dgamma = dot(dot(self.ubar, tau), grad(gamma))
        gammaSU = gamma + dgamma

        n = FacetNormal(state.mesh)
        un = 0.5*(dot(self.ubar, n) + abs(dot(self.ubar, n)))

        a_mass = gammaSU*theta*dx
        arhs = a_mass - dt*gammaSU*dot(self.ubar, grad(theta))*dx

        if 1 in direction:
            arhs -= (
                dt*dot(jump(gammaSU), (un('+')*theta('+')
                                       - un('-')*theta('-')))*dS_v
                - dt*(gammaSU('+')*dot(self.ubar('+'), n('+'))*theta('+')
                      + gammaSU('-')*dot(self.ubar('-'), n('-'))*theta('-'))*dS_v
            )
        if 2 in direction:
            arhs -= (
                dt*dot(jump(gammaSU), (un('+')*theta('+')
                                       - un('-')*theta('-')))*dS_h
                - dt*(gammaSU('+')*dot(self.ubar('+'), n('+'))*theta('+')
                      + gammaSU('-')*dot(self.ubar('-'), n('-'))*theta('-'))*dS_h
            )

        self.theta1 = Function(V)
        self.dtheta = Function(V)
        problem = LinearVariationalProblem(a_mass, action(arhs,self.theta1), self.dtheta)
        self.solver = LinearVariationalSolver(problem,
                                              options_prefix='SUPGAdvection')
Пример #8
0
    def advection_term(self, q):

        n = FacetNormal(self.state.mesh)
        Upwind = 0.5 * (sign(dot(self.ubar, n)) + 1)

        if self.state.mesh.topological_dimension() == 3:
            # <w,curl(u) cross ubar + grad( u.ubar)>
            # =<curl(u),ubar cross w> - <div(w), u.ubar>
            # =<u,curl(ubar cross w)> -
            #      <<u_upwind, [[n cross(ubar cross w)cross]]>>

            both = lambda u: 2 * avg(u)

            L = (inner(q, curl(cross(self.ubar, self.test))) * dx -
                 inner(both(Upwind * q),
                       both(cross(n, cross(self.ubar, self.test)))) * self.dS)

        else:

            perp = self.state.perp
            if self.state.on_sphere:
                outward_normals = CellNormal(self.state.mesh)
                perp_u_upwind = lambda q: Upwind('+') * cross(
                    outward_normals('+'), q('+')) + Upwind('-') * cross(
                        outward_normals('-'), q('-'))
            else:
                perp_u_upwind = lambda q: Upwind('+') * perp(q('+')) + Upwind(
                    '-') * perp(q('-'))

            if self.ibp == IntegrateByParts.ONCE:
                L = (-inner(perp(grad(inner(self.test, perp(self.ubar)))), q) *
                     dx - inner(jump(inner(self.test, perp(self.ubar)), n),
                                perp_u_upwind(q)) * self.dS)
            else:
                L = ((-inner(self.test,
                             div(perp(q)) * perp(self.ubar))) * dx -
                     inner(jump(inner(self.test, perp(self.ubar)), n),
                           perp_u_upwind(q)) * self.dS +
                     jump(inner(self.test, perp(self.ubar)) * perp(q), n) *
                     self.dS)

        L -= 0.5 * div(self.test) * inner(q, self.ubar) * dx

        return L
Пример #9
0
    def advection_term(self, q):

        if self.continuity:
            n = FacetNormal(self.state.mesh)
            L = (-dot(grad(self.test), self.ubar) * self.qbar * dx +
                 jump(self.ubar * self.test, n) * avg(self.qbar) * self.dS)
        else:
            L = self.test * dot(self.ubar, self.state.k) * dot(
                self.state.k, grad(self.qbar)) * dx
        return L
Пример #10
0
    def topography_term(self):
        g = self.state.parameters.g
        u0, _ = split(self.x0)
        b = self.state.fields("topography")
        n = FacetNormal(self.state.mesh)
        un = 0.5 * (dot(u0, n) + abs(dot(u0, n)))

        L = g * div(self.test) * b * dx - g * inner(
            jump(self.test, n),
            un('+') * b('+') - un('-') * b('-')) * dS
        return L
Пример #11
0
    def pressure_gradient_term(self):

        g = self.state.parameters.g
        u0, D0 = split(self.x0)
        n = FacetNormal(self.state.mesh)
        un = 0.5 * (dot(u0, n) + abs(dot(u0, n)))

        L = g * (div(self.test) * D0 * dx -
                 inner(jump(self.test, n),
                       un('+') * D0('+') - un('-') * D0('-')) * dS)
        return L
Пример #12
0
    def _build_forcing_solver(self, linear):
        """
        Only put forcing terms into the u equation.
        """

        state = self.state
        self.scaling = Constant(1.0)
        Vu = state.V[0]
        W = state.W

        self.x0 = Function(W)  # copy x to here

        u0, rho0, theta0 = split(self.x0)

        F = TrialFunction(Vu)
        w = TestFunction(Vu)
        self.uF = Function(Vu)

        Omega = state.Omega
        cp = state.parameters.cp
        mu = state.mu

        n = FacetNormal(state.mesh)

        pi = exner(theta0, rho0, state)

        a = inner(w, F) * dx
        L = self.scaling * (
            +cp * div(theta0 * w) * pi * dx  # pressure gradient [volume]
            - cp * jump(w * theta0, n) * avg(pi) * dS_v  # pressure gradient [surface]
        )

        if state.parameters.geopotential:
            Phi = state.Phi
            L += self.scaling * div(w) * Phi * dx  # gravity term
        else:
            g = state.parameters.g
            L -= self.scaling * g * inner(w, state.k) * dx  # gravity term

        if not linear:
            L -= self.scaling * 0.5 * div(w) * inner(u0, u0) * dx

        if Omega is not None:
            L -= self.scaling * inner(w, cross(2 * Omega, u0)) * dx  # Coriolis term

        if mu is not None:
            self.mu_scaling = Constant(1.0)
            L -= self.mu_scaling * mu * inner(w, state.k) * inner(u0, state.k) * dx

        bcs = [DirichletBC(Vu, 0.0, "bottom"), DirichletBC(Vu, 0.0, "top")]

        u_forcing_problem = LinearVariationalProblem(a, L, self.uF, bcs=bcs)

        self.u_forcing_solver = LinearVariationalSolver(u_forcing_problem)
Пример #13
0
def form_function(u, h, v, q):
    K = 0.5 * fd.inner(u, u)
    n = fd.FacetNormal(mesh)
    uup = 0.5 * (fd.dot(u, n) + abs(fd.dot(u, n)))
    Upwind = 0.5 * (fd.sign(fd.dot(u, n)) + 1)

    eqn = (fd.inner(v, f * perp(u)) * fd.dx -
           fd.inner(perp(fd.grad(fd.inner(v, perp(u)))), u) * fd.dx +
           fd.inner(both(perp(n) * fd.inner(v, perp(u))), both(Upwind * u)) *
           fd.dS - fd.div(v) * (g * (h + b) + K) * fd.dx -
           fd.inner(fd.grad(q), u) * h * fd.dx + fd.jump(q) *
           (uup('+') * h('+') - uup('-') * h('-')) * fd.dS)
    return eqn
Пример #14
0
def linear_continuity_form(state, test, qbar, facet_term=False):

    Vu = state.spaces("HDiv")
    ubar = Function(Vu)

    L = qbar * test * div(ubar) * dx

    if facet_term:
        n = FacetNormal(state.mesh)
        Vu = state.spaces("HDiv")
        dS_ = (dS_v + dS_h) if Vu.extruded else dS
        L += jump(ubar * test, n) * avg(qbar) * dS_

    form = transporting_velocity(L, ubar)

    return transport(form, TransportEquationType.conservative)
Пример #15
0
    def dgls_form(self, problem, mesh, bcs_p):
        rho = problem.rho
        mu = problem.mu
        k = problem.k
        f = problem.f

        q, p = fire.TrialFunctions(self._W)
        w, v = fire.TestFunctions(self._W)

        n = fire.FacetNormal(mesh)
        h = fire.CellDiameter(mesh)

        # Stabilizing parameters
        has_mesh_characteristic_length = True
        delta_0 = fire.Constant(1)
        delta_1 = fire.Constant(-1 / 2)
        delta_2 = fire.Constant(1 / 2)
        delta_3 = fire.Constant(1 / 2)
        eta_p = fire.Constant(100)
        eta_q = fire.Constant(100)
        h_avg = (h("+") + h("-")) / 2.0
        if has_mesh_characteristic_length:
            delta_2 = delta_2 * h * h
            delta_3 = delta_3 * h * h

        kappa = rho * k / mu
        inv_kappa = 1.0 / kappa

        # Classical mixed terms
        a = (dot(inv_kappa * q, w) - div(w) * p - delta_0 * v * div(q)) * dx
        L = -delta_0 * f * v * dx

        # DG terms
        a += jump(w, n) * avg(p) * dS - avg(v) * jump(q, n) * dS

        # Edge stabilizing terms
        a += (eta_q * h_avg) * avg(inv_kappa) * (
            jump(q, n) * jump(w, n)) * dS + (eta_p / h_avg) * avg(kappa) * dot(
                jump(v, n), jump(p, n)) * dS

        # Add the contributions of the pressure boundary conditions to L
        for pboundary, iboundary in bcs_p:
            L -= pboundary * dot(w, n) * ds(iboundary)

        # Stabilizing terms
        a += (delta_1 * inner(kappa * (inv_kappa * q + grad(p)),
                              delta_0 * inv_kappa * w + grad(v)) * dx)
        a += delta_2 * inv_kappa * div(q) * div(w) * dx
        a += delta_3 * inner(kappa * curl(inv_kappa * q), curl(
            inv_kappa * w)) * dx
        L += delta_2 * inv_kappa * f * div(w) * dx

        return a, L
Пример #16
0
    def advection_term(self, q):

        if self.continuity:
            if self.ibp == IntegrateByParts.ONCE:
                L = -inner(grad(self.test), outer(q, self.ubar)) * dx
            else:
                L = inner(self.test, div(outer(q, self.ubar))) * dx
        else:
            if self.ibp == IntegrateByParts.ONCE:
                L = -inner(div(outer(self.test, self.ubar)), q) * dx
            else:
                L = inner(outer(self.test, self.ubar), grad(q)) * dx

        if self.dS is not None and self.ibp != IntegrateByParts.NEVER:
            n = FacetNormal(self.state.mesh)
            un = 0.5 * (dot(self.ubar, n) + abs(dot(self.ubar, n)))

            L += dot(jump(self.test),
                     (un('+') * q('+') - un('-') * q('-'))) * self.dS

            if self.ibp == IntegrateByParts.TWICE:
                L -= (inner(self.test('+'),
                            dot(self.ubar('+'), n('+')) * q('+')) +
                      inner(self.test('-'),
                            dot(self.ubar('-'), n('-')) * q('-'))) * self.dS

        if self.outflow:
            n = FacetNormal(self.state.mesh)
            un = 0.5 * (dot(self.ubar, n) + abs(dot(self.ubar, n)))
            L += self.test * un * q * (ds_v + ds_t + ds_b)

        if self.vector_manifold:
            n = FacetNormal(self.state.mesh)
            w = self.test
            dS = self.dS
            u = q
            L += un('+') * inner(w('-'),
                                 n('+') + n('-')) * inner(u('+'), n('+')) * dS
            L += un('-') * inner(w('+'),
                                 n('+') + n('-')) * inner(u('-'), n('-')) * dS
        return L
Пример #17
0
    def __init__(self, state, V, continuity=False):

        super(DGAdvection, self).__init__(state)

        element = V.fiat_element
        assert element.entity_dofs() == element.entity_closure_dofs(), "Provided space is not discontinuous"
        dt = state.timestepping.dt

        if V.extruded:
            surface_measure = (dS_h + dS_v)
        else:
            surface_measure = dS

        phi = TestFunction(V)
        D = TrialFunction(V)
        self.D1 = Function(V)
        self.dD = Function(V)

        n = FacetNormal(state.mesh)
        # ( dot(v, n) + |dot(v, n)| )/2.0
        un = 0.5*(dot(self.ubar, n) + abs(dot(self.ubar, n)))

        a_mass = inner(phi,D)*dx

        if continuity:
            a_int = -inner(grad(phi), outer(D, self.ubar))*dx
        else:
            a_int = -inner(div(outer(phi,self.ubar)),D)*dx

        a_flux = (dot(jump(phi), un('+')*D('+') - un('-')*D('-')))*surface_measure
        arhs = a_mass - dt*(a_int + a_flux)

        DGproblem = LinearVariationalProblem(a_mass, action(arhs,self.D1),
                                             self.dD)
        self.DGsolver = LinearVariationalSolver(DGproblem,
                                                solver_parameters={
                                                    'ksp_type':'preonly',
                                                    'pc_type':'bjacobi',
                                                    'sub_pc_type': 'ilu'},
                                                options_prefix='DGAdvection')
Пример #18
0
    def __init__(self, state, V, qbar, options=None):
        super(LinearAdvection_V3, self).__init__(state)

        p = TestFunction(V)
        q = TrialFunction(V)
        self.dq = Function(V)

        n = FacetNormal(state.mesh)

        a = p*q*dx
        L = (dot(grad(p), self.ubar)*qbar*dx -
             jump(self.ubar*p, n)*avg(qbar)*(dS_v + dS_h))

        aProblem = LinearVariationalProblem(a,L,self.dq)
        if options is None:
            options = {'ksp_type':'cg',
                       'pc_type':'bjacobi',
                       'sub_pc_type':'ilu'}

        self.solver = LinearVariationalSolver(aProblem,
                                              solver_parameters=options,
                                              options_prefix='LinearAdvectionV3')
Пример #19
0
    def pressure_gradient_term(self):

        u0, rho0, theta0 = split(self.x0)
        cp = self.state.parameters.cp
        n = FacetNormal(self.state.mesh)
        Vtheta = self.state.spaces("HDiv_v")

        # introduce new theta so it can be changed by moisture
        theta = theta0

        # add effect of density of water upon theta
        if self.moisture is not None:
            water_t = Function(Vtheta).assign(0.0)
            for water in self.moisture:
                water_t += self.state.fields(water)
            theta = theta / (1 + water_t)

        pi = thermodynamics.pi(self.state.parameters, rho0, theta0)

        L = (+cp * div(theta * self.test) * pi * dx -
             cp * jump(self.test * theta, n) * avg(pi) * dS_v)
        return L
Пример #20
0
    def advection_term(self, q):

        if self.continuity:
            if self.ibp == "once":
                L = -inner(grad(self.test), outer(q, self.ubar)) * dx
            else:
                L = inner(self.test, div(outer(q, self.ubar))) * dx
        else:
            if self.ibp == "once":
                L = -inner(div(outer(self.test, self.ubar)), q) * dx
            else:
                L = inner(outer(self.test, self.ubar), grad(q)) * dx

        if self.dS is not None and self.ibp is not None:
            L += dot(jump(self.test),
                     (self.un('+') * q('+') - self.un('-') * q('-'))) * self.dS
            if self.ibp == "twice":
                L -= (
                    inner(self.test('+'),
                          dot(self.ubar('+'), self.n('+')) * q('+')) +
                    inner(self.test('-'),
                          dot(self.ubar('-'), self.n('-')) * q('-'))) * self.dS

        if self.outflow:
            L += self.test * self.un * q * self.ds

        if self.vector_manifold:
            un = self.un
            w = self.test
            u = q
            n = self.n
            dS = self.dS
            L += un('+') * inner(w('-'),
                                 n('+') + n('-')) * inner(u('+'), n('+')) * dS
            L += un('-') * inner(w('+'),
                                 n('+') + n('-')) * inner(u('-'), n('-')) * dS
        return L
Пример #21
0
                                  (1 - fd.exp(-c[0])) * (1 - fd.exp(-c[1])))
source = fd.div(velocity * u_exact) - fd.div(Dm * fd.grad(u_exact))

# stability
tau_d = fd.Constant(max([Dm, tau_e])) / h
tau_a = abs(fd.dot(velocity, n))
# tau = fd.Constant(1.0) / h + vn

# numerical flux
qhat = qh + tau_d * (ch - lmbd_h) * n
fhat = velocity * lmbd_h + tau_a * (ch - lmbd_h) * n

a_u = (
    fd.inner(fd.inv(Dm) * qh, vh) * fd.dx - ch * fd.div(vh) * fd.dx +
    # internal faces
    fd.jump(lmbd_h * vh, n) * fd.dS +
    # other faces
    lmbd_h * fd.inner(vh, n) * fd.ds)

# Dirichlet faces
L_u = 0

a_c = (-fd.inner(fd.grad(wh), qh + ch * velocity) * fd.dx +
       wh('+') * fd.jump(qhat + fhat, n) * fd.dS +
       wh * fd.inner(qhat + fhat, n) * fd.ds - wh * source * fd.dx)

L_c = 0

# transmission boundary condition
F_q = (
    mu_h('+')*fd.jump(qhat + fhat, n)*fd.dS + \
Пример #22
0
# Diff = fd.Identity(mesh.geometric_dimension())*(Dm + d_t*vnorm) + \
#     fd.Constant(d_l-d_t)*fd.outer(velocity, velocity)/vnorm

# stability
# tau = fd.Constant(1.0) / h + abs(fd.dot(velocity, n))
tau = fd.Constant(5) / h + vn

# numerical flux
chat = lmbd_h
qhat = qh + tau * (ch - chat) * n + velocity * chat
# qhat_n = fd.dot(qh, n) + tau*(ch - chat) + chat*vn

a_u = (
    fd.inner(fd.inv(Diff) * qh, vh) * fd.dx - ch * fd.div(vh) * fd.dx +
    # internal faces
    fd.jump(lmbd_h * vh, n) * fd.dS +
    # other faces
    lmbd_h * fd.inner(vh, n) * fd.ds(outflow) +
    lmbd_h * fd.inner(vh, n) * fd.ds(TOP) +
    lmbd_h * fd.inner(vh, n) * fd.ds(BOTTOM))

# Dirichlet faces
L_u = -fd.Constant(cIn) * fd.inner(vh, n) * fd.ds(inlet)

a_c = (wh * (ch - c0) / dtc * fd.dx -
       fd.inner(fd.grad(wh), qh + ch * velocity) * fd.dx +
       wh("+") * fd.jump(qhat, n) * fd.dS + wh * fd.inner(qhat, n) * fd.ds)

L_c = 0

# transmission boundary condition
Пример #23
0
D_eqn = (D_ - Dn) * psi * dx - dt * D_ad + inner(v, F_ - Frhs) * dx
Dad_p = LinearVariationalProblem(lhs(D_eqn), rhs(D_eqn), xp)
D_ad_solver = LinearVariationalSolver(Dad_p,
                                      solver_parameters={
                                          "mat_type": "aij",
                                          "snes_linesearch_type": "basic",
                                          "ksp_type": "preonly",
                                          "pc_type": "lu"
                                      })
# u advection solver
w = TestFunction(W1)
u_ = TrialFunction(W1)
u_bar = 0.5 * (un + u_)

u_ad = (inner(perp(grad(inner(Dbar * w, perp(u_rec)))), u_bar) * dx +
        inner(jump(inner(Dbar * w, perp(u_rec)), n), p_uw(ubar, u_bar)) * dS -
        f * inner(perp(u_rec), Dbar * w) * dx)
u_eqn = inner(u_ - un, Dbar * w) * dx - dt * u_ad
uad_p = LinearVariationalProblem(lhs(u_eqn), rhs(u_eqn), uad)
u_ad_solver = LinearVariationalSolver(uad_p)

# u forcing solver
u_f = div(w) * Prhs * dx

f_eqn = inner(u_, w) * dx - dt * u_f
uf_p = LinearVariationalProblem(lhs(f_eqn), rhs(f_eqn), uf)
f_u_solver = LinearVariationalSolver(uf_p)

# Auxiliary solvers
Frhs = unk * Dnk / 3. + un * Dnk / 6. + unk * Dn / 6. + un * Dn / 3.
u_rec_eqn = inner(w, Dbar * u_ - Frhs) * dx
    def _setup_solver(self):
        state = self.state      # just cutting down line length a bit
        Dt = state.timestepping.dt
        beta_ = Dt*state.timestepping.alpha
        cp = state.parameters.cp
        mu = state.mu
        Vu = state.spaces("HDiv")
        Vtheta = state.spaces("HDiv_v")
        Vrho = state.spaces("DG")

        # Store time-stepping coefficients as UFL Constants
        dt = Constant(Dt)
        beta = Constant(beta_)
        beta_cp = Constant(beta_ * cp)

        # Split up the rhs vector (symbolically)
        u_in, rho_in, theta_in = split(state.xrhs)

        # Build the reduced function space for u,rho
        M = MixedFunctionSpace((Vu, Vrho))
        w, phi = TestFunctions(M)
        u, rho = TrialFunctions(M)

        n = FacetNormal(state.mesh)

        # Get background fields
        thetabar = state.fields("thetabar")
        rhobar = state.fields("rhobar")
        pibar = thermodynamics.pi(state.parameters, rhobar, thetabar)
        pibar_rho = thermodynamics.pi_rho(state.parameters, rhobar, thetabar)
        pibar_theta = thermodynamics.pi_theta(state.parameters, rhobar, thetabar)

        # Analytical (approximate) elimination of theta
        k = state.k             # Upward pointing unit vector
        theta = -dot(k, u)*dot(k, grad(thetabar))*beta + theta_in

        # Only include theta' (rather than pi') in the vertical
        # component of the gradient

        # the pi prime term (here, bars are for mean and no bars are
        # for linear perturbations)

        pi = pibar_theta*theta + pibar_rho*rho

        # vertical projection
        def V(u):
            return k*inner(u, k)

        # specify degree for some terms as estimated degree is too large
        dxp = dx(degree=(self.quadrature_degree))
        dS_vp = dS_v(degree=(self.quadrature_degree))

        # add effect of density of water upon theta
        if self.moisture is not None:
            water_t = Function(Vtheta).assign(0.0)
            for water in self.moisture:
                water_t += self.state.fields(water)
            theta_w = theta / (1 + water_t)
            thetabar_w = thetabar / (1 + water_t)
        else:
            theta_w = theta
            thetabar_w = thetabar

        eqn = (
            inner(w, (state.h_project(u) - u_in))*dx
            - beta_cp*div(theta_w*V(w))*pibar*dxp
            # following does nothing but is preserved in the comments
            # to remind us why (because V(w) is purely vertical).
            # + beta_cp*jump(theta*V(w), n)*avg(pibar)*dS_v
            - beta_cp*div(thetabar_w*w)*pi*dxp
            + beta_cp*jump(thetabar_w*w, n)*avg(pi)*dS_vp
            + (phi*(rho - rho_in) - beta*inner(grad(phi), u)*rhobar)*dx
            + beta*jump(phi*u, n)*avg(rhobar)*(dS_v + dS_h)
        )

        if mu is not None:
            eqn += dt*mu*inner(w, k)*inner(u, k)*dx
        aeqn = lhs(eqn)
        Leqn = rhs(eqn)

        # Place to put result of u rho solver
        self.urho = Function(M)

        # Boundary conditions (assumes extruded mesh)
        bcs = [DirichletBC(M.sub(0), 0.0, "bottom"),
               DirichletBC(M.sub(0), 0.0, "top")]

        # Solver for u, rho
        urho_problem = LinearVariationalProblem(
            aeqn, Leqn, self.urho, bcs=bcs)

        self.urho_solver = LinearVariationalSolver(urho_problem,
                                                   solver_parameters=self.solver_parameters,
                                                   options_prefix='ImplicitSolver')

        # Reconstruction of theta
        theta = TrialFunction(Vtheta)
        gamma = TestFunction(Vtheta)

        u, rho = self.urho.split()
        self.theta = Function(Vtheta)

        theta_eqn = gamma*(theta - theta_in
                           + dot(k, u)*dot(k, grad(thetabar))*beta)*dx

        theta_problem = LinearVariationalProblem(lhs(theta_eqn),
                                                 rhs(theta_eqn),
                                                 self.theta)
        self.theta_solver = LinearVariationalSolver(theta_problem,
                                                    options_prefix='thetabacksubstitution')
Пример #25
0
    def __init__(self, prognostic_variables, simulation_parameters):

        mesh = simulation_parameters['mesh'][-1]
        self.scheme = simulation_parameters['scheme'][-1]
        self.timestepping = simulation_parameters['timestepping'][-1]
        alphasq = simulation_parameters['alphasq'][-1]
        c0 = simulation_parameters['c0'][-1]
        gamma = simulation_parameters['gamma'][-1]
        Dt = Constant(simulation_parameters['dt'][-1])
        self.solvers = []

        if alphasq.values()[0] > 0.0 and gamma.values()[0] == 0.0:
            self.setup = 'ch'
            if self.scheme == 'upwind' and self.timestepping == 'ssprk3':

                Vm = prognostic_variables.Vm
                Vu = prognostic_variables.Vu
                self.m = prognostic_variables.m
                self.u = prognostic_variables.u
                self.Xi = prognostic_variables.dXi
                self.m0 = Function(Vm).assign(self.m)

                # now make problem for the actual problem
                psi = TestFunction(Vm)
                self.m_trial = Function(Vm)
                self.dm = Function(
                    Vm
                )  # introduce this as the advection operator for a single step

                us = Dt * self.u + self.Xi

                nhat = FacetNormal(mesh)
                un = 0.5 * (dot(us, nhat) + abs(dot(us, nhat)))
                ones = Function(Vu).project(as_vector([Constant(1.)]))

                Lm = (psi * self.dm * dx -
                      psi.dx(0) * self.m_trial * dot(ones, us) * dx +
                      psi * self.m_trial * dot(ones, us.dx(0)) * dx +
                      jump(psi) * (un('+') * self.m_trial('+') -
                                   un('-') * self.m_trial('-')) * dS)
                mprob = NonlinearVariationalProblem(Lm, self.dm)
                self.msolver = NonlinearVariationalSolver(mprob,
                                                          solver_parameters={
                                                              'ksp_type':
                                                              'preonly',
                                                              'pc_type':
                                                              'bjacobi',
                                                              'sub_pc_type':
                                                              'ilu'
                                                          })

                phi = TestFunction(Vu)
                Lu = (dot(phi, ones) * self.m * dx - dot(phi, self.u) * dx -
                      alphasq * dot(self.u.dx(0), phi.dx(0)) * dx)
                uprob = NonlinearVariationalProblem(Lu, self.u)
                self.usolver = NonlinearVariationalSolver(uprob,
                                                          solver_parameters={
                                                              'ksp_type':
                                                              'preonly',
                                                              'pc_type': 'lu'
                                                          })

            elif self.scheme == 'hydrodynamic' and self.timestepping == 'midpoint':
                Vu = prognostic_variables.Vu

                self.u = prognostic_variables.u

                W = MixedFunctionSpace((Vu, ) * 3)
                psi, phi, zeta = TestFunctions(W)

                w1 = Function(W)
                self.u1, dFh, dGh = split(w1)

                uh = (self.u1 + self.u) / 2
                dXi = prognostic_variables.dXi
                dXi_x = prognostic_variables.dXi_x
                dXi_xx = prognostic_variables.dXi_xx
                dvh = Dt * uh + dXi

                Lu = (psi * (self.u1 - self.u) * dx +
                      psi * uh.dx(0) * dvh * dx - psi.dx(0) * dFh * dx +
                      psi * dGh * dx + phi * dFh * dx +
                      alphasq * phi.dx(0) * dFh.dx(0) * dx -
                      phi * uh * uh * Dt * dx -
                      0.5 * alphasq * phi * uh.dx(0) * uh.dx(0) * Dt * dx +
                      zeta * dGh * dx + alphasq * zeta.dx(0) * dGh.dx(0) * dx -
                      2 * zeta * uh * dXi_x * dx -
                      alphasq * zeta * uh.dx(0) * dXi_xx * dx)

                self.u1, dFh, dGh = w1.split()

                uprob = NonlinearVariationalProblem(Lu, w1)
                self.usolver = NonlinearVariationalSolver(uprob,
                                                          solver_parameters={
                                                              'mat_type':
                                                              'aij',
                                                              'ksp_type':
                                                              'preonly',
                                                              'pc_type': 'lu'
                                                          })

            elif self.scheme == 'no_gradient' and self.timestepping == 'midpoint':
                # a version of the hydrodynamic form but without exploiting the gradient
                Vu = prognostic_variables.Vu

                self.u = prognostic_variables.u

                W = MixedFunctionSpace((Vu, ) * 3)
                psi, phi, zeta = TestFunctions(W)

                w1 = Function(W)
                self.u1, dFh, dGh = split(w1)

                uh = (self.u1 + self.u) / 2
                dXi = prognostic_variables.dXi
                dXi_x = prognostic_variables.dXi_x
                dXi_xx = prognostic_variables.dXi_xx
                dvh = Dt * uh + dXi

                Lu = (psi * (self.u1 - self.u) * dx +
                      psi * uh.dx(0) * dvh * dx + psi * dFh.dx(0) * dx +
                      psi * dGh * dx + phi * dFh * dx +
                      alphasq * phi.dx(0) * dFh.dx(0) * dx -
                      phi * uh * uh * Dt * dx -
                      0.5 * alphasq * phi * uh.dx(0) * uh.dx(0) * Dt * dx +
                      zeta * dGh * dx + alphasq * zeta.dx(0) * dGh.dx(0) * dx -
                      2 * zeta * uh * dXi_x * dx -
                      alphasq * zeta * uh.dx(0) * dXi_xx * dx)

                self.u1, dFh, dGh = w1.split()

                uprob = NonlinearVariationalProblem(Lu, w1)
                self.usolver = NonlinearVariationalSolver(uprob,
                                                          solver_parameters={
                                                              'mat_type':
                                                              'aij',
                                                              'ksp_type':
                                                              'preonly',
                                                              'pc_type': 'lu'
                                                          })

            elif self.scheme == 'test' and self.timestepping == 'midpoint':
                self.u = prognostic_variables.u
                Vu = prognostic_variables.Vu
                psi = TestFunction(Vu)
                self.u1 = Function(Vu)
                uh = (self.u1 + self.u) / 2
                dvh = Dt * uh + prognostic_variables.dXi

                eqn = (psi * (self.u1 - self.u) * dx -
                       psi * uh * dvh.dx(0) * dx)
                prob = NonlinearVariationalProblem(eqn, self.u1)
                self.usolver = NonlinearVariationalSolver(prob,
                                                          solver_parameters={
                                                              'mat_type':
                                                              'aij',
                                                              'ksp_type':
                                                              'preonly',
                                                              'pc_type': 'lu'
                                                          })

            else:
                raise ValueError(
                    'Scheme %s and timestepping %s either not compatible or not recognised.'
                    % (self.scheme, self.timestepping))

        elif alphasq.values()[0] == 0.0 and gamma.values()[0] > 0.0:
            self.setup = 'kdv'
            if self.scheme == 'upwind' and self.timestepping == 'ssprk3':
                raise NotImplementedError(
                    'Scheme %s and timestepping %s not yet implemented.' %
                    (self.scheme, self.timestepping))

            elif self.scheme == 'upwind' and self.timestepping == 'midpoint':
                raise NotImplementedError(
                    'Scheme %s and timestepping %s not yet implemented.' %
                    (self.scheme, self.timestepping))

            elif self.scheme == 'hydrodynamic' and self.timestepping == 'midpoint':
                raise NotImplementedError(
                    'Scheme %s and timestepping %s not yet implemented.' %
                    (self.scheme, self.timestepping))

            else:
                raise ValueError(
                    'Scheme %s and timestepping %s either not compatible or not recognised.'
                    % (self.scheme, self.timestepping))

        else:
            raise NotImplementedError(
                'Schemes for your values of alpha squared %.3f and gamma %.3f are not yet implemented.'
                % (alphasq, gamma))
                                   {"ksp_type":"preonly",
                                    "pc_type":"lu"})
q_solver.solve()

# Build advection, forcing forms
Frhs = unk*Dnk/3. + un*Dnk/6. + unk*Dn/6. + un*Dn/3.
K = inner(un, un)/3. + inner(un, unk)/3. + inner(unk, unk)/3.
Prhs = g*(0.5*(Dn + Dp) + b) + 0.5*K

# D advection solver
phi = TestFunction(W0)
D_ = TrialFunction(W0)
D_bar = 0.5*(Dn + D_)

D_ad = (inner(grad(phi), D_bar*u_rec)*dx
        - jump(phi*u_rec, n)*uw(ubar, D_bar)*dS)
D_eqn = (D_ - Dn)*phi*dx - dt*D_ad
Dad_p = LinearVariationalProblem(lhs(D_eqn), rhs(D_eqn), Dp)
D_ad_solver = LinearVariationalSolver(Dad_p)

# u advection solver
w = TestFunction(W1)
u_ = TrialFunction(W1)
u_bar = 0.5*(un + u_)

u_ad = (inner(perp(grad(inner(Dbar*w, perp(u_rec)))), u_bar)*dx
        + inner(jump(inner(Dbar*w, perp(u_rec)), n),
                p_uw(ubar, u_bar))*dS)
u_eqn = inner(u_ - un, Dbar*w)*dx - dt*u_ad
uad_p = LinearVariationalProblem(lhs(u_eqn), rhs(u_eqn), uad)
u_ad_solver = LinearVariationalSolver(uad_p)
Пример #27
0
    def initialize(self, pc):
        """ Set up the problem context. Takes the original
        mixed problem and transforms it into the equivalent
        hybrid-mixed system.

        A KSP object is created for the Lagrange multipliers
        on the top/bottom faces of the mesh cells.
        """

        from firedrake import (FunctionSpace, Function, Constant,
                               FiniteElement, TensorProductElement,
                               TrialFunction, TrialFunctions, TestFunction,
                               DirichletBC, interval, MixedElement,
                               BrokenElement)
        from firedrake.assemble import (allocate_matrix,
                                        create_assembly_callable)
        from firedrake.formmanipulation import split_form
        from ufl.algorithms.replace import replace
        from ufl.cell import TensorProductCell

        # Extract PC context
        prefix = pc.getOptionsPrefix() + "vert_hybridization_"
        _, P = pc.getOperators()
        self.ctx = P.getPythonContext()

        if not isinstance(self.ctx, ImplicitMatrixContext):
            raise ValueError(
                "The python context must be an ImplicitMatrixContext")

        test, trial = self.ctx.a.arguments()

        V = test.function_space()
        mesh = V.mesh()

        # Magically determine which spaces are vector and scalar valued
        for i, Vi in enumerate(V):

            # Vector-valued spaces will have a non-empty value_shape
            if Vi.ufl_element().value_shape():
                self.vidx = i
            else:
                self.pidx = i

        Vv = V[self.vidx]
        Vp = V[self.pidx]

        # Create the space of approximate traces in the vertical.
        # NOTE: Technically a hack since the resulting space is technically
        # defined in cell interiors, however the degrees of freedom will only
        # be geometrically defined on edges. Arguments will only be used in
        # surface integrals
        deg, _ = Vv.ufl_element().degree()

        # Assumes a tensor product cell (quads, triangular-prisms, cubes)
        if not isinstance(Vp.ufl_element().cell(), TensorProductCell):
            raise NotImplementedError(
                "Currently only implemented for tensor product discretizations"
            )

        # Only want the horizontal cell
        cell, _ = Vp.ufl_element().cell()._cells

        DG = FiniteElement("DG", cell, deg)
        CG = FiniteElement("CG", interval, 1)
        Vv_tr_element = TensorProductElement(DG, CG)
        Vv_tr = FunctionSpace(mesh, Vv_tr_element)

        # Break the spaces
        broken_elements = MixedElement(
            [BrokenElement(Vi.ufl_element()) for Vi in V])
        V_d = FunctionSpace(mesh, broken_elements)

        # Set up relevant functions
        self.broken_solution = Function(V_d)
        self.broken_residual = Function(V_d)
        self.trace_solution = Function(Vv_tr)
        self.unbroken_solution = Function(V)
        self.unbroken_residual = Function(V)

        # Set up transfer kernels to and from the broken velocity space
        # NOTE: Since this snippet of code is used in a couple places in
        # in Gusto, might be worth creating a utility function that is
        # is importable and just called where needed.
        shapes = {
            "i": Vv.finat_element.space_dimension(),
            "j": np.prod(Vv.shape, dtype=int)
        }
        weight_kernel = """
        for (int i=0; i<{i}; ++i)
            for (int j=0; j<{j}; ++j)
                w[i*{j} + j] += 1.0;
        """.format(**shapes)

        self.weight = Function(Vv)
        par_loop(weight_kernel, dx, {"w": (self.weight, INC)})

        # Averaging kernel
        self.average_kernel = """
        for (int i=0; i<{i}; ++i)
            for (int j=0; j<{j}; ++j)
                vec_out[i*{j} + j] += vec_in[i*{j} + j]/w[i*{j} + j];
        """.format(**shapes)
        # Original mixed operator replaced with "broken" arguments
        arg_map = {test: TestFunction(V_d), trial: TrialFunction(V_d)}
        Atilde = Tensor(replace(self.ctx.a, arg_map))
        gammar = TestFunction(Vv_tr)
        n = FacetNormal(mesh)
        sigma = TrialFunctions(V_d)[self.vidx]

        # Again, assumes tensor product structure. Why use this if you
        # don't have some form of vertical extrusion?
        Kform = gammar('+') * jump(sigma, n=n) * dS_h

        # Here we deal with boundary conditions
        if self.ctx.row_bcs:
            # Find all the subdomains with neumann BCS
            # These are Dirichlet BCs on the vidx space
            neumann_subdomains = set()
            for bc in self.ctx.row_bcs:
                if bc.function_space().index == self.pidx:
                    raise NotImplementedError(
                        "Dirichlet conditions for scalar variable not supported. Use a weak bc."
                    )
                if bc.function_space().index != self.vidx:
                    raise NotImplementedError(
                        "Dirichlet bc set on unsupported space.")
                # append the set of sub domains
                subdom = bc.sub_domain
                if isinstance(subdom, str):
                    neumann_subdomains |= set([subdom])
                else:
                    neumann_subdomains |= set(as_tuple(subdom, int))

            # separate out the top and bottom bcs
            extruded_neumann_subdomains = neumann_subdomains & {
                "top", "bottom"
            }
            neumann_subdomains = neumann_subdomains - extruded_neumann_subdomains

            integrand = gammar * dot(sigma, n)
            measures = []
            trace_subdomains = []
            for subdomain in sorted(extruded_neumann_subdomains):
                measures.append({"top": ds_t, "bottom": ds_b}[subdomain])
                trace_subdomains.extend(
                    sorted({"top", "bottom"} - extruded_neumann_subdomains))

            measures.extend((ds(sd) for sd in sorted(neumann_subdomains)))
            markers = [int(x) for x in mesh.exterior_facets.unique_markers]
            dirichlet_subdomains = set(markers) - neumann_subdomains
            trace_subdomains.extend(sorted(dirichlet_subdomains))

            for measure in measures:
                Kform += integrand * measure

        else:
            trace_subdomains = ["top", "bottom"]

        trace_bcs = [
            DirichletBC(Vv_tr, Constant(0.0), subdomain)
            for subdomain in trace_subdomains
        ]

        # Make a SLATE tensor from Kform
        K = Tensor(Kform)

        # Assemble the Schur complement operator and right-hand side
        self.schur_rhs = Function(Vv_tr)
        self._assemble_Srhs = create_assembly_callable(
            K * Atilde.inv * AssembledVector(self.broken_residual),
            tensor=self.schur_rhs,
            form_compiler_parameters=self.ctx.fc_params)

        mat_type = PETSc.Options().getString(prefix + "mat_type", "aij")

        schur_comp = K * Atilde.inv * K.T
        self.S = allocate_matrix(schur_comp,
                                 bcs=trace_bcs,
                                 form_compiler_parameters=self.ctx.fc_params,
                                 mat_type=mat_type,
                                 options_prefix=prefix)
        self._assemble_S = create_assembly_callable(
            schur_comp,
            tensor=self.S,
            bcs=trace_bcs,
            form_compiler_parameters=self.ctx.fc_params,
            mat_type=mat_type)

        self._assemble_S()
        self.S.force_evaluation()
        Smat = self.S.petscmat

        nullspace = self.ctx.appctx.get("vert_trace_nullspace", None)
        if nullspace is not None:
            nsp = nullspace(Vv_tr)
            Smat.setNullSpace(nsp.nullspace(comm=pc.comm))

        # Set up the KSP for the system of Lagrange multipliers
        trace_ksp = PETSc.KSP().create(comm=pc.comm)
        trace_ksp.setOptionsPrefix(prefix)
        trace_ksp.setOperators(Smat)
        trace_ksp.setUp()
        trace_ksp.setFromOptions()
        self.trace_ksp = trace_ksp

        split_mixed_op = dict(split_form(Atilde.form))
        split_trace_op = dict(split_form(K.form))

        # Generate reconstruction calls
        self._reconstruction_calls(split_mixed_op, split_trace_op)
Пример #28
0
    def _setup_solver(self):
        import numpy as np

        state = self.state
        dt = state.dt
        beta_ = dt * self.alpha
        cp = state.parameters.cp
        Vu = state.spaces("HDiv")
        Vu_broken = FunctionSpace(state.mesh, BrokenElement(Vu.ufl_element()))
        Vtheta = state.spaces("theta")
        Vrho = state.spaces("DG")

        # Store time-stepping coefficients as UFL Constants
        beta = Constant(beta_)
        beta_cp = Constant(beta_ * cp)

        h_deg = Vrho.ufl_element().degree()[0]
        v_deg = Vrho.ufl_element().degree()[1]
        Vtrace = FunctionSpace(state.mesh, "HDiv Trace", degree=(h_deg, v_deg))

        # Split up the rhs vector (symbolically)
        self.xrhs = Function(self.equations.function_space)
        u_in, rho_in, theta_in = split(self.xrhs)[0:3]

        # Build the function space for "broken" u, rho, and pressure trace
        M = MixedFunctionSpace((Vu_broken, Vrho, Vtrace))
        w, phi, dl = TestFunctions(M)
        u, rho, l0 = TrialFunctions(M)

        n = FacetNormal(state.mesh)

        # Get background fields
        thetabar = state.fields("thetabar")
        rhobar = state.fields("rhobar")
        exnerbar = thermodynamics.exner_pressure(state.parameters, rhobar,
                                                 thetabar)
        exnerbar_rho = thermodynamics.dexner_drho(state.parameters, rhobar,
                                                  thetabar)
        exnerbar_theta = thermodynamics.dexner_dtheta(state.parameters, rhobar,
                                                      thetabar)

        # Analytical (approximate) elimination of theta
        k = state.k  # Upward pointing unit vector
        theta = -dot(k, u) * dot(k, grad(thetabar)) * beta + theta_in

        # Only include theta' (rather than exner') in the vertical
        # component of the gradient

        # The exner prime term (here, bars are for mean and no bars are
        # for linear perturbations)
        exner = exnerbar_theta * theta + exnerbar_rho * rho

        # Vertical projection
        def V(u):
            return k * inner(u, k)

        # hydrostatic projection
        h_project = lambda u: u - k * inner(u, k)

        # Specify degree for some terms as estimated degree is too large
        dxp = dx(degree=(self.quadrature_degree))
        dS_vp = dS_v(degree=(self.quadrature_degree))
        dS_hp = dS_h(degree=(self.quadrature_degree))
        ds_vp = ds_v(degree=(self.quadrature_degree))
        ds_tbp = (ds_t(degree=(self.quadrature_degree)) +
                  ds_b(degree=(self.quadrature_degree)))

        # Add effect of density of water upon theta
        if self.moisture is not None:
            water_t = Function(Vtheta).assign(0.0)
            for water in self.moisture:
                water_t += self.state.fields(water)
            theta_w = theta / (1 + water_t)
            thetabar_w = thetabar / (1 + water_t)
        else:
            theta_w = theta
            thetabar_w = thetabar

        _l0 = TrialFunction(Vtrace)
        _dl = TestFunction(Vtrace)
        a_tr = _dl('+') * _l0('+') * (
            dS_vp + dS_hp) + _dl * _l0 * ds_vp + _dl * _l0 * ds_tbp

        def L_tr(f):
            return _dl('+') * avg(f) * (
                dS_vp + dS_hp) + _dl * f * ds_vp + _dl * f * ds_tbp

        cg_ilu_parameters = {
            'ksp_type': 'cg',
            'pc_type': 'bjacobi',
            'sub_pc_type': 'ilu'
        }

        # Project field averages into functions on the trace space
        rhobar_avg = Function(Vtrace)
        exnerbar_avg = Function(Vtrace)

        rho_avg_prb = LinearVariationalProblem(a_tr, L_tr(rhobar), rhobar_avg)
        exner_avg_prb = LinearVariationalProblem(a_tr, L_tr(exnerbar),
                                                 exnerbar_avg)

        rho_avg_solver = LinearVariationalSolver(
            rho_avg_prb,
            solver_parameters=cg_ilu_parameters,
            options_prefix='rhobar_avg_solver')
        exner_avg_solver = LinearVariationalSolver(
            exner_avg_prb,
            solver_parameters=cg_ilu_parameters,
            options_prefix='exnerbar_avg_solver')

        with timed_region("Gusto:HybridProjectRhobar"):
            rho_avg_solver.solve()

        with timed_region("Gusto:HybridProjectExnerbar"):
            exner_avg_solver.solve()

        # "broken" u, rho, and trace system
        # NOTE: no ds_v integrals since equations are defined on
        # a periodic (or sphere) base mesh.
        if any([t.has_label(hydrostatic) for t in self.equations.residual]):
            u_mass = inner(w, (h_project(u) - u_in)) * dx
        else:
            u_mass = inner(w, (u - u_in)) * dx

        eqn = (
            # momentum equation
            u_mass - beta_cp * div(theta_w * V(w)) * exnerbar * dxp
            # following does nothing but is preserved in the comments
            # to remind us why (because V(w) is purely vertical).
            # + beta_cp*jump(theta_w*V(w), n=n)*exnerbar_avg('+')*dS_vp
            + beta_cp * jump(theta_w * V(w), n=n) * exnerbar_avg('+') * dS_hp +
            beta_cp * dot(theta_w * V(w), n) * exnerbar_avg * ds_tbp -
            beta_cp * div(thetabar_w * w) * exner * dxp
            # trace terms appearing after integrating momentum equation
            + beta_cp * jump(thetabar_w * w, n=n) * l0('+') * (dS_vp + dS_hp) +
            beta_cp * dot(thetabar_w * w, n) * l0 * (ds_tbp + ds_vp)
            # mass continuity equation
            + (phi *
               (rho - rho_in) - beta * inner(grad(phi), u) * rhobar) * dx +
            beta * jump(phi * u, n=n) * rhobar_avg('+') * (dS_v + dS_h)
            # term added because u.n=0 is enforced weakly via the traces
            + beta * phi * dot(u, n) * rhobar_avg * (ds_tb + ds_v)
            # constraint equation to enforce continuity of the velocity
            # through the interior facets and weakly impose the no-slip
            # condition
            + dl('+') * jump(u, n=n) * (dS_vp + dS_hp) + dl * dot(u, n) *
            (ds_tbp + ds_vp))

        # contribution of the sponge term
        if hasattr(self.equations, "mu"):
            eqn += dt * self.equations.mu * inner(w, k) * inner(u, k) * dx

        aeqn = lhs(eqn)
        Leqn = rhs(eqn)

        # Function for the hybridized solutions
        self.urhol0 = Function(M)

        hybridized_prb = LinearVariationalProblem(aeqn, Leqn, self.urhol0)
        hybridized_solver = LinearVariationalSolver(
            hybridized_prb,
            solver_parameters=self.solver_parameters,
            options_prefix='ImplicitSolver')
        self.hybridized_solver = hybridized_solver

        # Project broken u into the HDiv space using facet averaging.
        # Weight function counting the dofs of the HDiv element:
        shapes = {
            "i": Vu.finat_element.space_dimension(),
            "j": np.prod(Vu.shape, dtype=int)
        }
        weight_kernel = """
        for (int i=0; i<{i}; ++i)
            for (int j=0; j<{j}; ++j)
                w[i*{j} + j] += 1.0;
        """.format(**shapes)

        self._weight = Function(Vu)
        par_loop(weight_kernel, dx, {"w": (self._weight, INC)})

        # Averaging kernel
        self._average_kernel = """
        for (int i=0; i<{i}; ++i)
            for (int j=0; j<{j}; ++j)
                vec_out[i*{j} + j] += vec_in[i*{j} + j]/w[i*{j} + j];
        """.format(**shapes)

        # HDiv-conforming velocity
        self.u_hdiv = Function(Vu)

        # Reconstruction of theta
        theta = TrialFunction(Vtheta)
        gamma = TestFunction(Vtheta)

        self.theta = Function(Vtheta)
        theta_eqn = gamma * (theta - theta_in + dot(k, self.u_hdiv) *
                             dot(k, grad(thetabar)) * beta) * dx

        theta_problem = LinearVariationalProblem(lhs(theta_eqn),
                                                 rhs(theta_eqn), self.theta)
        self.theta_solver = LinearVariationalSolver(
            theta_problem,
            solver_parameters=cg_ilu_parameters,
            options_prefix='thetabacksubstitution')

        # Store boundary conditions for the div-conforming velocity to apply
        # post-solve
        self.bcs = self.equations.bcs['u']
Пример #29
0
 def stabilisation_term(self, alpha, zeta, mesh, v, test):
     e = avg(CellVolume(mesh)) / FacetArea(mesh)
     return 2 * alpha * zeta / e * (dot(jump(v), jump(test))) * dS
Пример #30
0
    def setup(self, state):

        space = state.spaces("HDiv")
        super(SawyerEliassenU, self).setup(state, space=space)

        u = state.fields("u")
        b = state.fields("b")
        v = inner(u, as_vector([0., 1., 0.]))

        # spaces
        V0 = FunctionSpace(state.mesh, "CG", 2)
        Vu = u.function_space()

        # project b to V0
        self.b_v0 = Function(V0)
        btri = TrialFunction(V0)
        btes = TestFunction(V0)
        a = inner(btes, btri) * dx
        L = inner(btes, b) * dx
        projectbproblem = LinearVariationalProblem(a, L, self.b_v0)
        self.project_b_solver = LinearVariationalSolver(
            projectbproblem, solver_parameters={'ksp_type': 'cg'})

        # project v to V0
        self.v_v0 = Function(V0)
        vtri = TrialFunction(V0)
        vtes = TestFunction(V0)
        a = inner(vtes, vtri) * dx
        L = inner(vtes, v) * dx
        projectvproblem = LinearVariationalProblem(a, L, self.v_v0)
        self.project_v_solver = LinearVariationalSolver(
            projectvproblem, solver_parameters={'ksp_type': 'cg'})

        # stm/psi is a stream function
        self.stm = Function(V0)
        psi = TrialFunction(V0)
        xsi = TestFunction(V0)

        f = state.parameters.f
        H = state.parameters.H
        L = state.parameters.L
        dbdy = state.parameters.dbdy
        x, y, z = SpatialCoordinate(state.mesh)

        bcs = [DirichletBC(V0, 0., "bottom"), DirichletBC(V0, 0., "top")]

        Mat = as_matrix([[b.dx(2), 0., -f * self.v_v0.dx(2)], [0., 0., 0.],
                         [-self.b_v0.dx(0), 0., f**2 + f * self.v_v0.dx(0)]])

        Equ = (inner(grad(xsi), dot(Mat, grad(psi))) -
               dbdy * inner(grad(xsi), as_vector([-v, 0., f *
                                                  (z - H / 2)]))) * dx

        # fourth-order terms
        if state.parameters.fourthorder:
            eps = Constant(0.0001)
            brennersigma = Constant(10.0)
            n = FacetNormal(state.mesh)
            deltax = Constant(state.parameters.deltax)
            deltaz = Constant(state.parameters.deltaz)

            nn = as_matrix([[sqrt(brennersigma / Constant(deltax)), 0., 0.],
                            [0., 0., 0.],
                            [0., 0.,
                             sqrt(brennersigma / Constant(deltaz))]])

            mu = as_matrix([[1., 0., 0.], [0., 0., 0.], [0., 0., H / L]])

            # anisotropic form
            Equ += eps * (
                div(dot(mu, grad(psi))) * div(dot(mu, grad(xsi))) * dx -
                (avg(dot(dot(grad(grad(psi)), n), n)) * jump(grad(xsi), n=n) +
                 avg(dot(dot(grad(grad(xsi)), n), n)) * jump(grad(psi), n=n) -
                 jump(nn * grad(psi), n=n) * jump(nn * grad(xsi), n=n)) *
                (dS_h + dS_v))

        Au = lhs(Equ)
        Lu = rhs(Equ)
        stmproblem = LinearVariationalProblem(Au, Lu, self.stm, bcs=bcs)
        self.stream_function_solver = LinearVariationalSolver(
            stmproblem, solver_parameters={'ksp_type': 'cg'})

        # solve for sawyer_eliassen u
        self.u = Function(Vu)
        utrial = TrialFunction(Vu)
        w = TestFunction(Vu)
        a = inner(w, utrial) * dx
        L = (w[0] * (-self.stm.dx(2)) + w[2] * (self.stm.dx(0))) * dx
        ugproblem = LinearVariationalProblem(a, L, self.u)
        self.sawyer_eliassen_u_solver = LinearVariationalSolver(
            ugproblem, solver_parameters={'ksp_type': 'cg'})
    def __init__(self, diagnostic_variables, prognostic_variables, outputting,
                 simulation_parameters):

        self.diagnostic_variables = diagnostic_variables
        self.prognostic_variables = prognostic_variables
        self.outputting = outputting
        self.simulation_parameters = simulation_parameters
        Dt = Constant(simulation_parameters['dt'][-1])
        Ld = simulation_parameters['Ld'][-1]
        u = self.prognostic_variables.u
        Xi = self.prognostic_variables.dXi
        Vu = u.function_space()
        vector_u = True if Vu.ufl_element() == VectorElement else False
        ones = Function(
            VectorFunctionSpace(self.prognostic_variables.mesh, "CG",
                                1)).project(as_vector([Constant(1.0)]))
        self.to_update_constants = False
        self.interpolators = []
        self.projectors = []
        self.solvers = []

        mesh = u.function_space().mesh()
        x, = SpatialCoordinate(mesh)
        alphasq = simulation_parameters['alphasq'][-1]
        periodic = simulation_parameters['periodic'][-1]

        # do peakon data checks here
        true_peakon_data = simulation_parameters['true_peakon_data'][-1]
        if true_peakon_data is not None:
            self.true_peakon_file = Dataset(
                'results/' + true_peakon_data + '/data.nc', 'r')
            # check length of file is correct
            ndump = simulation_parameters['ndump'][-1]
            tmax = simulation_parameters['tmax'][-1]
            dt = simulation_parameters['dt'][-1]
            if len(self.true_peakon_file['time'][:]) != int(tmax /
                                                            (ndump * dt)) + 1:
                raise ValueError(
                    'If reading in true peakon data, the dump frequency must be the same as that used for the true peakon data.'
                    +
                    ' Length of true peakon data as %i, but proposed length is %i'
                    % (len(self.true_peakon_file['time'][:]),
                       int(tmax / (ndump * dt)) + 1))
            if self.true_peakon_file['p'][:].shape != (int(tmax /
                                                           (ndump * dt)) +
                                                       1, ):
                raise ValueError(
                    'True peakon data shape %i must be the same shape as proposed data %i'
                    % ((int(tmax / (ndump * dt)) + 1, ),
                       self.true_peakon_file['p'][:].shape))

        # do peakon data checks here
        true_mean_peakon_data = simulation_parameters['true_mean_peakon_data'][
            -1]
        if true_mean_peakon_data is not None:
            self.true_mean_peakon_file = Dataset(
                'results/' + true_mean_peakon_data + '/data.nc', 'r')
            # check length of file is correct
            ndump = simulation_parameters['ndump'][-1]
            tmax = simulation_parameters['tmax'][-1]
            dt = simulation_parameters['dt'][-1]
            if len(self.true_mean_peakon_file['time'][:]) != int(tmax /
                                                                 (ndump * dt)):
                raise ValueError(
                    'If reading in true peakon data, the dump frequency must be the same as that used for the true peakon data.'
                )
            if self.true_mean_peakon_file['p'][:].shape != (int(
                    tmax / (ndump * dt)), ):
                raise ValueError(
                    'True peakon data must have same shape as proposed data!')

        for key, value in self.diagnostic_variables.fields.items():

            if key == 'uscalar':
                uscalar = self.diagnostic_variables.fields['uscalar']
                u_interpolator = Interpolator(dot(ones, u), uscalar)
                self.interpolators.append(u_interpolator)

            elif key == 'Euscalar':
                Eu = self.prognostic_variables.Eu
                Euscalar = self.diagnostic_variables.fields['Euscalar']
                Eu_interpolator = Interpolator(dot(ones, Eu), Euscalar)
                self.interpolators.append(Eu_interpolator)

            elif key == 'Xiscalar':
                Xi = self.prognostic_variables.dXi
                Xiscalar = self.diagnostic_variables.fields['Xiscalar']
                Xi_interpolator = Interpolator(dot(ones, Xi), Xiscalar)
                self.interpolators.append(Xi_interpolator)

            elif key == 'du':
                if type(u.function_space().ufl_element()) == VectorElement:
                    u_to_project = self.diagnostic_variables.fields['uscalar']
                else:
                    u_to_project = u
                du = self.diagnostic_variables.fields['du']
                du_projector = Projector(u_to_project.dx(0), du)
                self.projectors.append(du_projector)

            elif key == 'jump_du':
                du = self.diagnostic_variables.fields['du']
                jump_du = self.diagnostic_variables.fields['jump_du']
                V = jump_du.function_space()
                jtrial = TrialFunction(V)
                psi = TestFunction(V)
                Lj = psi('+') * abs(jump(du)) * dS
                aj = psi('+') * jtrial('+') * dS
                jprob = LinearVariationalProblem(aj, Lj, jump_du)
                jsolver = LinearVariationalSolver(jprob)
                self.solvers.append(jsolver)

            elif key == 'du_smooth':
                du = self.diagnostic_variables.fields['du']
                du_smooth = self.diagnostic_variables.fields['du_smooth']
                projector = Projector(du, du_smooth)
                self.projectors.append(projector)

            elif key == 'u2_flux':
                gamma = simulation_parameters['gamma'][-1]
                u2_flux = self.diagnostic_variables.fields['u2_flux']
                xis = self.prognostic_variables.pure_xi_list
                xis_x = []
                xis_xxx = []
                CG1 = FunctionSpace(mesh, "CG", 1)
                psi = TestFunction(CG1)
                for xi in xis:
                    xis_x.append(Function(CG1).project(xi.dx(0)))
                for xi_x in xis_x:
                    xi_xxx = Function(CG1)
                    form = (psi * xi_xxx + psi.dx(0) * xi_x.dx(0)) * dx
                    prob = NonlinearVariationalProblem(form, xi_xxx)
                    solver = NonlinearVariationalSolver(prob)
                    solver.solve()
                    xis_xxx.append(xi_xxx)

                flux_expr = 0.0 * x
                for xi, xi_x, xi_xxx in zip(xis, xis_x, xis_xxx):
                    flux_expr += (6 * u.dx(0) * xi + 12 * u * xi_x + gamma *
                                  xi_xxx) * (6 * u.dx(0) * xi + 24 * u * xi_x +
                                             gamma * xi_xxx)
                projector = Projector(flux_expr, u2_flux)
                self.projectors.append(projector)

            elif key == 'a':
                # find  6 * u_x * Xi + gamma * Xi_xxx
                mesh = u.function_space().mesh()
                gamma = simulation_parameters['gamma'][-1]
                a_flux = self.diagnostic_variables.fields['a']
                xis = self.prognostic_variables.pure_xis
                xis_x = []
                xis_xxx = []
                CG1 = FunctionSpace(mesh, "CG", 1)
                psi = TestFunction(CG1)
                for xi in xis:
                    xis_x.append(Function(CG1).project(xi.dx(0)))
                for xi_x in xis_x:
                    xi_xxx = Function(CG1)
                    form = (psi * xi_xxx + psi.dx(0) * xi_x.dx(0)) * dx
                    prob = NonlinearVariationalProblem(form, xi_xxx)
                    solver = NonlinearVariationalSolver(prob)
                    solver.solve()
                    xis_xxx.append(xi_xxx)

                x, = SpatialCoordinate(mesh)
                a_expr = 0.0 * x
                for xi, xi_x, xi_xxx in zip(xis, xis_x, xis_xxx):
                    a_expr += 6 * u.dx(0) * xi + gamma * xi_xxx
                projector = Projector(a_expr, a_flux)
                self.projectors.append(projector)

            elif key == 'b':
                # find 12 * u * Xi_x
                mesh = u.function_space().mesh()
                gamma = simulation_parameters['gamma'][-1]
                b_flux = self.diagnostic_variables.fields['b']
                xis = self.prognostic_variables.pure_xis

                x, = SpatialCoordinate(mesh)
                b_expr = 0.0 * x
                for xi, xi_x, xi_xxx in zip(xis, xis_x, xis_xxx):
                    b_expr += 12 * u * xi.dx(0)
                projector = Projector(b_expr, b_flux)
                self.projectors.append(projector)

            elif key == 'kdv_1':
                # find the first part of the kdv form
                u0 = prognostic_variables.u0
                uh = (u + u0) / 2
                us = Dt * uh + sqrt(Dt) * Xi
                psi = TestFunction(Vu)
                du_1 = self.diagnostic_variables.fields['kdv_1']

                eqn = psi * du_1 * dx - 6 * psi.dx(0) * uh * us * dx
                prob = NonlinearVariationalProblem(eqn, du_1)
                solver = NonlinearVariationalSolver(prob)
                self.solvers.append(solver)

            elif key == 'kdv_2':
                # find the second part of the kdv form
                u0 = prognostic_variables.u0
                uh = (u + u0) / 2
                us = Dt * uh + sqrt(Dt) * Xi
                psi = TestFunction(Vu)
                du_2 = self.diagnostic_variables.fields['kdv_2']

                eqn = psi * du_2 * dx + 6 * psi * uh * us.dx(0) * dx
                prob = NonlinearVariationalProblem(eqn, du_2)
                solver = NonlinearVariationalSolver(prob)
                self.solvers.append(solver)

            elif key == 'kdv_3':
                # find the third part of the kdv form
                u0 = prognostic_variables.u0
                uh = (u + u0) / 2
                us = Dt * uh + sqrt(Dt) * Xi
                du_3 = self.diagnostic_variables.fields['kdv_3']
                gamma = simulation_parameters['gamma'][-1]

                phi = TestFunction(Vu)
                F = Function(Vu)

                eqn = (phi * F * dx + phi.dx(0) * us.dx(0) * dx)
                prob = NonlinearVariationalProblem(eqn, F)
                solver = NonlinearVariationalSolver(prob)
                self.solvers.append(solver)

                self.projectors.append(Projector(-gamma * F.dx(0), du_3))

                # nu = TestFunction(Vu)
                # back_eqn = nu * du_3 * dx - gamma * nu.dx(0) * F * dx
                # back_prob = NonlinearVariationalProblem(back_eqn, du_3)
                # back_solver = NonlinearVariationalSolver(back_prob)
                # self.solvers.append(solver)

            elif key == 'm':

                m = self.diagnostic_variables.fields['m']
                phi = TestFunction(Vu)
                eqn = phi * m * dx - phi * u * dx - alphasq * phi.dx(0) * u.dx(
                    0) * dx
                prob = NonlinearVariationalProblem(eqn, m)
                solver = NonlinearVariationalSolver(prob)
                self.solvers.append(solver)

            elif key == 'u_xx':

                u_xx = self.diagnostic_variables.fields['u_xx']
                phi = TestFunction(Vu)
                eqn = phi * u_xx * dx + phi.dx(0) * u_xx.dx(0) * dx
                prob = NonlinearVariationalProblem(eqn, u_xx)
                solver = NonlinearVariationalSolver(prob)
                self.solvers.append(solver)

            elif key == 'u_sde':
                self.to_update_constants = True
                self.Ld = Ld
                self.alphasq = alphasq
                self.p = Constant(1.0 * 0.5 * (1 + exp(-Ld / sqrt(alphasq))) /
                                  (1 - exp(-Ld / sqrt(alphasq))))
                self.q = Constant(Ld / 2)

                u_sde = self.diagnostic_variables.fields['u_sde']
                if periodic:
                    expr = conditional(
                        x < self.q - Ld / 2,
                        self.p * ((exp(-(x - self.q + Ld) / sqrt(alphasq)) +
                                   exp(-Ld / sqrt(alphasq)) * exp(
                                       (x - self.q + Ld) / sqrt(alphasq))) /
                                  (1 - exp(-Ld / sqrt(alphasq)))),
                        conditional(
                            x < self.q + Ld / 2,
                            self.p * ((exp(-sqrt((self.q - x)**2 / alphasq)) +
                                       exp(-Ld / sqrt(alphasq)) *
                                       exp(sqrt((self.q - x)**2 / alphasq))) /
                                      (1 - exp(-Ld / sqrt(alphasq)))),
                            self.p *
                            ((exp(-(self.q + Ld - x) / sqrt(alphasq)) +
                              exp(-Ld / sqrt(alphasq) * exp(
                                  (self.q + Ld - x) / sqrt(alphasq)))) /
                             (1 - exp(-Ld / sqrt(alphasq))))))
                else:
                    expr = conditional(
                        x < self.q - Ld / 2,
                        self.p * exp(-(x - self.q + Ld) / sqrt(alphasq)),
                        conditional(
                            x < self.q + Ld / 2,
                            self.p * exp(-sqrt((self.q - x)**2 / alphasq)),
                            self.p * exp(-(self.q + Ld - x) / sqrt(alphasq))))

                self.interpolators.append(Interpolator(expr, u_sde))

            elif key == 'u_sde_weak':
                u_sde = self.diagnostic_variables.fields['u_sde']
                u_sde_weak = self.diagnostic_variables.fields['u_sde_weak']
                psi = TestFunction(Vu)

                eqn = psi * u_sde_weak * dx - psi * (u - u_sde) * dx
                prob = NonlinearVariationalProblem(eqn, u_sde_weak)
                solver = NonlinearVariationalSolver(prob)
                self.solvers.append(solver)

            elif key == 'u_sde_mean':
                self.to_update_constants = True
                self.p = Constant(1.0)
                self.q = Constant(Ld / 2)

                if periodic:
                    raise NotImplementedError(
                        'u_sde_mean not yet implemented for periodic peakon')

                u_sde = self.diagnostic_variables.fields['u_sde_mean']
                expr = conditional(
                    x < self.q - Ld / 2,
                    self.p * exp(-(x - self.q + Ld) / sqrt(alphasq)),
                    conditional(
                        x < self.q + Ld / 2,
                        self.p * exp(-sqrt((self.q - x)**2 / alphasq)),
                        self.p * exp(-(self.q + Ld - x) / sqrt(alphasq))))
                self.interpolators.append(Interpolator(expr, u_sde))

            elif key == 'u_sde_weak_mean':
                u_sde = self.diagnostic_variables.fields['u_sde_mean']
                u_sde_weak = self.diagnostic_variables.fields[
                    'u_sde_weak_mean']
                psi = TestFunction(Vu)

                eqn = psi * u_sde_weak * dx - psi * (u - u_sde) * dx
                prob = NonlinearVariationalProblem(eqn, u_sde_weak)
                solver = NonlinearVariationalSolver(prob)
                self.solvers.append(solver)

            elif key == 'pure_xi':
                pure_xi = 0.0 * x
                for xi in self.prognostic_variables.pure_xi_list:
                    if vector_u:
                        pure_xi += dot(ones, xi)
                    else:
                        pure_xi += xi
                Xiscalar = self.diagnostic_variables.fields['pure_xi']
                Xi_interpolator = Interpolator(pure_xi, Xiscalar)
                self.interpolators.append(Xi_interpolator)

            elif key == 'pure_xi_x':
                pure_xi_x = 0.0 * x
                for xix in self.prognostic_variables.pure_xi_x_list:
                    if vector_u:
                        pure_xi_x += dot(ones, xix)
                    else:
                        pure_xi_x += xix
                Xiscalar = self.diagnostic_variables.fields['pure_xi_x']
                Xi_interpolator = Interpolator(pure_xi_x, Xiscalar)
                self.interpolators.append(Xi_interpolator)

            elif key == 'pure_xi_xx':
                pure_xi_xx = 0.0 * x
                for xixx in self.prognostic_variables.pure_xi_xx_list:
                    if vector_u:
                        pure_xi_xx += dot(ones, xixx)
                    else:
                        pure_xi_xx += xixx
                Xiscalar = self.diagnostic_variables.fields['pure_xi_xx']
                Xi_interpolator = Interpolator(pure_xi_xx, Xiscalar)
                self.interpolators.append(Xi_interpolator)

            elif key == 'pure_xi_xxx':
                pure_xi_xxx = 0.0 * x
                for xixxx in self.prognostic_variables.pure_xi_xxx_list:
                    if vector_u:
                        pure_xi_xxx += dot(ones, xixxx)
                    else:
                        pure_xi_xxx += xixxx
                Xiscalar = self.diagnostic_variables.fields['pure_xi_xxx']
                Xi_interpolator = Interpolator(pure_xi_xxx, Xiscalar)
                self.interpolators.append(Xi_interpolator)

            elif key == 'pure_xi_xxxx':
                pure_xi_xxxx = 0.0 * x
                for xixxxx in self.prognostic_variables.pure_xi_xx_list:
                    if vector_u:
                        pure_xi_xxxx += dot(ones, xixxxx)
                    else:
                        pure_xi_xxxx += xixxxx
                Xiscalar = self.diagnostic_variables.fields['pure_xi_xxxx']
                Xi_interpolator = Interpolator(pure_xi_xxxx, Xiscalar)
                self.interpolators.append(Xi_interpolator)

            else:
                raise NotImplementedError('Diagnostic %s not yet implemented' %
                                          key)
Пример #32
0
def heat_exchanger_optimization(mu=0.03, n_iters=1000):

    output_dir = "2D/"

    path = os.path.abspath(__file__)
    dir_path = os.path.dirname(path)
    mesh = fd.Mesh(f"{dir_path}/2D_mesh.msh")
    # Perturb the mesh coordinates. Necessary to calculate shape derivatives
    S = fd.VectorFunctionSpace(mesh, "CG", 1)
    s = fd.Function(S, name="deform")
    mesh.coordinates.assign(mesh.coordinates + s)

    # Initial level set function
    x, y = fd.SpatialCoordinate(mesh)
    PHI = fd.FunctionSpace(mesh, "CG", 1)
    phi_expr = sin(y * pi / 0.2) * cos(x * pi / 0.2) - fd.Constant(0.8)
    # Avoid recording the operation interpolate into the tape.
    # Otherwise, the shape derivatives will not be correct
    with fda.stop_annotating():
        phi = fd.interpolate(phi_expr, PHI)
        phi.rename("LevelSet")
        fd.File(output_dir + "phi_initial.pvd").write(phi)

    # Physics
    mu = fd.Constant(mu)  # viscosity
    alphamin = 1e-12
    alphamax = 2.5 / (2e-4)
    parameters = {
        "mat_type": "aij",
        "ksp_type": "preonly",
        "ksp_converged_reason": None,
        "pc_type": "lu",
        "pc_factor_mat_solver_type": "mumps",
    }
    stokes_parameters = parameters
    temperature_parameters = parameters
    u_inflow = 2e-3
    tin1 = fd.Constant(10.0)
    tin2 = fd.Constant(100.0)

    P2 = fd.VectorElement("CG", mesh.ufl_cell(), 2)
    P1 = fd.FiniteElement("CG", mesh.ufl_cell(), 1)
    TH = P2 * P1
    W = fd.FunctionSpace(mesh, TH)

    U = fd.TrialFunction(W)
    u, p = fd.split(U)
    V = fd.TestFunction(W)
    v, q = fd.split(V)

    epsilon = fd.Constant(10000.0)

    def hs(phi, epsilon):
        return fd.Constant(alphamax) * fd.Constant(1.0) / (
            fd.Constant(1.0) + exp(-epsilon * phi)) + fd.Constant(alphamin)

    def stokes(phi, BLOCK_INLET_MOUTH, BLOCK_OUTLET_MOUTH):
        a_fluid = mu * inner(grad(u), grad(v)) - div(v) * p - q * div(u)
        darcy_term = inner(u, v)
        return (a_fluid * dx + hs(phi, epsilon) * darcy_term * dx(0) +
                alphamax * darcy_term *
                (dx(BLOCK_INLET_MOUTH) + dx(BLOCK_OUTLET_MOUTH)))

    # Dirichlet boundary conditions
    inflow1 = fd.as_vector([
        u_inflow * sin(
            ((y - (line_sep -
                   (dist_center + inlet_width))) * pi) / inlet_width),
        0.0,
    ])
    inflow2 = fd.as_vector([
        u_inflow * sin(((y - (line_sep + dist_center)) * pi) / inlet_width),
        0.0,
    ])

    noslip = fd.Constant((0.0, 0.0))

    # Stokes 1
    bcs1_1 = fd.DirichletBC(W.sub(0), noslip, WALLS)
    bcs1_2 = fd.DirichletBC(W.sub(0), inflow1, INLET1)
    bcs1_3 = fd.DirichletBC(W.sub(1), fd.Constant(0.0), OUTLET1)
    bcs1_4 = fd.DirichletBC(W.sub(0), noslip, INLET2)
    bcs1_5 = fd.DirichletBC(W.sub(0), noslip, OUTLET2)
    bcs1 = [bcs1_1, bcs1_2, bcs1_3, bcs1_4, bcs1_5]

    # Stokes 2
    bcs2_1 = fd.DirichletBC(W.sub(0), noslip, WALLS)
    bcs2_2 = fd.DirichletBC(W.sub(0), inflow2, INLET2)
    bcs2_3 = fd.DirichletBC(W.sub(1), fd.Constant(0.0), OUTLET2)
    bcs2_4 = fd.DirichletBC(W.sub(0), noslip, INLET1)
    bcs2_5 = fd.DirichletBC(W.sub(0), noslip, OUTLET1)
    bcs2 = [bcs2_1, bcs2_2, bcs2_3, bcs2_4, bcs2_5]

    # Forward problems
    U1, U2 = fd.Function(W), fd.Function(W)
    L = inner(fd.Constant((0.0, 0.0, 0.0)), V) * dx
    problem = fd.LinearVariationalProblem(stokes(-phi, INMOUTH2, OUTMOUTH2),
                                          L,
                                          U1,
                                          bcs=bcs1)
    solver_stokes1 = fd.LinearVariationalSolver(
        problem,
        solver_parameters=stokes_parameters,
        options_prefix="stokes_1")
    solver_stokes1.solve()
    problem = fd.LinearVariationalProblem(stokes(phi, INMOUTH1, OUTMOUTH1),
                                          L,
                                          U2,
                                          bcs=bcs2)
    solver_stokes2 = fd.LinearVariationalSolver(
        problem,
        solver_parameters=stokes_parameters,
        options_prefix="stokes_2")
    solver_stokes2.solve()

    # Convection difussion equation
    ks = fd.Constant(1e0)
    cp_value = 5.0e5
    cp = fd.Constant(cp_value)
    T = fd.FunctionSpace(mesh, "DG", 1)
    t = fd.Function(T, name="Temperature")
    w = fd.TestFunction(T)

    # Mesh-related functions
    n = fd.FacetNormal(mesh)
    h = fd.CellDiameter(mesh)
    u1, p1 = fd.split(U1)
    u2, p2 = fd.split(U2)

    def upwind(u):
        return (dot(u, n) + abs(dot(u, n))) / 2.0

    u1n = upwind(u1)
    u2n = upwind(u2)

    # Penalty term
    alpha = fd.Constant(500.0)
    # Bilinear form
    a_int = dot(grad(w), ks * grad(t) - cp * (u1 + u2) * t) * dx

    a_fac = (fd.Constant(-1.0) * ks * dot(avg(grad(w)), jump(t, n)) * dS +
             fd.Constant(-1.0) * ks * dot(jump(w, n), avg(grad(t))) * dS +
             ks("+") *
             (alpha("+") / avg(h)) * dot(jump(w, n), jump(t, n)) * dS)

    a_vel = (dot(
        jump(w),
        cp * (u1n("+") + u2n("+")) * t("+") - cp *
        (u1n("-") + u2n("-")) * t("-"),
    ) * dS + dot(w,
                 cp * (u1n + u2n) * t) * ds)

    a_bnd = (dot(w,
                 cp * dot(u1 + u2, n) * t) * (ds(INLET1) + ds(INLET2)) +
             w * t * (ds(INLET1) + ds(INLET2)) - w * tin1 * ds(INLET1) -
             w * tin2 * ds(INLET2) + alpha / h * ks * w * t *
             (ds(INLET1) + ds(INLET2)) - ks * dot(grad(w), t * n) *
             (ds(INLET1) + ds(INLET2)) - ks * dot(grad(t), w * n) *
             (ds(INLET1) + ds(INLET2)))

    aT = a_int + a_fac + a_vel + a_bnd

    LT_bnd = (alpha / h * ks * tin1 * w * ds(INLET1) +
              alpha / h * ks * tin2 * w * ds(INLET2) -
              tin1 * ks * dot(grad(w), n) * ds(INLET1) -
              tin2 * ks * dot(grad(w), n) * ds(INLET2))

    problem = fd.LinearVariationalProblem(derivative(aT, t), LT_bnd, t)
    solver_temp = fd.LinearVariationalSolver(
        problem,
        solver_parameters=temperature_parameters,
        options_prefix="temperature",
    )
    solver_temp.solve()
    # fd.solve(eT == 0, t, solver_parameters=temperature_parameters)

    # Cost function: Flux at the cold outlet
    scale_factor = 4e-4
    Jform = fd.assemble(
        fd.Constant(-scale_factor * cp_value) * inner(t * u1, n) * ds(OUTLET1))
    # Constraints: Pressure drop on each fluid
    power_drop = 1e-2
    Power1 = fd.assemble(p1 / power_drop * ds(INLET1))
    Power2 = fd.assemble(p2 / power_drop * ds(INLET2))

    phi_pvd = fd.File("phi_evolution.pvd")

    def deriv_cb(phi):
        with stop_annotating():
            phi_pvd.write(phi[0])

    c = fda.Control(s)

    # Reduced Functionals
    Jhat = LevelSetFunctional(Jform, c, phi, derivative_cb_pre=deriv_cb)
    P1hat = LevelSetFunctional(Power1, c, phi)
    P1control = fda.Control(Power1)

    P2hat = LevelSetFunctional(Power2, c, phi)
    P2control = fda.Control(Power2)

    Jhat_v = Jhat(phi)
    print("Initial cost function value {:.5f}".format(Jhat_v), flush=True)
    print("Power drop 1 {:.5f}".format(Power1), flush=True)
    print("Power drop 2 {:.5f}".format(Power2), flush=True)

    beta_param = 0.08
    # Regularize the shape derivatives only in the domain marked with 0
    reg_solver = RegularizationSolver(S,
                                      mesh,
                                      beta=beta_param,
                                      gamma=1e5,
                                      dx=dx,
                                      design_domain=0)

    tol = 1e-5
    dt = 0.05
    params = {
        "alphaC": 1.0,
        "debug": 5,
        "alphaJ": 1.0,
        "dt": dt,
        "K": 1e-3,
        "maxit": n_iters,
        "maxtrials": 5,
        "itnormalisation": 10,
        "tol_merit":
        5e-3,  # new merit can be within 0.5% of the previous merit
        # "normalize_tol" : -1,
        "tol": tol,
    }

    solver_parameters = {
        "reinit_solver": {
            "h_factor": 2.0,
        }
    }
    # Optimization problem
    problem = InfDimProblem(
        Jhat,
        reg_solver,
        ineqconstraints=[
            Constraint(P1hat, 1.0, P1control),
            Constraint(P2hat, 1.0, P2control),
        ],
        solver_parameters=solver_parameters,
    )
    results = nlspace_solve(problem, params)

    return results
Пример #33
0
mu = fd.Constant(mu)
rho = fd.Constant(rho)

n = fd.FacetNormal(mesh)
mul = fd.Function(DG0)
mul.interpolate(fd.conditional(logical, mueff[0], mueff[1]))


def D(x):
    return 2*fd.sym(fd.grad(x))


# weak form -> SB
F_sb = 2*mu*fd.inner(D(v), D(u))*fd.dx - p*fd.div(v)*fd.dx + \
    mu*ikm*fd.inner(u, v)*fd.dx + q*fd.div(u)*fd.dx - \
    2*mu*fd.inner(fd.avg(D(u)*n), fd.jump(v))*fd.dS - \
    2*mu*Beta*fd.inner(fd.avg(D(v)*n), fd.jump(u))*fd.dS -\
    fd.inner(f, v)*fd.dx - p_out*fd.inner(v, n)*fd.ds(outlet)


# -------------------------------------------------------------------------
# transport
# coefficients
Dt = fd.Constant(np.sqrt(tol))
c_mid = 0.5 * (c0 + c)  # Crank-Nicolson timestepping

# stability
gamma = fd.Constant(2*(mesh.geometric_dimension()+1) /
                    mesh.geometric_dimension())
h_E = fd.sqrt(2) * fd.CellVolume(mesh) / fd.CellDiameter(mesh)
Пример #34
0
                          Ty('+') * Ty('-') / fd.avg(Ty), 0.0)
Tz_facet = fd.conditional(fd.gt(fd.avg(Tz), 0.0),
                          Tz('+') * Tz('-') / fd.avg(Tz), 0.0)

T_facet = (Tx_facet * (abs(n[0]('+')) + abs(n[0]('-'))) / 2 + Ty_facet *
           (abs(n[1]('+')) + abs(n[1]('-'))) / 2 + Tz_facet *
           (abs(n[2]('+')) + abs(n[2]('-'))) / 2)

# We can now define the bilinear and linear forms for the left and right
x, y, z = mesh.coordinates

x_func = fd.interpolate(x, V)
y_func = fd.interpolate(y, V)
z_func = fd.interpolate(z, V)

Delta_x = fd.jump(x_func)
Delta_y = fd.jump(y_func)
Delta_z = fd.jump(z_func)

Delta = fd.sqrt(Delta_x**2 + Delta_y**2 + Delta_z**2)

dx = fd.dx

alpha = 1
gamma = 1

m = u * v * w * dx
a = T_facet/Delta*fd.dot(fd.jump(v,n), fd.jump(u,n))*fd.dS_h \
  + T_facet/Delta*fd.dot(fd.jump(v,n), fd.jump(u,n))*fd.dS_v

# Defining the eigenvalue problem
Пример #35
0
    def __init__(self, state, V):
        super(EulerPoincareForm, self).__init__(state)

        dt = state.timestepping.dt
        w = TestFunction(V)
        u = TrialFunction(V)
        self.u0 = Function(V)
        ustar = 0.5*(self.u0 + u)
        n = FacetNormal(state.mesh)
        Upwind = 0.5*(sign(dot(self.ubar, n))+1)

        if state.mesh.geometric_dimension() == 3:

            if V.extruded:
                surface_measure = (dS_h + dS_v)
            else:
                surface_measure = dS

            # <w,curl(u) cross ubar + grad( u.ubar)>
            # =<curl(u),ubar cross w> - <div(w), u.ubar>
            # =<u,curl(ubar cross w)> -
            #      <<u_upwind, [[n cross(ubar cross w)cross]]>>

            both = lambda u: 2*avg(u)

            Eqn = (
                inner(w, u-self.u0)*dx
                + dt*inner(ustar, curl(cross(self.ubar, w)))*dx
                - dt*inner(both(Upwind*ustar),
                           both(cross(n, cross(self.ubar, w))))*surface_measure
                - dt*div(w)*inner(ustar, self.ubar)*dx
            )

        # define surface measure and terms involving perp differently
        # for slice (i.e. if V.extruded is True) and shallow water
        # (V.extruded is False)
        else:
            if V.extruded:
                surface_measure = (dS_h + dS_v)
                perp = lambda u: as_vector([-u[1], u[0]])
                perp_u_upwind = Upwind('+')*perp(ustar('+')) + Upwind('-')*perp(ustar('-'))
            else:
                surface_measure = dS
                outward_normals = CellNormal(state.mesh)
                perp = lambda u: cross(outward_normals, u)
                perp_u_upwind = Upwind('+')*cross(outward_normals('+'),ustar('+')) + Upwind('-')*cross(outward_normals('-'),ustar('-'))

            Eqn = (
                (inner(w, u-self.u0)
                 - dt*inner(w, div(perp(ustar))*perp(self.ubar))
                 - dt*div(w)*inner(ustar, self.ubar))*dx
                - dt*inner(jump(inner(w, perp(self.ubar)), n),
                           perp_u_upwind)*surface_measure
                + dt*jump(inner(w,
                                perp(self.ubar))*perp(ustar), n)*surface_measure
            )

        a = lhs(Eqn)
        L = rhs(Eqn)
        self.u1 = Function(V)
        uproblem = LinearVariationalProblem(a, L, self.u1)
        self.usolver = LinearVariationalSolver(uproblem,
                                               options_prefix='EPAdvection')
Пример #36
0
    def _setup_solver(self):
        state = self.state      # just cutting down line length a bit
        dt = state.timestepping.dt
        beta = dt*state.timestepping.alpha
        cp = state.parameters.cp
        mu = state.mu

        # Split up the rhs vector (symbolically)
        u_in, rho_in, theta_in = split(state.xrhs)

        # Build the reduced function space for u,rho
        M = MixedFunctionSpace((state.V[0], state.V[1]))
        w, phi = TestFunctions(M)
        u, rho = TrialFunctions(M)

        n = FacetNormal(state.mesh)

        # Get background fields
        thetabar = state.thetabar
        rhobar = state.rhobar
        pibar = exner(thetabar, rhobar, state)
        pibar_rho = exner_rho(thetabar, rhobar, state)
        pibar_theta = exner_theta(thetabar, rhobar, state)

        # Analytical (approximate) elimination of theta
        k = state.k             # Upward pointing unit vector
        theta = -dot(k,u)*dot(k,grad(thetabar))*beta + theta_in

        # Only include theta' (rather than pi') in the vertical
        # component of the gradient

        # the pi prime term (here, bars are for mean and no bars are
        # for linear perturbations)

        pi = pibar_theta*theta + pibar_rho*rho

        # vertical projection
        def V(u):
            return k*inner(u,k)

        eqn = (
            inner(w, (u - u_in))*dx
            - beta*cp*div(theta*V(w))*pibar*dx
            # following does nothing but is preserved in the comments
            # to remind us why (because V(w) is purely vertical.
            # + beta*cp*jump(theta*V(w),n)*avg(pibar)*dS_v
            - beta*cp*div(thetabar*w)*pi*dx
            + beta*cp*jump(thetabar*w,n)*avg(pi)*dS_v
            + (phi*(rho - rho_in) - beta*inner(grad(phi), u)*rhobar)*dx
            + beta*jump(phi*u, n)*avg(rhobar)*(dS_v + dS_h)
        )

        if mu is not None:
            eqn += dt*mu*inner(w,k)*inner(u,k)*dx
        aeqn = lhs(eqn)
        Leqn = rhs(eqn)

        # Place to put result of u rho solver
        self.urho = Function(M)

        # Boundary conditions (assumes extruded mesh)
        dim = M.sub(0).ufl_element().value_shape()[0]
        bc = ("0.0",)*dim
        bcs = [DirichletBC(M.sub(0), Expression(bc), "bottom"),
               DirichletBC(M.sub(0), Expression(bc), "top")]

        # Solver for u, rho
        urho_problem = LinearVariationalProblem(
            aeqn, Leqn, self.urho, bcs=bcs)

        self.urho_solver = LinearVariationalSolver(urho_problem,
                                                   solver_parameters=self.params,
                                                   options_prefix='ImplicitSolver')

        # Reconstruction of theta
        theta = TrialFunction(state.V[2])
        gamma = TestFunction(state.V[2])

        u, rho = self.urho.split()
        self.theta = Function(state.V[2])

        theta_eqn = gamma*(theta - theta_in +
                           dot(k,u)*dot(k,grad(thetabar))*beta)*dx

        theta_problem = LinearVariationalProblem(lhs(theta_eqn),
                                                 rhs(theta_eqn),
                                                 self.theta)
        self.theta_solver = LinearVariationalSolver(theta_problem,
                                                    options_prefix='thetabacksubstitution')
                                       "pc_type": "lu"
                                   })
q_solver.solve()

# Build advection, forcing forms
Frhs = unk * Dnk / 3. + un * Dnk / 6. + unk * Dn / 6. + un * Dn / 3.
K = inner(un, un) / 3. + inner(un, unk) / 3. + inner(unk, unk) / 3.
Prhs = g * (0.5 * (Dn + Dp) + b) + 0.5 * K

# D advection solver
phi = TestFunction(W0)
D_ = TrialFunction(W0)
D_bar = 0.5 * (Dn + D_)

D_ad = (inner(grad(phi), D_bar * u_rec) * dx -
        jump(phi * u_rec, n) * uw(ubar, D_bar) * dS)
D_eqn = (D_ - Dn) * phi * dx - dt * D_ad
Dad_p = LinearVariationalProblem(lhs(D_eqn), rhs(D_eqn), Dp)
D_ad_solver = LinearVariationalSolver(Dad_p)

# u advection solver
w = TestFunction(W1)
u_ = TrialFunction(W1)
u_bar = 0.5 * (un + u_)

u_ad = (inner(perp(grad(inner(w, perp(u_rec)))), u_bar) * dx +
        inner(jump(inner(w, perp(u_rec)), n), p_uw(ubar, u_bar)) * dS)
u_eqn = inner(u_ - un, w) * dx - dt * u_ad
uad_p = LinearVariationalProblem(lhs(u_eqn), rhs(u_eqn), uad)
u_ad_solver = LinearVariationalSolver(uad_p)