def function_arg(self, g): '''Set the value of this boundary condition.''' if isinstance(g, firedrake.Function): if g.function_space() != self.function_space(): raise RuntimeError("%r is defined on incompatible FunctionSpace!" % g) self._function_arg = g elif isinstance(g, ufl.classes.Zero): if g.ufl_shape and g.ufl_shape != self.function_space().ufl_element().value_shape(): raise ValueError(f"Provided boundary value {g} does not match shape of space") # Special case. Scalar zero for direct Function.assign. self._function_arg = ufl.zero() elif isinstance(g, ufl.classes.Expr): if g.ufl_shape != self.function_space().ufl_element().value_shape(): raise RuntimeError(f"Provided boundary value {g} does not match shape of space") try: self._function_arg = firedrake.Function(self.function_space()) self._function_arg_update = firedrake.Interpolator(g, self._function_arg).interpolate except (NotImplementedError, AttributeError): # Element doesn't implement interpolation self._function_arg = firedrake.Function(self.function_space()).project(g) self._function_arg_update = firedrake.Projector(g, self._function_arg).project else: try: g = as_ufl(g) self._function_arg = g except UFLException: try: # Recurse to handle this through interpolation. self.function_arg = as_ufl(as_tensor(g)) except UFLException: raise ValueError(f"{g} is not a valid DirichletBC expression")
def modified_terminal(self, o): mt = analyse_modified_terminal(o) terminal = mt.terminal if not isinstance(terminal, Coefficient): # Only split coefficients return o if type(terminal.ufl_element()) != MixedElement: # Only split mixed coefficients return o # Reference value expected assert mt.reference_value # Derivative indices beta = indices(mt.local_derivatives) components = [] for subcoeff in self._split[terminal]: # Apply terminal modifiers onto the subcoefficient component = construct_modified_terminal(mt, subcoeff) # Collect components of the subcoefficient for alpha in numpy.ndindex(subcoeff.ufl_element().reference_value_shape()): # New modified terminal: component[alpha + beta] components.append(component[alpha + beta]) # Repack derivative indices to shape c, = indices(1) return ComponentTensor(as_tensor(components)[c], MultiIndex((c,) + beta))
def function_arg(self, g): '''Set the value of this boundary condition.''' if isinstance(g, function.Function) and g.function_space() != self._function_space: raise RuntimeError("%r is defined on incompatible FunctionSpace!" % g) if not isinstance(g, expression.Expression): try: # Bare constant? as_ufl(g) except UFLException: try: # List of bare constants? Convert to UFL expression g = as_ufl(as_tensor(g)) if g.ufl_shape != self._function_space.shape: raise ValueError("%r doesn't match the shape of the function space." % (g,)) except UFLException: raise ValueError("%r is not a valid DirichletBC expression" % (g,)) if isinstance(g, expression.Expression) or has_type(as_ufl(g), SpatialCoordinate): if isinstance(g, expression.Expression): self._expression_state = g._state try: g = function.Function(self._function_space).interpolate(g) # Not a point evaluation space, need to project onto V except NotImplementedError: g = projection.project(g, self._function_space) self._function_arg = g self._currently_zeroed = False
def dtheta_dC(self, u_, p_, ivar, theta_old_, thres, dt): theta_ = ivar["theta"] dFg_dtheta = self.F_g(theta_,tang=True) ktheta = self.res_dtheta_growth(u_, p_, ivar, theta_old_, thres, dt, 'ktheta') K_growth = self.res_dtheta_growth(u_, p_, ivar, theta_old_, thres, dt, 'tang') i, j, k, l = indices(4) if self.growth_trig == 'volstress': Cmat = self.S(u_,p_,ivar,tang=True) # TeX: \frac{\partial \vartheta}{\partial \boldsymbol{C}} = \frac{k(\vartheta) \Delta t}{\frac{\partial r}{\partial \vartheta}}\left(\boldsymbol{S} + \boldsymbol{C} : \frac{1}{2} \check{\mathbb{C}}\right) tangdC = (ktheta*dt/K_growth) * (self.S(u_,p_,ivar=ivar) + 0.5*as_tensor(self.kin.C(u_)[i,j]*Cmat[i,j,k,l], (k,l))) elif self.growth_trig == 'fibstretch': # TeX: \frac{\partial \vartheta}{\partial \boldsymbol{C}} = \frac{k(\vartheta) \Delta t}{\frac{\partial r}{\partial \vartheta}} \frac{1}{2\lambda_{f}} \boldsymbol{f}_{0}\otimes \boldsymbol{f}_{0} tangdC = (ktheta*dt/K_growth) * outer(self.kin.fib_funcs[0],self.kin.fib_funcs[0])/(2.*self.kin.fibstretch(u_,self.kin.fib_funcs[0])) else: raise NameError("Unkown growth_trig!") return tangdC
def Cgrowth(self, u_, p_, ivar, theta_old_, thres, dt): theta_ = ivar["theta"] dFg_dtheta = self.F_g(theta_,tang=True) i, j, k, l = indices(4) dtheta_dC_ = self.dtheta_dC(u_, p_, ivar, theta_old_, thres, dt) dS_dFg_ = self.dS_dFg(u_, p_, ivar, theta_old_, dt) dS_dFg_times_dFg_dtheta = as_tensor(dS_dFg_[i,j,k,l]*dFg_dtheta[k,l], (i,j)) Cgrowth = 2.*as_tensor(dS_dFg_times_dFg_dtheta[i,j]*dtheta_dC_[k,l], (i,j,k,l)) return Cgrowth
def reshape(expr, shape): if numpy.prod(expr.ufl_shape, dtype=int) != numpy.prod(shape, dtype=int): raise ValueError(f"Can't reshape from {expr.ufl_shape} to {shape}") if shape == expr.ufl_shape: return expr if shape == (): return expr else: expr = numpy.asarray([expr[i] for i in numpy.ndindex(expr.ufl_shape)]) return ufl.as_tensor(expr.reshape(shape))
def stf3d3(rank3_3d): r""" Return the symmetric and trace-free part of a 3D 3-tensor. Return the symmetric and trace-free part of a 3D 3-tensor. (dev(sym(.))) Returns the STF part :math:`A_{\langle i j k\rangle}` of a rank-3 tensor :math:`A \in \mathbb{R}^{3 \times 3 \times 3}` [TOR2018]_. .. math:: A_{\langle i j k\rangle}=A_{(i j k)}-\frac{1}{5}\left[A_{(i l l)} \delta_{j k}+A_{(l j l)} \delta_{i k}+A_{(l l k)} \delta_{i j}\right] A gradient :math:`\frac{\partial S_{\langle i j}}{\partial x_{k \rangle}}` of a symmetric 2-tensor :math:`S \in \mathbb{R}^{3 \times 3}` has the deviator [STR2005]_: .. math:: \frac{\partial S_{\langle i j}}{\partial x_{k \rangle}} =& \frac{1}{3}\left( \frac{\partial S_{i j}}{\partial x_{k}} +\frac{\partial S_{i k}}{\partial x_{j}} +\frac{\partial S_{j k}}{\partial x_{i}} \right) -\frac{1}{15} \biggl[ \left( \frac{\partial S_{i r}}{\partial x_{r}} +\frac{\partial S_{i r}}{\partial x_{r}} +\frac{\partial S_{r r}}{\partial x_{i}} \right) \delta_{j k} \\ &+ \left( \frac{\partial S_{j r}}{\partial x_{r}} +\frac{\partial S_{j r}}{\partial x_{r}} +\frac{\partial S_{r r}}{\partial x_{j}} \right) \delta_{i k} +\left( \frac{\partial S_{k r}}{\partial x_{r}} +\frac{\partial S_{k r}}{\partial x_{r}} +\frac{\partial S_{r r}}{\partial x_{k}} \right) \delta_{i j} \biggr] """ i, j, k, L = ufl.indices(4) delta = df.Identity(3) sym_ijk = sym3d3(rank3_3d)[i, j, k] traces_ijk = 1 / 5 * (+sym3d3(rank3_3d)[i, L, L] * delta[j, k] + sym3d3(rank3_3d)[L, j, L] * delta[i, k] + sym3d3(rank3_3d)[L, L, k] * delta[i, j]) tracefree_ijk = sym_ijk - traces_ijk return ufl.as_tensor(tracefree_ijk, (i, j, k))
def Cremod(self, u_, p_, ivar, theta_old_, thres, dt): theta_ = ivar["theta"] i, j, k, l = indices(4) dphi_dtheta_ = self.phi_remod(theta_,tang=True) dtheta_dC_ = self.dtheta_dC(u_, p_, ivar, theta_old_, thres, dt) Cremod = 2.*dphi_dtheta_ * as_tensor(dtheta_dC_[i,j]*(self.stress_remod - self.stress_base)[k,l], (i,j,k,l)) return Cremod
def sym3d3(rank3_3d): r""" Return the symmetric part of a 3D 3-tensor. Returns the symmetric part :math:`A_{(i j k)}` of a 3D rank-3 tensor :math:`A \in \mathbb{R}^{3 \times 3 \times 3}` [STR2005]_ [TOR2018]_. .. math:: A_{(i j k)}=\frac{1}{6}\left( A_{i j k}+A_{i k j}+A_{j i k}+A_{j k i}+A_{k i j}+A_{k j i} \right) """ i, j, k = ufl.indices(3) symm_ijk = 1 / 6 * ( # All permutations +rank3_3d[i, j, k] + rank3_3d[i, k, j] + rank3_3d[j, i, k] + rank3_3d[j, k, i] + rank3_3d[k, i, j] + rank3_3d[k, j, i]) return ufl.as_tensor(symm_ijk, (i, j, k))
def div3d3(rank3_3d): r""" Return the 3D divergence of a 3-tensor. Return the 3D divergence of a 3-tensor as .. math:: {(\mathrm{div}(m))}_{ij} = \frac{\partial m_{ijk}}{\partial x_k} Compare with [SCH2009]_ (p. 92). .. [SCH2009] Heinz Schade, Klaus Neemann (2009). “Tensoranalysis”. 2. überarbeitete Auflage. """ i, j, k = ufl.indices(3) div_ij = rank3_3d[i, j, 0].dx(0) + rank3_3d[i, j, 1].dx(1) return ufl.as_tensor(div_ij, (i, j))
def __init__(self, angular_quad, L): from transport_data import angular_tensors_ext_module i,j,k1,k2,p,q = ufl.indices(6) tensors = angular_tensors_ext_module.AngularTensors(angular_quad, L) self.Y = ufl.as_tensor( numpy.reshape(tensors.Y(), tensors.shape_Y()) ) self.Q = ufl.as_tensor( numpy.reshape(tensors.Q(), tensors.shape_Q()) ) self.QT = ufl.transpose(self.Q) self.Qt = ufl.as_tensor( numpy.reshape(tensors.Qt(), tensors.shape_Qt()) ) self.QtT = ufl.as_tensor( self.Qt[k1,p,i], (p,i,k1) ) self.G = ufl.as_tensor( numpy.reshape(tensors.G(), tensors.shape_G()) ) self.T = ufl.as_tensor( numpy.reshape(tensors.T(), tensors.shape_T()) ) self.Wp = ufl.as_vector( angular_quad.get_pw() ) self.W = ufl.diag(self.Wp)
def dS_dFg(self, u_, p_, ivar, theta_old_, dt): theta_ = ivar["theta"] Cmat = self.S(u_, p_, ivar, tang=True) i, j, k, l, m, n = indices(6) # elastic material tangent (living in intermediate growth configuration) Cmat_e = dot( self.F_g(theta_), dot(self.F_g(theta_), dot(Cmat, dot(self.F_g(theta_).T, self.F_g(theta_).T)))) Fginv_outertop_S = as_tensor( inv(self.F_g(theta_))[i, k] * self.S(u_, p_, ivar=ivar)[j, l], (i, j, k, l)) S_outerbot_Fginv = as_tensor( self.S(u_, p_, ivar=ivar)[i, l] * inv(self.F_g(theta_))[j, k], (i, j, k, l)) Fginv_outertop_Fginv = as_tensor( inv(self.F_g(theta_))[i, k] * inv(self.F_g(theta_))[j, l], (i, j, k, l)) FginvT_outertop_Ce = as_tensor( inv(self.F_g(theta_)).T[i, k] * self.C_e(self.kin.C(u_), theta_)[j, l], (i, j, k, l)) Ce_outerbot_FginvT = as_tensor( self.C_e(self.kin.C(u_), theta_)[i, l] * inv(self.F_g(theta_)).T[j, k], (i, j, k, l)) Cmat_e_with_C_e = 0.5 * as_tensor( Cmat_e[i, j, m, n] * (FginvT_outertop_Ce[m, n, k, l] + Ce_outerbot_FginvT[m, n, k, l]), (i, j, k, l)) Fginv_outertop_Fginv_with_Cmat_e_with_C_e = as_tensor( Fginv_outertop_Fginv[i, j, m, n] * Cmat_e_with_C_e[m, n, k, l], (i, j, k, l)) return -(Fginv_outertop_S + S_outerbot_Fginv) - Fginv_outertop_Fginv_with_Cmat_e_with_C_e
def test_apply_algebra_lowering_complex(self): cell = triangle element = FiniteElement("Lagrange", cell, 1) v = TestFunction(element) u = TrialFunction(element) gv = grad(v) gu = grad(u) a = dot(gu, gv) b = inner(gv, gu) c = outer(gu, gv) lowered_a = apply_algebra_lowering(a) lowered_b = apply_algebra_lowering(b) lowered_c = apply_algebra_lowering(c) lowered_a_index = lowered_a.index() lowered_b_index = lowered_b.index() lowered_c_indices = lowered_c.indices() assert lowered_a == gu[lowered_a_index] * gv[lowered_a_index] assert lowered_b == gv[lowered_b_index] * conj(gu[lowered_b_index]) assert lowered_c == as_tensor(conj(gu[lowered_c_indices[0]]) * gv[lowered_c_indices[1]], (lowered_c_indices[0],) + (lowered_c_indices[1],))
def apply_mapping(expression, mapping, domain): """ This applies the appropriate transformation to the given expression for interpolation to a specific element, according to the manner in which it maps from the reference cell. The following is borrowed from the UFC documentation: Let g be a field defined on a physical domain T with physical coordinates x. Let T_0 be a reference domain with coordinates X. Assume that F: T_0 -> T such that x = F(X) Let J be the Jacobian of F, i.e J = dx/dX and let K denote the inverse of the Jacobian K = J^{-1}. Then we (currently) have the following four types of mappings: 'affine' mapping for g: G(X) = g(x) For vector fields g: 'contravariant piola' mapping for g: G(X) = det(J) K g(x) i.e G_i(X) = det(J) K_ij g_j(x) 'covariant piola' mapping for g: G(X) = J^T g(x) i.e G_i(X) = J^T_ij g(x) = J_ji g_j(x) 'double covariant piola' mapping for g: G(X) = J^T g(x) J i.e. G_il(X) = J_ji g_jk(x) J_kl 'double contravariant piola' mapping for g: G(X) = det(J)^2 K g(x) K^T i.e. G_il(X)=(detJ)^2 K_ij g_jk K_lk If 'contravariant piola' or 'covariant piola' are applied to a matrix-valued function, the appropriate mappings are applied row-by-row. :arg expression: UFL expression :arg mapping: a string indicating the mapping to apply """ mesh = expression.ufl_domain() if mesh is None: mesh = domain if domain is not None and mesh != domain: raise NotImplementedError("Multiple domains not supported") rank = len(expression.ufl_shape) if mapping == "affine": return expression elif mapping == "covariant piola": J = Jacobian(mesh) *i, j, k = indices(len(expression.ufl_shape) + 1) expression = Indexed(expression, MultiIndex((*i, k))) return as_tensor(J.T[j, k] * expression, (*i, j)) elif mapping == "contravariant piola": K = JacobianInverse(mesh) detJ = JacobianDeterminant(mesh) *i, j, k = indices(len(expression.ufl_shape) + 1) expression = Indexed(expression, MultiIndex((*i, k))) return as_tensor(detJ * K[j, k] * expression, (*i, j)) elif mapping == "double covariant piola" and rank == 2: J = Jacobian(mesh) return J.T * expression * J elif mapping == "double contravariant piola" and rank == 2: K = JacobianInverse(mesh) detJ = JacobianDeterminant(mesh) return (detJ)**2 * K * expression * K.T else: raise NotImplementedError("Don't know how to handle mapping type %s for expression of rank %d" % (mapping, rank))
apply_lifting(b, [a], bcs=[bcs]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) set_bc(b, bcs) # Solve solver = PETSc.KSP().create(MPI.COMM_WORLD) PETSc.Options()["ksp_type"] = "preonly" PETSc.Options()["pc_type"] = "lu" PETSc.Options()["pc_factor_mat_solver_type"] = "mumps" solver.setFromOptions() solver.setOperators(A) x_h = Function(V) solver.solve(b, x_h.vector) x_h.x.scatter_forward() sigma_h = S(ufl.as_tensor([[x_h[0], x_h[1]], [x_h[2], x_h[3]]])) # Viz xvfb.start_xvfb(wait=0.05) pyvista.OFF_SCREEN = True plotter = pyvista.Plotter( title="Displacement", window_size=[1600, 600], shape=(1, 1), ) (_S, _w) = x_h.split() _plt = plot_scalar(_w, plotter, subplot=(0, 0)) # _plt = plot_vector(u, plotter, subplot=(0, 1))
def _make_metric_tensor(self, specification: Optional[str]) \ -> ufl.tensors.ListTensor: """Assemble metric tensor. Parameters ---------- specification : str, optional String containing Python code to define the entries of the metric tensor. By default, it is taken to be the identity matrix. The code is valid Python code for populating a dictionary `g` indexed by tuples. The entries of the dictionary can be either constants or strings of valid UFL code. See also the documentation for fenics.functions.expression.Expression. Examples -------- The string "g[0, 0] = 'pow(sin(x[1]), 2)'; g[1, 1] = 1.0" gives the metric tensor for the unit sphere. Note that the string assigned to g[0, 0] is C++ code whereas the assignments themselves are valid Python code. """ def zero_matrix(dimension): return [[0 for _ in range(dimension)] for _ in range(dimension)] def get_dimension(metric_tensor_dict): pairs = metric_tensor_dict.keys() return max([x for pair in pairs for x in pair]) + 1 def eval_metric_tensor(spec): metric_tensor_dict = {} locals_dict = {'g': metric_tensor_dict} exec(spec, None, locals_dict) return metric_tensor_dict vector_space = self.vector_space dim = vector_space.ufl_domain().geometric_dimension() G = zero_matrix(dim) if specification: g = eval_metric_tensor(specification) dim_g = get_dimension(g) if dim != dim_g: err_msg = ( 'The dimension of the metric tensor ({}) does not ' 'match the dimension of the vector space ({})'.format( dim_g, dim)) raise LaplaceBeltramiEigensolverError(err_msg) degree = vector_space.ufl_element().degree() for key, val in g.items(): i, j = key if isinstance(val, str): expr = fenics.Expression(val, degree=degree) expr = fenics.interpolate(expr, vector_space) else: expr = val G[i][j], G[j][i] = expr, expr else: for i in range(dim): G[i][i] = 1.0 return ufl.as_tensor(G)
def test_biharmonic(): """Manufactured biharmonic problem. Solved using rotated Regge mixed finite element method. This is equivalent to the Hellan-Herrmann-Johnson (HHJ) finite element method in two-dimensions.""" mesh = RectangleMesh(MPI.COMM_WORLD, [np.array([0.0, 0.0, 0.0]), np.array([1.0, 1.0, 0.0])], [32, 32], CellType.triangle) element = ufl.MixedElement([ufl.FiniteElement("Regge", ufl.triangle, 1), ufl.FiniteElement("Lagrange", ufl.triangle, 2)]) V = FunctionSpace(mesh, element) sigma, u = ufl.TrialFunctions(V) tau, v = ufl.TestFunctions(V) x = ufl.SpatialCoordinate(mesh) u_exact = ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) * ufl.sin(ufl.pi * x[1]) f_exact = div(grad(div(grad(u_exact)))) sigma_exact = grad(grad(u_exact)) # sigma and tau are tangential-tangential continuous according to the # H(curl curl) continuity of the Regge space. However, for the biharmonic # problem we require normal-normal continuity H (div div). Theorem 4.2 of # Lizao Li's PhD thesis shows that the latter space can be constructed by # the former through the action of the operator S: def S(tau): return tau - ufl.Identity(2) * ufl.tr(tau) sigma_S = S(sigma) tau_S = S(tau) # Discrete duality inner product eq. 4.5 Lizao Li's PhD thesis def b(tau_S, v): n = FacetNormal(mesh) return inner(tau_S, grad(grad(v))) * dx \ - ufl.dot(ufl.dot(tau_S('+'), n('+')), n('+')) * jump(grad(v), n) * dS \ - ufl.dot(ufl.dot(tau_S, n), n) * ufl.dot(grad(v), n) * ds # Non-symmetric formulation a = inner(sigma_S, tau_S) * dx - b(tau_S, u) + b(sigma_S, v) L = inner(f_exact, v) * dx V_1 = V.sub(1).collapse() zero_u = Function(V_1) with zero_u.vector.localForm() as zero_u_local: zero_u_local.set(0.0) # Strong (Dirichlet) boundary condition boundary_facets = locate_entities_boundary( mesh, mesh.topology.dim - 1, lambda x: np.full(x.shape[1], True, dtype=bool)) boundary_dofs = locate_dofs_topological((V.sub(1), V_1), mesh.topology.dim - 1, boundary_facets) bcs = [DirichletBC(zero_u, boundary_dofs, V.sub(1))] A = assemble_matrix(a, bcs=bcs) A.assemble() b = assemble_vector(L) apply_lifting(b, [a], [bcs]) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) # Solve solver = PETSc.KSP().create(MPI.COMM_WORLD) PETSc.Options()["ksp_type"] = "preonly" PETSc.Options()["pc_type"] = "lu" # PETSc.Options()["pc_factor_mat_solver_type"] = "mumps" solver.setFromOptions() solver.setOperators(A) x_h = Function(V) solver.solve(b, x_h.vector) x_h.vector.ghostUpdate(addv=PETSc.InsertMode.INSERT, mode=PETSc.ScatterMode.FORWARD) # Recall that x_h has flattened indices. u_error_numerator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(u_exact - x_h[4], u_exact - x_h[4]) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) u_error_denominator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(u_exact, u_exact) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) assert(np.absolute(u_error_numerator / u_error_denominator) < 0.05) # Reconstruct tensor from flattened indices. # Apply inverse transform. In 2D we have S^{-1} = S. sigma_h = S(ufl.as_tensor([[x_h[0], x_h[1]], [x_h[2], x_h[3]]])) sigma_error_numerator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(sigma_exact - sigma_h, sigma_exact - sigma_h) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) sigma_error_denominator = np.sqrt(mesh.mpi_comm().allreduce(assemble_scalar( inner(sigma_exact, sigma_exact) * dx(mesh, metadata={"quadrature_degree": 5})), op=MPI.SUM)) assert(np.absolute(sigma_error_numerator / sigma_error_denominator) < 0.005)
def forward(mu_expression, lmbda_expression, rho, Lx=10, Ly=10, t_end=1, omega_p=5, amplitude=5000, center=0, target=False): Lpml = Lx / 10 #c_p = cp(mu.vector(), lmbda.vector(), rho) max_velocity = 200 #c_p.max() stable_hx = stable_dx(max_velocity, omega_p) nx = int(Lx / stable_hx) + 1 #nx = max(nx, 60) ny = int(Ly * nx / Lx) + 1 mesh = mesh_generator(Lx, Ly, Lpml, nx, ny) used_hx = Lx / nx dt = stable_dt(used_hx, max_velocity) cfl_ct = cfl_constant(max_velocity, dt, used_hx) print(used_hx, stable_hx) print(cfl_ct) #time.sleep(10) PE = FunctionSpace(mesh, "DG", 0) mu = interpolate(mu_expression, PE) lmbda = interpolate(lmbda_expression, PE) m = 2 R = 10e-8 t = 0.0 gamma = 0.50 beta = 0.25 ff = MeshFunction("size_t", mesh, mesh.geometry().dim() - 1) Dirichlet(Lx, Ly, Lpml).mark(ff, 1) # Create function spaces VE = VectorElement("CG", mesh.ufl_cell(), 1, dim=2) TE = TensorElement("DG", mesh.ufl_cell(), 0, shape=(2, 2), symmetry=True) W = FunctionSpace(mesh, MixedElement([VE, TE])) F = FunctionSpace(mesh, "CG", 2) V = W.sub(0).collapse() M = W.sub(1).collapse() alpha_0 = Alpha_0(m, stable_hx, R, Lpml) alpha_1 = Alpha_1(alpha_0, Lx, Lpml, degree=2) alpha_2 = Alpha_2(alpha_0, Ly, Lpml, degree=2) beta_0 = Beta_0(m, max_velocity, R, Lpml) beta_1 = Beta_1(beta_0, Lx, Lpml, degree=2) beta_2 = Beta_2(beta_0, Ly, Lpml, degree=2) alpha_1 = interpolate(alpha_1, F) alpha_2 = interpolate(alpha_2, F) beta_1 = interpolate(beta_1, F) beta_2 = interpolate(beta_2, F) a_ = alpha_1 * alpha_2 b_ = alpha_1 * beta_2 + alpha_2 * beta_1 c_ = beta_1 * beta_2 Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]]) Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]]) a_ = alpha_1 * alpha_2 b_ = alpha_1 * beta_2 + alpha_2 * beta_1 c_ = beta_1 * beta_2 Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]]) Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]]) # Set up boundary condition bc = DirichletBC(W.sub(0), Constant(("0.0", "0.0")), ff, 1) # Create measure for the source term dx = Measure("dx", domain=mesh) ds = Measure("ds", domain=mesh, subdomain_data=ff) # Set up initial values u0 = Function(V) u0.set_allow_extrapolation(True) v0 = Function(V) a0 = Function(V) U0 = Function(M) V0 = Function(M) A0 = Function(M) # Test and trial functions (u, S) = TrialFunctions(W) (w, T) = TestFunctions(W) g = ModifiedRickerPulse(0, omega_p, amplitude, center) F = rho * inner(a_ * N_ddot(u, u0, a0, v0, dt, beta) \ + b_ * N_dot(u, u0, v0, a0, dt, beta, gamma) + c_ * u, w) * dx \ + inner(N_dot(S, U0, V0, A0, dt, beta, gamma).T * Lambda_e + S.T * Lambda_p, grad(w)) * dx \ - inner(g, w) * ds \ + inner(compliance(a_ * N_ddot(S, U0, A0, V0, dt, beta) + b_ * N_dot(S, U0, V0, A0, dt, beta, gamma) + c_ * S, u, mu, lmbda), T) * dx \ - 0.5 * inner(grad(u) * Lambda_p + Lambda_p * grad(u).T + grad(N_dot(u, u0, v0, a0, dt, beta, gamma)) * Lambda_e \ + Lambda_e * grad(N_dot(u, u0, v0, a0, dt, beta, gamma)).T, T) * dx \ a, L = lhs(F), rhs(F) # Assemble rhs (once) A = assemble(a) # Create GMRES Krylov solver solver = KrylovSolver(A, "gmres") # Create solution function S = Function(W) if target: xdmffile_u = XDMFFile("inversion_temporal_file/target/u.xdmf") pvd = File("inversion_temporal_file/target/u.pvd") xdmffile_u.write(u0, t) timeseries_u = TimeSeries( "inversion_temporal_file/target/u_timeseries") else: xdmffile_u = XDMFFile("inversion_temporal_file/obs/u.xdmf") xdmffile_u.write(u0, t) timeseries_u = TimeSeries("inversion_temporal_file/obs/u_timeseries") rec_counter = 0 while t < t_end - 0.5 * dt: t += float(dt) if rec_counter % 10 == 0: print( '\n\rtime: {:.3f} (Progress: {:.2f}%)'.format( t, 100 * t / t_end), ) g.t = t # Assemble rhs and apply boundary condition b = assemble(L) bc.apply(A, b) # Compute solution solver.solve(S.vector(), b) (u, U) = S.split(True) # Update previous time step update(u, u0, v0, a0, beta, gamma, dt) update(U, U0, V0, A0, beta, gamma, dt) xdmffile_u.write(u, t) pvd << (u, t) timeseries_u.store(u.vector(), t) energy = inner(u, u) * dx E = assemble(energy) print("E = ", E) print(u.vector().max())
alpha_2 = alpha_2(alpha_0, Ly, Lpml, degree=2) beta_0 = beta_0(m, V_r, R, Lpml) beta_1 = beta_1(beta_0, Lx, Lpml, degree=2) beta_2 = beta_2(beta_0, Ly, Lpml, degree=2) alpha_1 = interpolate(alpha_1, F) alpha_2 = interpolate(alpha_2, F) beta_1 = interpolate(beta_1, F) beta_2 = interpolate(beta_2, F) a_ = alpha_1 * alpha_2 b_ = alpha_1 * beta_2 + alpha_2 * beta_1 c_ = beta_1 * beta_2 Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]]) Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]]) a_ = alpha_1 * alpha_2 b_ = alpha_1 * beta_2 + alpha_2 * beta_1 c_ = beta_1 * beta_2 Lambda_e = as_tensor([[alpha_2, 0], [0, alpha_1]]) Lambda_p = as_tensor([[beta_2, 0], [0, beta_1]]) # Set up boundary condition bc = DirichletBC(W.sub(0), Constant(("0.0", "0.0")), ff, 1) # Create measure for the source term ds = Measure("ds", domain=mesh, subdomain_data=ff)
def constant(self, a): if a.value.shape == (): return float(a.value) else: return ufl.as_tensor(a.value)