def compute_cfl_number(mesh, velocity, time_step):
    assert(isinstance(mesh, dlfn.Mesh))
    assert(isinstance(velocity, dlfn.Function))
    assert(isinstance(time_step, float) and time_step > 0.0)
    Vh_DG = dlfn.FunctionSpace(mesh, "DG", 0)
    h_cell = dlfn.CellDiameter(mesh)
    cfl_cell_expression = dlfn.sqrt(dlfn.inner(velocity, velocity)) * time_step / h_cell
    local_cfl = dlfn.project(cfl_cell_expression, Vh_DG)
    return local_cfl.vector().max()
 def _compute_cfl_number(self, velocity, time_step):
     assert hasattr(self, "_mesh")
     assert (isinstance(velocity, dlfn.Function))
     assert (isinstance(time_step, float) and time_step > 0.0)
     Vh = dlfn.FunctionSpace(self._mesh, "DG", 0)
     h_cell = dlfn.CellDiameter(self._mesh)
     from dolfin import sqrt, inner
     cfl_cell_expression = sqrt(inner(velocity, velocity)) * time_step / (
         self._parameters.velocity_degree * h_cell)
     local_cfl = dlfn.project(cfl_cell_expression, Vh)
     return local_cfl.vector().max()
示例#3
0
    def update_mesh_data(self, connectivity_changed=True):
        """
        Some precomputed values must be calculated before the timestepping
        and updated every time the mesh changes
        """
        if connectivity_changed:
            init_connectivity(self)
        precompute_cell_data(self)
        precompute_facet_data(self)

        # Work around missing consensus on what CellDiameter is for bendy cells
        mesh = self.data['mesh']
        if mesh.ufl_coordinate_element().degree() > 1:
            h = dolfin.CellVolume(mesh)**(1 / mesh.topology().dim())
        else:
            h = dolfin.CellDiameter(mesh)
        self.data['h'] = h
示例#4
0
    def __init__(self, mesh, Vh, prior, misfit, simulation_times,
                 wind_velocity, gls_stab):
        self.mesh = mesh
        self.Vh = Vh
        self.prior = prior
        self.misfit = misfit
        # Assume constant timestepping
        self.simulation_times = simulation_times
        dt = simulation_times[1] - simulation_times[0]

        u = dl.TrialFunction(Vh[STATE])
        v = dl.TestFunction(Vh[STATE])

        kappa = dl.Constant(.001)
        dt_expr = dl.Constant(dt)

        r_trial = u + dt_expr * (-ufl.div(kappa * ufl.grad(u)) +
                                 ufl.inner(wind_velocity, ufl.grad(u)))
        r_test = v + dt_expr * (-ufl.div(kappa * ufl.grad(v)) +
                                ufl.inner(wind_velocity, ufl.grad(v)))

        h = dl.CellDiameter(mesh)
        vnorm = ufl.sqrt(ufl.inner(wind_velocity, wind_velocity))
        if gls_stab:
            tau = ufl.min_value((h * h) / (dl.Constant(2.) * kappa), h / vnorm)
        else:
            tau = dl.Constant(0.)

        self.M = dl.assemble(ufl.inner(u, v) * dl.dx)
        self.M_stab = dl.assemble(ufl.inner(u, v + tau * r_test) * dl.dx)
        self.Mt_stab = dl.assemble(ufl.inner(u + tau * r_trial, v) * dl.dx)
        Nvarf = (ufl.inner(kappa * ufl.grad(u), ufl.grad(v)) +
                 ufl.inner(wind_velocity, ufl.grad(u)) * v) * dl.dx
        Ntvarf = (ufl.inner(kappa * ufl.grad(v), ufl.grad(u)) +
                  ufl.inner(wind_velocity, ufl.grad(v)) * u) * dl.dx
        self.N = dl.assemble(Nvarf)
        self.Nt = dl.assemble(Ntvarf)
        stab = dl.assemble(tau * ufl.inner(r_trial, r_test) * dl.dx)
        self.L = self.M + dt * self.N + stab
        self.Lt = self.M + dt * self.Nt + stab

        self.solver = dl.PETScLUSolver(dl.as_backend_type(self.L))
        self.solvert = dl.PETScLUSolver(dl.as_backend_type(self.Lt))

        # Part of model public API
        self.gauss_newton_approx = False
示例#5
0
    def set_forms(self):
        """
        Set up week forms
        """
        # Assume constant timestepping
        dt = self.simulation_times[1] - self.simulation_times[0]

        self.wind_velocity = self.computeVelocityField()

        u = dl.TrialFunction(self.Vh[STATE])
        v = dl.TestFunction(self.Vh[STATE])

        kappa = dl.Constant(self.kappa)
        dt_expr = dl.Constant(dt)

        r_trial = u + dt_expr * (-ufl.div(kappa * ufl.grad(u)) +
                                 ufl.inner(self.wind_velocity, ufl.grad(u)))
        r_test = v + dt_expr * (-ufl.div(kappa * ufl.grad(v)) +
                                ufl.inner(self.wind_velocity, ufl.grad(v)))

        h = dl.CellDiameter(self.mesh)
        vnorm = ufl.sqrt(ufl.inner(self.wind_velocity, self.wind_velocity))
        if self.gls_stab:
            tau = ufl.min_value((h * h) / (dl.Constant(2.) * kappa), h / vnorm)
        else:
            tau = dl.Constant(0.)

        self.M = dl.assemble(ufl.inner(u, v) * ufl.dx)
        self.M_stab = dl.assemble(ufl.inner(u, v + tau * r_test) * ufl.dx)
        self.Mt_stab = dl.assemble(ufl.inner(u + tau * r_trial, v) * ufl.dx)
        Nvarf = (ufl.inner(kappa * ufl.grad(u), ufl.grad(v)) +
                 ufl.inner(self.wind_velocity, ufl.grad(u)) * v) * ufl.dx
        Ntvarf = (ufl.inner(kappa * ufl.grad(v), ufl.grad(u)) +
                  ufl.inner(self.wind_velocity, ufl.grad(v)) * u) * ufl.dx
        self.N = dl.assemble(Nvarf)
        self.Nt = dl.assemble(Ntvarf)
        stab = dl.assemble(tau * ufl.inner(r_trial, r_test) * ufl.dx)
        self.L = self.M + dt * self.N + stab
        self.Lt = self.M + dt * self.Nt + stab

        self.solver = PETScLUSolver(self.mpi_comm)
        self.solver.set_operator(dl.as_backend_type(self.L))
        self.solvert = PETScLUSolver(self.mpi_comm)
        self.solvert.set_operator(dl.as_backend_type(self.Lt))
示例#6
0
 def apply_stabilization(self):
     df.dS = self.dS  #Important <----
     h_msh = df.CellDiameter(self.mesh)
     h_avg = (h_msh("+") + h_msh("-")) / 2.0
     #Output
     local_stab = 0.0
     if self.stab_type == 'cip':
         if self.moment_order == 3 or self.moment_order == 'ns':
             local_stab += self.DELTA_T * h_avg**self.ht * df.jump(df.grad(self.u[0]),self.nv)\
                     * df.jump(df.grad(self.v[0]),self.nv) * df.dS #cip for temp
         if self.moment_order == 6:
             local_stab += self.DELTA_P * h_avg**self.hp * df.jump(df.grad(self.u[0]),self.nv)\
                     * df.jump(df.grad(self.v[0]),self.nv) * df.dS #cip for pressure
             local_stab += self.DELTA_U * h_avg**self.hu * df.jump(df.grad(self.u[1]),self.nv)\
                     * df.jump(df.grad(self.v[1]),self.nv) * df.dS #cip for velocity_x
             local_stab += self.DELTA_U * h_avg**self.hu * df.jump(df.grad(self.u[2]),self.nv)\
                     * df.jump(df.grad(self.v[2]),self.nv) * df.dS #cip for velocity_y
         if self.moment_order == 13:
             local_stab += self.DELTA_T * h_avg**self.ht * df.jump(df.grad(self.u[3]),self.nv)\
                     * df.jump(df.grad(self.v[3]),self.nv) * df.dS #cip for temp
             local_stab += self.DELTA_P * h_avg**self.hp * df.jump(df.grad(self.u[0]),self.nv)\
                     * df.jump(df.grad(self.v[0]),self.nv) * df.dS #cip for pressure
             local_stab += self.DELTA_U * h_avg**self.hu * df.jump(df.grad(self.u[1]),self.nv)\
                     * df.jump(df.grad(self.v[1]),self.nv) * df.dS #cip for velocity_x
             local_stab += self.DELTA_U * h_avg**self.hu * df.jump(df.grad(self.u[2]),self.nv)\
                     * df.jump(df.grad(self.v[2]),self.nv) * df.dS #cip for velocity_y
         if self.moment_order == 'grad13':
             local_stab += self.DELTA_T * h_avg**self.ht * df.jump(df.grad(self.u[3]),self.nv)\
                     * df.jump(df.grad(self.v[6]),self.nv) * df.dS #cip for temp
             local_stab += self.DELTA_P * h_avg**self.hp * df.jump(df.grad(self.u[0]),self.nv)\
                     * df.jump(df.grad(self.v[0]),self.nv) * df.dS #cip for pressure
             local_stab += self.DELTA_U * h_avg**self.hu * df.jump(df.grad(self.u[1]),self.nv)\
                     * df.jump(df.grad(self.v[1]),self.nv) * df.dS #cip for velocity_x
             local_stab += self.DELTA_U * h_avg**self.hu * df.jump(df.grad(self.u[2]),self.nv)\
                     * df.jump(df.grad(self.v[2]),self.nv) * df.dS #cip for velocity_y
     elif self.stab_type == 'gls':
         local_stab = (0.0001* h_msh * df.inner(self.SA_x * df.Dx(self.u,0)\
                 + self.SA_y * df.Dx(self.u,1) + self.SP_Coeff * self.u, self.SA_x * df.Dx(self.v,0)\
                 + self.SA_y * df.Dx(self.v,1) + self.SP_Coeff * self.v ) * df.dx)
     return local_stab
示例#7
0
    def __init__(self,
                 mesh,
                 energy,
                 state,
                 bcs,
                 z,
                 rayleigh=None,
                 nullspace=None,
                 parameters=None):
        self.i = 0
        self.parameters = self.default_parameters()
        if parameters is not None:
            self.parameters.update(parameters)  # for debug purposes
        self.u = state[0]
        self.alpha = state[1]
        self._u = dolfin.Vector(self.u.vector())
        self._alpha = dolfin.Vector(self.alpha.vector())
        self.meshsize = (mesh.hmax() + mesh.hmax()) / 2.
        self.mesh = mesh

        self.Z = z.function_space()
        self.z = z

        # self.Z = dolfin.FunctionSpace(mesh, dolfin.MixedElement([state[0].ufl_element(), state[1].ufl_element()]))
        # self.z = dolfin.Function(self.Z)

        self.z_old = dolfin.Function(self.Z)
        zeta = dolfin.TestFunction(self.Z)
        v, beta = dolfin.split(zeta)

        cdm = dolfin.project(
            dolfin.CellDiameter(self.mesh)**2.,
            dolfin.FunctionSpace(self.mesh, 'CG', 1))
        self.cellarea = dolfin.Function(z.function_space())
        self.cellarea.assign(cdm)

        self.ownership = self.Z.dofmap().ownership_range()
        self.assigner = dolfin.FunctionAssigner(
            self.Z,  # receiving space
            [self.u.function_space(),
             self.alpha.function_space()])  # assigning space

        dim = self.u.function_space().ufl_element().value_size()
        self.u_zero = dolfin.project(
            dolfin.Constant(0.),
            self.u.function_space()) if dim == 1 else dolfin.project(
                dolfin.Constant([0.] * dim), self.u.function_space())
        self.a_one = dolfin.project(dolfin.Constant(1.),
                                    self.alpha.function_space())

        Zu = self.Z.extract_sub_space([0])
        Za = self.Z.extract_sub_space([1])

        self.Xa = Za.collapse().tabulate_dof_coordinates()
        self.Xu = Zu.collapse().tabulate_dof_coordinates()
        (_, self.mapa) = Za.collapse(collapsed_dofs=True)
        (_, self.mapu) = Zu.collapse(collapsed_dofs=True)

        self.computed = []
        self.provided = []

        self.stable = ''
        self.negev = -1

        self.Ealpha = dolfin.derivative(
            energy, self.alpha,
            dolfin.TestFunction(self.alpha.ufl_function_space()))
        self.energy = energy

        (z_u, z_a) = dolfin.split(self.z)
        # import pdb; pdb.set_trace()
        # energy = ufl.replace(energy, {self.u: z_u, self.alpha: z_a})
        energy = ufl.replace(energy, {state[0]: z_u, state[1]: z_a})
        self.J = dolfin.derivative(energy, self.z, dolfin.TestFunction(self.Z))
        self.H = dolfin.derivative(self.J, self.z,
                                   dolfin.TrialFunction(self.Z))

        self.nullspace = nullspace

        if rayleigh:
            rP = rayleigh[0]
            rN = rayleigh[1]
            self.rP = dolfin.derivative(
                dolfin.derivative(rP, self.z, dolfin.TestFunction(self.Z)),
                self.z, dolfin.TrialFunction(self.Z))
            self.rN = dolfin.derivative(
                dolfin.derivative(rN, self.z, dolfin.TestFunction(self.Z)),
                self.z, dolfin.TrialFunction(self.Z))

        self.ownership_range = self.Z.dofmap().ownership_range()
        if len(bcs) > 0:
            self.bcs = bcs
            self.bc_dofs = self.get_bc_dofs(bcs)
        else:
            self.bcs = None
            self.bc_dofs = set()

        self.perturbation_v = dolfin.Function(self.Z.sub(0).collapse())
        self.perturbation_beta = dolfin.Function(self.Z.sub(1).collapse())

        dolfin.PETScOptions.set("ksp_type", "preonly")
        dolfin.PETScOptions.set("pc_type", "cholesky")
        dolfin.PETScOptions.set("pc_factor_mat_solver_type", "mumps")
        dolfin.PETScOptions.set("mat_mumps_icntl_24", 1)
        dolfin.PETScOptions.set("mat_mumps_icntl_13", 1)
        dolfin.PETScOptions.set("eps_monitor")
示例#8
0
    def initialize_variables(self):
        r"""
		Initialize the model variables to default values.  The variables
		defined here are:

		Various things :

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

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

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

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

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

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

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

		Grid mass :math:`m_i`:

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

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

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

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

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

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

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

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

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

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

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

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

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

        # save the number of degrees of freedom :
        self.dofs = self.m.vector().size()
psih_avg = 0.5 * (psi_h("+") + psi_h("-"))
psih_jump = psi_h("+") * nhat("+") + psi_h("-") * nhat("-")

Qs_upwind = df.avg(flow_dir) * Qs_avg + 0.5 * Qs_jump
# Sediment flux (Eq 8)
if geom == "1sided":
    R_Qs = ((ddot - edot) * psi_Q * df.dx +
            df.dot(Qs_upwind, psiQ_jump) * df.dS +
            Qs * flow_dir * nhat * psi_Q * ds(1))
else:
    R_Qs = ((ddot - edot) * psi_Q * df.dx +
            df.dot(Qs_upwind, psiQ_jump) * df.dS +
            Qs * flow_dir * nhat * psi_Q * ds  # (1)
            )
# Sediment transport (Eq 5)
h = df.CellDiameter(mesh)
dhsdt = (h_s("+") - h_s("-")) / (0.5 * (h("+") + h("-")))
R_hs = (psi_h *
        ((h_s - h_s0) / dt + rho_r / rho_s * Bdot - ddot + edot) * df.dx +
        df.avg(k_diff) * dhsdt * psih_jump * df.dS)
# Bedrock evolution (Eq 2)
R_B = psi_B * ((B - B0) / dt - Bdot) * df.dx
# ??
R_hsx = psi_h_ * (h_s - h_s_) * df.dx
# Effective thickness ?
R_heff = psi_eff * (h_eff - softplus(h_0, Base - Bhat, alpha=10.0)) * df.dx

# Weak form of sediment dynamics, solves for bedrock elevation, fluvial sed. flux,
# sediment thickness, projected sediment thickness, and effective water layer thickness.
R_sed = R_B + R_Qs + R_hs + R_hsx + R_heff
J_sed = df.derivative(R_sed, T, dT)
##########################################################
########################  MESH  ##########################
##########################################################

# Define a unit interval mesh with equal cell size
N_cells = 300
mesh = df.IntervalMesh(N_cells, 0, 1)

# Shift vertices such that they are concentrated towards the
# terminus following a polynomial curve.
mesh_exp = 1.5
mesh.coordinates()[:] = (1 - mesh.coordinates()**mesh_exp)[::-1]

# Mesh Functions
h = df.CellDiameter(mesh)  # Cell size
x_spatial = df.SpatialCoordinate(mesh)  # spatial coordinate
nhat = df.FacetNormal(mesh)  # facet normal vector
ocean = df.MeshFunction('size_t', mesh, 0, 0)  # boundary subdomain function
# ocean=1 -> terminus
# ocean=2 -> ice divide
df.ds = df.ds(subdomain_data=ocean)

for f in df.facets(mesh):
    if df.near(f.midpoint().x(), 1):
        ocean[f] = 1
    if df.near(f.midpoint().x(), 0):
        ocean[f] = 2

#########################################################
#################  FUNCTION SPACES  #####################
示例#11
0
# Geometric variables
d = Max(-Bhat, 1 / Z)  # Water depth
l = Max(0, Bhat + 1 / Z)  # water surface height
B = Max(Bhat, -rho / rho_w * H)  # Ice base
N = H - Max(rho_w / rho * (l - B), 0.8 * H)  # Effective pressure

dt = df.Constant(1e-8)

# Non-dimensional groups
U_ = (rho * g * Z) / (beta2 * L)
gamma = b / 2 * (U_ / L)**(1. / n) / (rho * g * Z)
tau_ = L / U_

# Signum and Heaviside function
S = phi / df.sqrt(phi**2 + df.CellDiameter(mesh)**2)
Heav = (S + 1) * 0.5

# Effective pressure regularization
N0 = 1e-3

# SSA stress balance
eta = (u.dx(0)**2 + v.dx(1)**2 + u.dx(0) * v.dx(1) + 0.25 *
       (u.dx(1) + v.dx(0))**2 + (L / U_)**2 * 1e-10)**((1 - n) / (2 * n))
R_u = (-gamma * lamda_x.dx(0) * 2 * eta * H *
       (2 * u.dx(0) + v.dx(1)) - gamma * lamda_x.dx(1) * eta * H *
       (u.dx(1) + v.dx(0)) - lamda_x *
       (N + N0) * u - lamda_x * H * B.dx(0) + 0.5 * H**2 *
       lamda_x.dx(0)) * df.dx - 0.5 * H**2 * lamda_x * nhat[0] * df.ds
R_v = (-gamma * lamda_y.dx(0) * eta * H *
       (u.dx(1) + v.dx(0)) - gamma * lamda_y.dx(1) * 2 * eta * H *
示例#12
0
    def __init__(self, mesh, Vh, t_init, t_final, t_1, dt, wind_velocity, gls_stab, Prior):
        self.mesh = mesh
        self.Vh = Vh
        self.t_init = t_init
        self.t_final = t_final
        self.t_1 = t_1
        self.dt = dt
        self.sim_times = np.arange(self.t_init, self.t_final+.5*self.dt, self.dt)
        
        u = dl.TrialFunction(Vh[STATE])
        v = dl.TestFunction(Vh[STATE])
        
        kappa = dl.Constant(.001)
        dt_expr = dl.Constant(self.dt)
        
        r_trial = u + dt_expr*( -dl.div(kappa*dl.nabla_grad(u))+ dl.inner(wind_velocity, dl.nabla_grad(u)) )
        r_test  = v + dt_expr*( -dl.div(kappa*dl.nabla_grad(v))+ dl.inner(wind_velocity, dl.nabla_grad(v)) )

        
        h = dl.CellDiameter(mesh)
        vnorm = dl.sqrt(dl.inner(wind_velocity, wind_velocity))
        if gls_stab:
            tau = ufl.min_value((h*h)/(dl.Constant(2.)*kappa), h/vnorm )
        else:
            tau = dl.Constant(0.)
                            
        self.M = dl.assemble( dl.inner(u,v)*dl.dx )
        self.M_stab = dl.assemble( dl.inner(u, v+tau*r_test)*dl.dx )
        self.Mt_stab = dl.assemble( dl.inner(u+tau*r_trial,v)*dl.dx )
        Nvarf  = (dl.inner(kappa *dl.nabla_grad(u), dl.nabla_grad(v)) + dl.inner(wind_velocity, dl.nabla_grad(u))*v )*dl.dx
        Ntvarf  = (dl.inner(kappa *dl.nabla_grad(v), dl.nabla_grad(u)) + dl.inner(wind_velocity, dl.nabla_grad(v))*u )*dl.dx
        self.N  = dl.assemble( Nvarf )
        self.Nt = dl.assemble(Ntvarf)
        stab = dl.assemble( tau*dl.inner(r_trial, r_test)*dl.dx)
        self.L = self.M + dt*self.N + stab
        self.Lt = self.M + dt*self.Nt + stab
        
        boundaries = dl.MeshFunction("size_t", mesh,1)
        boundaries.set_all(0)

        class InsideBoundary(dl.SubDomain):
            def inside(self,x,on_boundary):
                x_in = x[0] > dl.DOLFIN_EPS and x[0] < 1 - dl.DOLFIN_EPS
                y_in = x[1] > dl.DOLFIN_EPS and x[1] < 1 - dl.DOLFIN_EPS
                return on_boundary and x_in and y_in
            
        Gamma_M = InsideBoundary()
        Gamma_M.mark(boundaries,1)
        ds_marked = dl.Measure("ds", subdomain_data=boundaries)
        
        self.Q = dl.assemble( self.dt*dl.inner(u, v) * ds_marked(1) )

        self.Prior = Prior
        
     
        self.solver  = dl.PETScLUSolver( dl.as_backend_type(self.L) )
        self.solvert = dl.PETScLUSolver( dl.as_backend_type(self.Lt) )
                        
        self.ud = self.generate_vector(STATE)
        self.noise_variance = 0
        # Part of model public API
        self.gauss_newton_approx = False
示例#13
0
    def boundary_components(self, trial, test):
        """
        Generates momentum (stress, velocity) and thermal (heat flux. temperature) boundary components
        of the TVAcoustic weak form equation.

        I expect the usage should be something like:
            bcond = {"noslip" : True, "heat_flux" : 1.}
        """
        pressure, velocity, temperature = trial
        test_pressure, test_velocity, test_temperature = test

        stress_boundary_component = dolf.Constant(0.0) * self.domain.ds()
        temperature_boundary_component = dolf.Constant(0.0) * self.domain.ds()

        for boundary in self.domain.boundary_elements:
            # Step 1. Parse boundary condition data provided by boundary elements.
            # We only accept one boundary condition for stress/velocity and temperature/heat flux.
            temperature_bc = self._pop_boundary_condition(
                boundary.bcond, self.allowed_temperature_bcs
            )
            temperature_bc_type = self.allowed_temperature_bcs[temperature_bc]

            # Step 2. If the boundary condition is one of the Neumann or Robin,
            # we construct necessary boundary integrals in weak form.
            if temperature_bc_type == "Neumann" or temperature_bc_type == "Robin":
                if temperature_bc == "adiabatic":
                    heat_flux = dolf.Constant(0.0)
                elif temperature_bc == "heat_flux":
                    heat_flux = self._parse_dolf_expression(
                        boundary.bcond[temperature_bc]
                    )
                elif temperature_bc == "thermal_accommodation":
                    heat_flux = (
                        -self._parse_dolf_expression(boundary.bcond[temperature_bc])
                        * temperature
                    )
                else:
                    raise TypeError(
                        f"Invalid temperature boundary condition type for {temperature_bc_type} condition."
                    )
                temperature_boundary_component += (
                    -heat_flux
                    * test_temperature
                    * self.domain.ds((boundary.surface_index,))
                )

            # Same for stress / velocity boundary conditions
            stress_bc = self._pop_boundary_condition(
                boundary.bcond, self.allowed_stress_bcs
            )
            stress_bc_type = self.allowed_stress_bcs[stress_bc]

            if stress_bc_type == "Neumann" or stress_bc_type == "Robin":
                if stress_bc == "free":
                    stress = dolf.Constant((0.0,) * self.geometric_dimension)
                elif stress_bc == "force":
                    stress = self._parse_dolf_expression(boundary.bcond[stress_bc])
                elif stress_bc == "impedance":
                    stress = (
                        self._parse_dolf_expression(boundary.bcond[stress_bc])
                        * velocity
                    )
                elif stress_bc == "inhom_impedance":
                    # Impedance term
                    stress = (
                        self._parse_dolf_expression(boundary.bcond[stress_bc][0])
                        * velocity
                    )
                    # Force term
                    normal_force = boundary.bcond[stress_bc][1]
                    normal_force = 0.5 * (
                        normal_force.real + normal_force.imag
                    ) - 0.5j * (normal_force.real - normal_force.imag)
                    stress += self._parse_dolf_expression(normal_force) * self.domain.n
                elif stress_bc == "nozzle_impedance":
                    capacitance = boundary.bcond[stress_bc]["capacitance"]
                    inductance = boundary.bcond[stress_bc]["inductance"]
                    resistance = boundary.bcond[stress_bc]["resistance"]
                    frequency = boundary.bcond[stress_bc]["frequency"]

                    z1 = -1.0 / (frequency * capacitance) - frequency * inductance
                    z1 = self._parse_dolf_expression(z1)

                    z2 = self._parse_dolf_expression(resistance)

                    stress = z1 * dolf.inner(
                        velocity, self.domain.n
                    ) * self.domain.n + z2 * velocity.dx(0).dx(0)
                elif stress_bc == "inhom_nozzle_impedance":
                    inductance = boundary.bcond[stress_bc]["inductance"]
                    resistance = boundary.bcond[stress_bc]["resistance"]
                    frequency = boundary.bcond[stress_bc]["frequency"]

                    z1 = -1.0j * frequency * inductance
                    z1 = self._parse_dolf_expression(z1)

                    z2 = self._parse_dolf_expression(resistance)

                    stress = z1 * velocity + z2 * velocity.dx(0).dx(0)

                    # Force term
                    normal_force = boundary.bcond[stress_bc]["force"]
                    normal_force = 0.5 * (
                        normal_force.real + normal_force.imag
                    ) - 0.5j * (normal_force.real - normal_force.imag)
                    stress += self._parse_dolf_expression(normal_force) * self.domain.n
                elif stress_bc == "shape_impedance":
                    try:
                        shape = boundary.velocity_shape
                    except AttributeError:
                        raise AttributeError(
                            "`shape_impedance` boundary condition requires expected velocity shape. "
                            + "Provide it as a dolfin Expression."
                        )
                    stress = (
                        self._parse_dolf_expression(boundary.bcond[stress_bc])
                        * velocity
                        / shape
                    )
                elif stress_bc == "normal_impedance":
                    stress = (
                        self._parse_dolf_expression(boundary.bcond[stress_bc])
                        * dolf.inner(velocity, self.domain.n)
                        * self.domain.n
                    )
                elif stress_bc == "normal_force":
                    normal_force = boundary.bcond[stress_bc]
                    # normal_force = 0.5 * (
                    #     normal_force.real + normal_force.imag
                    # ) - 0.5j * (normal_force.real - normal_force.imag)
                    stress = self._parse_dolf_expression(normal_force) * self.domain.n
                elif stress_bc == "slip" or stress_bc == "normal_velocity":
                    normal_velocity = (
                        dolf.Constant(0.0)
                        if stress_bc == "slip"
                        else self._parse_dolf_expression(boundary.bcond[stress_bc])
                    )
                    stress = (
                        dolf.Constant(-1.0e2)
                        / dolf.CellDiameter(self.domain.mesh)
                        * (dolf.inner(velocity, self.domain.n) - normal_velocity)
                        * self.domain.n
                    )
                else:
                    raise TypeError(
                        f"Invalid temperature boundary condition type for {stress_bc_type} condition."
                    )
                stress_boundary_component += -dolf.inner(
                    stress, test_velocity
                ) * self.domain.ds((boundary.surface_index,))

        return stress_boundary_component + temperature_boundary_component