def SetupUnitMeshHelper(mesh, V=None, Vc=None): if V is None: V = df.FunctionSpace(mesh, 'CG', 1) if Vc is None: Vc = df.FunctionSpace(mesh, 'DG', 0) boundaries = dict() boundaries['left'] = df.CompiledSubDomain("near(x[0], 0.0) && on_boundary") boundaries['bottom'] = df.CompiledSubDomain( "near(x[1], 0.0) && on_boundary") boundaries['top'] = df.CompiledSubDomain("near(x[1], 1.0) && on_boundary") boundaries['right'] = df.CompiledSubDomain( "near(x[0], 1.0) && on_boundary") boundarymarkers = df.MeshFunction('size_t', mesh, mesh.topology().dim() - 1, 0) boundarymarkers.set_all(0) domainmarkers = df.MeshFunction('size_t', mesh, mesh.topology().dim(), 0) boundaries['left'].mark(boundarymarkers, 1) boundaries['bottom'].mark(boundarymarkers, 2) boundaries['right'].mark(boundarymarkers, 3) boundaries['top'].mark(boundarymarkers, 4) ds = df.Measure('ds', domain=mesh, subdomain_data=boundarymarkers) dx = df.Measure('dx', domain=mesh, subdomain_data=domainmarkers) return boundaries, boundarymarkers, domainmarkers, dx, ds, V, Vc
def load_2d_muscle_geo(filename='../geo/muscle_2d.xml', L0=1e-2): mesh = fe.Mesh(filename) coords = mesh.coordinates() coords *= L0 mesh.bounding_box_tree().build(mesh) # Define Boundaries bottom = fe.CompiledSubDomain("near(x[1], side, 0.01) && on_boundary", side=-20.0 * L0) top = fe.CompiledSubDomain("near(x[1], side, 0.01) && on_boundary", side=20.0 * L0) # Initialize mesh function for boundary domains boundaries = fe.MeshFunction('size_t', mesh, 2) boundaries.set_all(0) bottom.mark(boundaries, 1) top.mark(boundaries, 2) # Define new measures associated with the interior domains and # exterior boundaries dx = fe.Measure('dx', domain=mesh) ds = fe.Measure('ds', domain=mesh, subdomain_data=boundaries) return mesh, dx, ds, {"top": top, "bottom": bottom}
#fe.parameters["form_compiler"]["quadrature_degree"] = 5 # Create mesh and define function space n = 20 mesh = fe.UnitCubeMesh(n, n, n) # Init function spaces element_3 = fe.VectorElement("P", mesh.ufl_cell(), 1) element = fe.FiniteElement("P", mesh.ufl_cell(), 2) # Mixed function space TH = element_3 * element V = fe.FunctionSpace(mesh, TH) # Define Boundaries left = fe.CompiledSubDomain("near(x[0], side) && on_boundary", side=0.0) right = fe.CompiledSubDomain("near(x[0], side) && on_boundary", side=1.0) # Define Dirichlet boundary (x = 0 or x = 1) u_left = fe.Expression(("0.0", "0.0", "0.0"), element=element_3) u_right = fe.Expression(("0.0", "0.0", "0.0"), element=element_3) p_left = fe.Constant(0.) # Define acting force b = fe.Constant((0.0, 0.0, 0.0)) # Body force per unit volume t_bar = fe.Constant((0.0, 0.0, 0.0)) # Traction force on the boundary # Define test and trial functions w = fe.Function(V) # most recently computed solution (u, p) = fe.split(w) (v, q) = fe.TestFunctions(V)
def regular_box_mesh(n=10, S_x=0.0, S_y=0.0, S_z=None, E_x=1.0, E_y=1.0, E_z=None): r"""Creates a mesh corresponding to a rectangle or cube. This function creates a uniform mesh of either a rectangle or a cube, with specified start (``S_``) and end points (``E_``). The resulting mesh uses ``n`` elements along the shortest direction and accordingly many along the longer ones. The resulting domain is .. math:: \begin{alignedat}{2} &[S_x, E_x] \times [S_y, E_y] \quad &&\text{ in } 2D, \\ &[S_x, E_x] \times [S_y, E_y] \times [S_z, E_z] \quad &&\text{ in } 3D. \end{alignedat} The boundary markers are ordered as follows: - 1 corresponds to :math:`x=S_x`. - 2 corresponds to :math:`x=E_x`. - 3 corresponds to :math:`y=S_y`. - 4 corresponds to :math:`y=E_y`. - 5 corresponds to :math:`z=S_z` (only in 3D). - 6 corresponds to :math:`z=E_z` (only in 3D). Parameters ---------- n : int Number of elements in the shortest coordinate direction. S_x : float Start of the x-interval. S_y : float Start of the y-interval. S_z : float or None, optional Start of the z-interval, mesh is 2D if this is ``None`` (default is ``None``). E_x : float End of the x-interval. E_y : float End of the y-interval. E_z : float or None, optional End of the z-interval, mesh is 2D if this is ``None`` (default is ``None``). Returns ------- mesh : dolfin.cpp.mesh.Mesh The computational mesh. subdomains : dolfin.cpp.mesh.MeshFunctionSizet A MeshFunction object containing the subdomains. boundaries : dolfin.cpp.mesh.MeshFunctionSizet A MeshFunction object containing the boundaries. dx : ufl.measure.Measure The volume measure of the mesh corresponding to subdomains. ds : ufl.measure.Measure The surface measure of the mesh corresponding to boundaries. dS : ufl.measure.Measure The interior facet measure of the mesh corresponding to boundaries. """ n = int(n) if not n > 0: raise InputError('cashocs.geometry.regular_box_mesh', 'n', 'This needs to be positive.') if not S_x < E_x: raise InputError( 'cashocs.geometry.regular_box_mesh', 'S_x', 'Incorrect input for the x-coordinate. S_x has to be smaller than E_x.' ) if not S_y < E_y: raise InputError( 'cashocs.geometry.regular_box_mesh', 'S_y', 'Incorrect input for the y-coordinate. S_y has to be smaller than E_y.' ) if not ((S_z is None and E_z is None) or (S_z < E_z)): raise InputError( 'cashocs.geometry.regular_box_mesh', 'S_z', 'Incorrect input for the z-coordinate. S_z has to be smaller than E_z, or only one of them is specified.' ) if S_z is None: lx = E_x - S_x ly = E_y - S_y sizes = [lx, ly] dim = 2 else: lx = E_x - S_x ly = E_y - S_y lz = E_z - S_z sizes = [lx, ly, lz] dim = 3 size_min = np.min(sizes) num_points = [int(np.round(length / size_min * n)) for length in sizes] if S_z is None: mesh = fenics.RectangleMesh(fenics.Point(S_x, S_y), fenics.Point(E_x, E_y), num_points[0], num_points[1]) else: mesh = fenics.BoxMesh(fenics.Point(S_x, S_y, S_z), fenics.Point(E_x, E_y, E_z), num_points[0], num_points[1], num_points[2]) subdomains = fenics.MeshFunction('size_t', mesh, dim=dim) boundaries = fenics.MeshFunction('size_t', mesh, dim=dim - 1) x_min = fenics.CompiledSubDomain('on_boundary && near(x[0], sx, tol)', tol=fenics.DOLFIN_EPS, sx=S_x) x_max = fenics.CompiledSubDomain('on_boundary && near(x[0], ex, tol)', tol=fenics.DOLFIN_EPS, ex=E_x) x_min.mark(boundaries, 1) x_max.mark(boundaries, 2) y_min = fenics.CompiledSubDomain('on_boundary && near(x[1], sy, tol)', tol=fenics.DOLFIN_EPS, sy=S_y) y_max = fenics.CompiledSubDomain('on_boundary && near(x[1], ey, tol)', tol=fenics.DOLFIN_EPS, ey=E_y) y_min.mark(boundaries, 3) y_max.mark(boundaries, 4) if S_z is not None: z_min = fenics.CompiledSubDomain('on_boundary && near(x[2], sz, tol)', tol=fenics.DOLFIN_EPS, sz=S_z) z_max = fenics.CompiledSubDomain('on_boundary && near(x[2], ez, tol)', tol=fenics.DOLFIN_EPS, ez=E_z) z_min.mark(boundaries, 5) z_max.mark(boundaries, 6) dx = fenics.Measure('dx', mesh, subdomain_data=subdomains) ds = fenics.Measure('ds', mesh, subdomain_data=boundaries) dS = fenics.Measure('dS', mesh) return mesh, subdomains, boundaries, dx, ds, dS
def regular_mesh(n=10, L_x=1.0, L_y=1.0, L_z=None): r"""Creates a mesh corresponding to a rectangle or cube. This function creates a uniform mesh of either a rectangle or a cube, starting at the origin and having length specified in ``L_x``, ``L_y``, and ``L_z``. The resulting mesh uses ``n`` elements along the shortest direction and accordingly many along the longer ones. The resulting domain is .. math:: \begin{alignedat}{2} &[0, L_x] \times [0, L_y] \quad &&\text{ in } 2D, \\ &[0, L_x] \times [0, L_y] \times [0, L_z] \quad &&\text{ in } 3D. \end{alignedat} The boundary markers are ordered as follows: - 1 corresponds to :math:`x=0`. - 2 corresponds to :math:`x=L_x`. - 3 corresponds to :math:`y=0`. - 4 corresponds to :math:`y=L_y`. - 5 corresponds to :math:`z=0` (only in 3D). - 6 corresponds to :math:`z=L_z` (only in 3D). Parameters ---------- n : int Number of elements in the shortest coordinate direction. L_x : float Length in x-direction. L_y : float Length in y-direction. L_z : float or None, optional Length in z-direction, if this is ``None``, then the geometry will be two-dimensional (default is ``None``). Returns ------- mesh : dolfin.cpp.mesh.Mesh The computational mesh. subdomains : dolfin.cpp.mesh.MeshFunctionSizet A :py:class:`fenics.MeshFunction` object containing the subdomains. boundaries : dolfin.cpp.mesh.MeshFunctionSizet A MeshFunction object containing the boundaries. dx : ufl.measure.Measure The volume measure of the mesh corresponding to subdomains. ds : ufl.measure.Measure The surface measure of the mesh corresponding to boundaries. dS : ufl.measure.Measure The interior facet measure of the mesh corresponding to boundaries. """ if not n > 0: raise InputError('cashocs.geometry.regular_mesh', 'n', 'This needs to be positive.') if not L_x > 0.0: raise InputError('cashocs.geometry.regular_mesh', 'L_x', 'L_x needs to be positive') if not L_y > 0.0: raise InputError('cashocs.geometry.regular_mesh', 'L_y', 'L_y needs to be positive') if not (L_z is None or L_z > 0.0): raise InputError('cashocs.geometry.regular_mesh', 'L_z', 'L_z needs to be positive or None (for 2D mesh)') n = int(n) if L_z is None: sizes = [L_x, L_y] dim = 2 else: sizes = [L_x, L_y, L_z] dim = 3 size_min = np.min(sizes) num_points = [int(np.round(length / size_min * n)) for length in sizes] if L_z is None: mesh = fenics.RectangleMesh(fenics.Point(0, 0), fenics.Point(sizes), num_points[0], num_points[1]) else: mesh = fenics.BoxMesh(fenics.Point(0, 0, 0), fenics.Point(sizes), num_points[0], num_points[1], num_points[2]) subdomains = fenics.MeshFunction('size_t', mesh, dim=dim) boundaries = fenics.MeshFunction('size_t', mesh, dim=dim - 1) x_min = fenics.CompiledSubDomain('on_boundary && near(x[0], 0, tol)', tol=fenics.DOLFIN_EPS) x_max = fenics.CompiledSubDomain('on_boundary && near(x[0], length, tol)', tol=fenics.DOLFIN_EPS, length=sizes[0]) x_min.mark(boundaries, 1) x_max.mark(boundaries, 2) y_min = fenics.CompiledSubDomain('on_boundary && near(x[1], 0, tol)', tol=fenics.DOLFIN_EPS) y_max = fenics.CompiledSubDomain('on_boundary && near(x[1], length, tol)', tol=fenics.DOLFIN_EPS, length=sizes[1]) y_min.mark(boundaries, 3) y_max.mark(boundaries, 4) if L_z is not None: z_min = fenics.CompiledSubDomain('on_boundary && near(x[2], 0, tol)', tol=fenics.DOLFIN_EPS) z_max = fenics.CompiledSubDomain( 'on_boundary && near(x[2], length, tol)', tol=fenics.DOLFIN_EPS, length=sizes[2]) z_min.mark(boundaries, 5) z_max.mark(boundaries, 6) dx = fenics.Measure('dx', mesh, subdomain_data=subdomains) ds = fenics.Measure('ds', mesh, subdomain_data=boundaries) dS = fenics.Measure('dS', mesh) return mesh, subdomains, boundaries, dx, ds, dS
# Dirichlet data u_g = fn.Constant((0.0, 0.0)) p_g = fn.Constant(0.0) h_g = fn.Constant((0.0, -sigma0)) def strain(v): return fn.sym(fn.grad(v)) # boundary conditions bdry = fn.MeshFunction("size_t", mesh, 1) bdry.set_all(0) FooT = fn.CompiledSubDomain( "(x[0] >= -0.2) && (x[0] <= 0.2) && near(x[1], 0.75) && on_boundary") GammaU = fn.CompiledSubDomain( "( near(x[0], -0.5) || near(x[1], 0.0) ) && on_boundary") GammaU.mark(bdry, 31) FooT.mark(bdry, 32) ds = fn.Measure("ds", subdomain_data=bdry) bcU = fn.DirichletBC(Hh.sub(0), u_g, bdry, 31) bcP = fn.DirichletBC(Hh.sub(2), p_g, bdry, 32) bcs = [bcU, bcP] # ******** Weak forms ********** # PLeft = 2*mu*fn.inner(strain(u),strain(v)) * fn.dx \ - fn.div(v) * phi * fn.dx \ + (c0/alpha + 1.0/lmbda)* p * q * fn.dx \
from jaxfenics_adjoint import build_jax_fem_eval from jaxfenics_adjoint import from_numpy import matplotlib.pyplot as plt config.update("jax_enable_x64", True) fn.set_log_level(fn.LogLevel.ERROR) # Create mesh, refined in the center n = 64 mesh = fn.UnitSquareMesh(n, n) cf = fn.MeshFunction("bool", mesh, mesh.geometry().dim()) subdomain = fn.CompiledSubDomain( "std::abs(x[0]-0.5) < 0.25 && std::abs(x[1]-0.5) < 0.25" ) subdomain.mark(cf, True) mesh = fa.Mesh(fn.refine(mesh, cf)) # Define discrete function spaces and functions V = fn.FunctionSpace(mesh, "CG", 1) W = fn.FunctionSpace(mesh, "DG", 0) solve_templates = (fa.Function(W),) assemble_templates = (fa.Function(V), fa.Function(W)) # Define and solve the Poisson equation @build_jax_fem_eval(solve_templates) def fenics_solve(f): u = fa.Function(V, name="State")
# dirichlet data u_g = fn.Constant((0.0, 0.0, 0.0)) p_g = fn.Constant(0.0) h_g = fn.Constant((0.0, -sigma_0, 0.0)) # symmetric strain tensor def strain(v): return fn.sym(fn.grad(v)) # boundary and boundary conditions bdry = fn.MeshFunctionSizet(mesh, 2) bdry.set_all(0) FooT = fn.CompiledSubDomain( "sqrt(x[0]*x[0] + x[2]*x[2]) >= -0.4*L &&" + "sqrt(x[0]*x[0] + x[2]*x[2]) <= 0.4*L &&" + "near(x[1], 2*L) && on_boundary", L=L) GammaU = fn.CompiledSubDomain( "(near(x[0], -L) || near(x[0], L) ||" + " near(x[2], -L) || near(x[2], L) ||" + " near(x[1], 0.0)) && on_boundary", L=L) GammaU.mark(bdry, 31) FooT.mark(bdry, 32) fn.ds = fn.Measure("ds", subdomain_data=bdry) bcU = fn.DirichletBC(Hh.sub(0), u_g, bdry, 31) bcP = fn.DirichletBC(Hh.sub(2), p_g, bdry, 32) bcs = [bcU, bcP] # weak forms PLeft = 2*mu*fn.inner(strain(u), strain(v)) * fn.dx \
- (1.0 - heaviside(E - En)) * n) def RD_f(E, n): return 1.0/tauE * (-E + (Estar - pow(n, M)) \ * (1.0 - fn.tanh(E - Eh)) * pow(E, 2) * 0.5) def D(E, sigma): # this is important: it's where the coupling occurs return fn.Identity(2) * D0 * (1 + D0*E) + pow(D0, 2) * sigma # boundaries mesh_boundary = fn.MeshFunctionSizet(mesh, 1) mesh_boundary.set_all(0) # section of boundary that is free free_boundary = fn.CompiledSubDomain( "(near(x[1], mesh_height) || near(x[0], mesh_width/2)) && on_boundary", mesh_height=mesh_height, mesh_width=mesh_width) # section of boundary that is a rigid wall wall_boundary = fn.CompiledSubDomain( "(near(x[1], 0.0) || near(x[0], -mesh_width/2)) && on_boundary", mesh_width=mesh_width) # mark boundaries free_boundary.mark(mesh_boundary, 31) wall_boundary.mark(mesh_boundary, 32) # ds, for integrating ds = fn.Measure("ds", subdomain_data=mesh_boundary) # boundary conditions
def compute_static_deformation(self): assert self.mesh is not None # now we define subdomains on the mesh bottom = fe.CompiledSubDomain('near(x[2], 0) && on_boundary') top = fe.CompiledSubDomain('near(x[2], 1) && on_boundary') # middle = fe.CompiledSubDomain('x[2] > 0.3 && x[2] < 0.7') # Initialize mesh function for interior domains self.domains = fe.MeshFunction('size_t', self.mesh, 3) self.domains.set_all(0) # middle.mark(self.domains, 1) # Initialize mesh function for boundary domains self.boundaries = fe.MeshFunction('size_t', self.mesh, 2) self.boundaries.set_all(0) bottom.mark(self.boundaries, 1) top.mark(self.boundaries, 2) # Define new measures associated with the interior domains and # exterior boundaries self.dx = fe.Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.ds = fe.Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) # define function spaces V = fe.VectorFunctionSpace(self.mesh, "Lagrange", 1) # now we define subdomains on the mesh bottom = fe.CompiledSubDomain('near(x[2], 0) && on_boundary') top = fe.CompiledSubDomain('near(x[2], 1) && on_boundary') # middle = fe.CompiledSubDomain('x[2] > 0.3 && x[2] < 0.7') d = self.mesh.geometry().dim() # Initialize mesh function for interior domains self.domains = fe.MeshFunction('size_t', self.mesh, d) self.domains.set_all(0) # middle.mark(self.domains, 1) # Initialize mesh function for boundary domains self.boundaries = fe.MeshFunction('size_t', self.mesh, d - 1) self.boundaries.set_all(0) bottom.mark(self.boundaries, 1) top.mark(self.boundaries, 2) # Define new measures associated with the interior domains and # exterior boundaries self.dx = fe.Measure('dx', domain=self.mesh, subdomain_data=self.domains) self.ds = fe.Measure('ds', domain=self.mesh, subdomain_data=self.boundaries) c_zero = fe.Constant((0, 0, 0)) # define boundary conditions bc_bottom = fe.DirichletBC(V, c_zero, bottom) bc_top = fe.DirichletBC(V, c_zero, top) bcs = [bc_bottom] # , bc_top] # define functions du = TrialFunction(V) v = TestFunction(V) u = Function(V) B = fe.Constant((0., 2.0, 0.)) T = fe.Constant((0.0, 0.0, 0.0)) d = u.geometric_dimension() I = fe.Identity(d) F = I + grad(u) C = F.T * F I_1 = tr(C) J = det(F) E, mu = 10., 0.3 mu, lmbda = fe.Constant(E / (2 * (1 + mu))), fe.Constant( E * mu / ((1 + mu) * (1 - 2 * mu))) # stored energy (comp. neo-hookean model) psi = (mu / 2.) * (I_1 - 3) - mu * fe.ln(J) + (lmbda / 2.) * (fe.ln(J))**2 dx = self.dx ds = self.ds Pi = psi * fe.dx - dot(B, u) * fe.dx - dot(T, u) * fe.ds F = fe.derivative(Pi, u, v) J = fe.derivative(F, u, du) fe.solve(F == 0, u, bcs, J=J) # save results self.u = u # write to disk output = fe.File("/tmp/static.pvd") output << u
def vocal_tract_solver_backward(f_data, g_data, c_sound, length, Nx, basis_degree, T, num_tsteps, iteration): """ TODO """ # f expression f_cppcode = """ #include <iostream> #include <cmath> #include <pybind11/pybind11.h> #include <pybind11/eigen.h> #include <dolfin/function/Expression.h> class FExpress: public dolfin::Expression { public: int t_idx; // time index double DX; // length of uniformly spaced cell Eigen::MatrixXd array; // external data // Constructor FExpress() : dolfin::Expression(1), t_idx(0) { } // Overload: evaluate at given point in given cell void eval(Eigen::Ref<Eigen::VectorXd> values, Eigen::Ref<const Eigen::VectorXd> x) const { // values: values at the point // x: coordinates of the point int x_idx = std::round(x(0) / DX); // spatial index values(0) = array(t_idx, x_idx); } }; // Binding FExpress PYBIND11_MODULE(SIGNATURE, m) { pybind11::class_<FExpress, std::shared_ptr<FExpress>, dolfin::Expression> (m, "FExpress") .def(pybind11::init<>()) .def_readwrite("t_idx", &FExpress::t_idx) .def_readwrite("DX", &FExpress::DX) .def_readwrite("array", &FExpress::array) ; } """ f_expr = dolfin.compile_cpp_code(f_cppcode).FExpress() f = dolfin.CompiledExpression(f_expr, degree=basis_degree + 2) f.array = f_data f.t_idx = 0 f.DX = 1.0 / (Nx * basis_degree) # Initial expression u_I = F.Constant(0.0) # Neumann boundary expression g_cppcode = """ #include <pybind11/pybind11.h> #include <pybind11/eigen.h> #include <dolfin/function/Expression.h> class GExpress: public dolfin::Expression { public: int idx; // time-dependent index Eigen::VectorXd array; // external data // Constructor GExpress() : dolfin::Expression(1), idx(0) { } // Overload: evaluate at given point in given cell void eval(Eigen::Ref<Eigen::VectorXd> values, Eigen::Ref<const Eigen::VectorXd> x) const { // values: values at the point // x: coordinates of the point values(0) = array(idx); } }; // Binding GExpress PYBIND11_MODULE(SIGNATURE, m) { pybind11::class_<GExpress, std::shared_ptr<GExpress>, dolfin::Expression> (m, "GExpress") .def(pybind11::init<>()) .def_readwrite("idx", &GExpress::idx) .def_readwrite("array", &GExpress::array) ; } """ g_expr = dolfin.compile_cpp_code(g_cppcode).GExpress() g = dolfin.CompiledExpression(g_expr, degree=basis_degree + 2) g.array = g_data subboundary_L = F.CompiledSubDomain( "on_boundary && near(x[0], length, tol)", length=length, tol=1e-14) # boundary @ L # Solve boundary_conditions = {1: {"Neumann": g}, "subboundary": subboundary_L} divisions = (Nx, ) dt = T / num_tsteps # time step size U_k = pde_solver_backward( f, boundary_conditions, u_I, c_sound, divisions, T, dt, num_tsteps, initial_method="project", degree=basis_degree, iteration=iteration, ) return U_k
p_g = fn.Constant(0.0) h_g = fn.Constant((0.0, -sigma0)) def strain(v): return fn.sym(fn.grad(v)) # boundary conditions bdry = fn.MeshFunction("size_t", mesh, 1) bdry.set_all(0) # foot boundary FooT = fn.CompiledSubDomain( "x[0]>= -0.4*L && x[0] <= 0.4*L && near(x[1],75.0) && on_boundary", L=L) GammaU = fn.CompiledSubDomain( "(near(x[0],-50.0) || near(x[1],0.0) || near(x[0],50.0) ) && on_boundary") GammaU.mark(bdry, 31) FooT.mark(bdry, 32) ds = fn.Measure("ds", subdomain_data=bdry) bcU = fn.DirichletBC(Hh.sub(0), u_g, bdry, 31) bcP = fn.DirichletBC(Hh.sub(2), p_g, bdry, 32) bcs = [bcU, bcP] # weak forms PLeft = 2*mu*fn.inner(strain(u),strain(v)) * fn.dx \ - fn.div(v) * phi * fn.dx \ + (c0/alpha + 1.0/lmbda)* p * q * fn.dx \ + kappa/(alpha*nu) * fn.dot(fn.grad(p),fn.grad(q)) * fn.dx \
# dirichlet boundary conditions u_g = fn.Constant((0.0, 0.0)) # 0 displacement on walls p_g = fn.Constant(0.0) # 0 pressure on free surface h_g = fn.Expression(("0","-sigma0*t"), sigma0=sigma0, t=0.0, degree=3) # symmetric strain tensor def strain(u): return fn.sym(fn.grad(u)) # boundaries mesh_boundary = fn.MeshFunctionSizet(mesh, 1) mesh_boundary.set_all(0) # section of boundary on which foot presses foot_boundary = fn.CompiledSubDomain( "(x[0] >= -foot_width/2) && (x[0] <= foot_width/2)" + "&& near(x[1], mesh_height) && on_boundary", foot_width=foot_width, mesh_height=mesh_height) pressure_boundary = fn.CompiledSubDomain( "((x[0] < -foot_width/2) || (x[0] > foot_width/2))" + "&& near(x[1], mesh_height) && on_boundary", foot_width=foot_width, mesh_height=mesh_height) # section of boundary that is a rigid wall wall_boundary = fn.CompiledSubDomain( "(near(x[0], -mesh_width/2) || near(x[0], mesh_width/2)" + "|| near(x[1], 0.0)) && on_boundary", mesh_width=mesh_width) # mark boundaries foot_boundary.mark(mesh_boundary, 31)