def rotation_matrix_2d(angle): """ Rotation matrix associated with some ``angle``, as a UFL matrix. """ return ufl.as_matrix( [[ufl.cos(angle), -ufl.sin(angle)], [ufl.sin(angle), ufl.cos(angle)]] )
def fenics_cost(u, f): x = ufl.SpatialCoordinate(mesh) w = ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) d = 1 / (2 * ufl.pi ** 2) * w alpha = fa.Constant(1e-6) J_form = (0.5 * ufl.inner(u - d, u - d)) * ufl.dx + alpha / 2 * f ** 2 * ufl.dx J = fa.assemble(J_form) return J
def test_complex_assembly(): """Test assembly of complex matrices and vectors""" mesh = dolfinx.generation.UnitSquareMesh(dolfinx.MPI.comm_world, 10, 10) P2 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 2) V = dolfinx.function.FunctionSpace(mesh, P2) u = ufl.TrialFunction(V) v = ufl.TestFunction(V) g = -2 + 3.0j j = 1.0j a_real = inner(u, v) * dx L1 = inner(g, v) * dx b = dolfinx.fem.assemble_vector(L1) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bnorm = b.norm(PETSc.NormType.N1) b_norm_ref = abs(-2 + 3.0j) assert bnorm == pytest.approx(b_norm_ref) A = dolfinx.fem.assemble_matrix(a_real) A.assemble() A0_norm = A.norm(PETSc.NormType.FROBENIUS) x = SpatialCoordinate(mesh) a_imag = j * inner(u, v) * dx f = 1j * ufl.sin(2 * np.pi * x[0]) L0 = inner(f, v) * dx A = dolfinx.fem.assemble_matrix(a_imag) A.assemble() A1_norm = A.norm(PETSc.NormType.FROBENIUS) assert A0_norm == pytest.approx(A1_norm) b = dolfinx.fem.assemble_vector(L0) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) b1_norm = b.norm(PETSc.NormType.N2) a_complex = (1 + j) * inner(u, v) * dx f = ufl.sin(2 * np.pi * x[0]) L2 = inner(f, v) * dx A = dolfinx.fem.assemble_matrix(a_complex) A.assemble() A2_norm = A.norm(PETSc.NormType.FROBENIUS) assert A1_norm == pytest.approx(A2_norm / np.sqrt(2)) b = dolfinx.fem.assemble_vector(L2) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) b2_norm = b.norm(PETSc.NormType.N2) assert b2_norm == pytest.approx(b1_norm)
def test_complex_assembly(): """Test assembly of complex matrices and vectors""" mesh = create_unit_square(MPI.COMM_WORLD, 10, 10) P2 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 2) V = FunctionSpace(mesh, P2) u = ufl.TrialFunction(V) v = ufl.TestFunction(V) g = -2 + 3.0j j = 1.0j a_real = form(inner(u, v) * dx) L1 = form(inner(g, v) * dx) b = assemble_vector(L1) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) bnorm = b.norm(PETSc.NormType.N1) b_norm_ref = abs(-2 + 3.0j) assert bnorm == pytest.approx(b_norm_ref) A = assemble_matrix(a_real) A.assemble() A0_norm = A.norm(PETSc.NormType.FROBENIUS) x = ufl.SpatialCoordinate(mesh) a_imag = form(j * inner(u, v) * dx) f = 1j * ufl.sin(2 * np.pi * x[0]) L0 = form(inner(f, v) * dx) A = assemble_matrix(a_imag) A.assemble() A1_norm = A.norm(PETSc.NormType.FROBENIUS) assert A0_norm == pytest.approx(A1_norm) b = assemble_vector(L0) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) b1_norm = b.norm(PETSc.NormType.N2) a_complex = form((1 + j) * inner(u, v) * dx) f = ufl.sin(2 * np.pi * x[0]) L2 = form(inner(f, v) * dx) A = assemble_matrix(a_complex) A.assemble() A2_norm = A.norm(PETSc.NormType.FROBENIUS) assert A1_norm == pytest.approx(A2_norm / np.sqrt(2)) b = assemble_vector(L2) b.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) b2_norm = b.norm(PETSc.NormType.N2) assert b2_norm == pytest.approx(b1_norm)
def assemble_solution(self, t): # returns """ :param t: time :return: Womersley flow (analytic solution) at time t analytic solution at any time is a steady parabolic flow + linear combination of 8 modes modes were precomputed as 8 functions on given mesh and stored in hdf5 file """ if self.tc is not None: self.tc.start('assembleSol') sol = Function(self.solutionSpace) # analytic solution has zero x and y components dofs2 = self.solutionSpace.sub(2).dofmap().dofs( ) # gives field of indices corresponding to z axis sol.assign(Constant(("0.0", "0.0", "0.0"))) # QQ not needed sol.vector()[dofs2] += self.factor * self.bessel_parabolic.vector( ).array() # parabolic part of sol for idx in range(8): # add modes of Womersley sol sol.vector()[dofs2] += self.factor * cos( self.coefs_exp[idx] * pi * t) * self.bessel_real[idx].vector().array() sol.vector()[dofs2] += self.factor * -sin( self.coefs_exp[idx] * pi * t) * self.bessel_complex[idx].vector().array() if self.tc is not None: self.tc.end('assembleSol') return sol
def test_mpc_assembly(master_point, degree, celltype, get_assemblers): # noqa: F811 _, assemble_vector = get_assemblers # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 3, 5, celltype) V = fem.FunctionSpace(mesh, ("Lagrange", degree)) # Generate reference vector v = ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh) f = ufl.sin(2 * ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) rhs = ufl.inner(f, v) * ufl.dx linear_form = fem.form(rhs) def l2b(li): return np.array(li, dtype=np.float64).tobytes() s_m_c = { l2b([1, 0]): { l2b([0, 1]): 0.43, l2b([1, 1]): 0.11 }, l2b([0, 0]): { l2b(master_point): 0.69 } } mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_general_constraint(s_m_c) mpc.finalize() b = assemble_vector(linear_form, mpc) b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) # Reduce system with global matrix K after assembly L_org = fem.petsc.assemble_vector(linear_form) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) root = 0 comm = mesh.comm with Timer("~TEST: Compare"): dolfinx_mpc.utils.compare_mpc_rhs(L_org, b, mpc, root=root) list_timings(comm, [TimingType.wall])
def test_dolfin_expression_compilation_of_math_functions(dolfin): # Define some PyDOLFIN coefficients mesh = dolfin.UnitSquareMesh(3, 3) # Using quadratic element deliberately for accuracy V = dolfin.FunctionSpace(mesh, "CG", 2) u = dolfin.Function(V) u.interpolate(dolfin.Expression("x[0]*x[1]")) w0 = u # Define ufl expression with math functions v = abs(ufl.cos(u))/2 + 0.02 uexpr = ufl.sin(u) + ufl.tan(v) + ufl.exp(u) + ufl.ln(v) + ufl.atan(v) + ufl.acos(v) + ufl.asin(v) #print dolfin.assemble(uexpr**2*dolfin.dx, mesh=mesh) # 11.7846508409 # Define expected output from compilation ucode = 'v_w0[0]' vcode = '0.02 + fabs(cos(v_w0[0])) / 2' funcs = 'asin(%(v)s) + (acos(%(v)s) + (atan(%(v)s) + (log(%(v)s) + (exp(%(u)s) + (sin(%(u)s) + tan(%(v)s))))))' oneliner = funcs % {'u':ucode, 'v':vcode} # Oneliner version (ignoring reuse): expected_lines = ['double s[1];', 'Array<double> v_w0(1);', 'w0->eval(v_w0, x);', 's[0] = %s;' % oneliner, 'values[0] = s[0];'] #cppcode = format_dolfin_expression(classname="DebugExpression", shape=(), eval_body=expected_lines) #print '-'*100 #print cppcode #print '-'*100 #dolfin.plot(dolfin.Expression(cppcode=cppcode, mesh=mesh)) #dolfin.interactive() # Split version (handles reuse of v, no other reuse): expected_lines = ['double s[2];', 'Array<double> v_w0(1);', 'w0->eval(v_w0, x);', 's[0] = %s;' % (vcode,), 's[1] = %s;' % (funcs % {'u':ucode,'v':'s[0]'},), 'values[0] = s[1];'] # Define expected evaluation values: [(x,value), (x,value), ...] import math x, y = 0.6, 0.7 u = x*y v = abs(math.cos(u))/2 + 0.02 v0 = .52 expected0 = math.tan(v0) + 1 + math.log(v0) + math.atan(v0) + math.acos(v0) + math.asin(v0) expected = math.sin(u) + math.tan(v) + math.exp(u) + math.log(v) + math.atan(v) + math.acos(v) + math.asin(v) expected_values = [((0.0, 0.0), (expected0,)), ((x, y), (expected,)), ] # Execute all tests check_dolfin_expression_compilation(uexpr, expected_lines, expected_values, members={'w0':w0})
def test_complex_algebra(self): z1 = ComplexValue(1j) z2 = ComplexValue(1+1j) # Remember that ufl.algebra functions return ComplexValues, but ufl.mathfunctions return complex Python scalar # Any operations with a ComplexValue and a complex Python scalar promote to ComplexValue assert z1*z2 == ComplexValue(-1+1j) assert z2/z1 == ComplexValue(1-1j) assert pow(z2, z1) == ComplexValue((1+1j)**1j) assert sqrt(z2) * as_ufl(1) == ComplexValue(cmath.sqrt(1+1j)) assert ((sin(z2) + cosh(z2) - atan(z2)) * z1) == ComplexValue((cmath.sin(1+1j) + cmath.cosh(1+1j) - cmath.atan(1+1j))*1j) assert (abs(z2) - ln(z2))/exp(z1) == ComplexValue((abs(1+1j) - cmath.log(1+1j))/cmath.exp(1j))
def test_latex_formatting_of_cmath(): x = ufl.SpatialCoordinate(ufl.triangle)[0] assert expr2latex(ufl.exp(x)) == r"e^{x_0}" assert expr2latex(ufl.ln(x)) == r"\ln(x_0)" assert expr2latex(ufl.sqrt(x)) == r"\sqrt{x_0}" assert expr2latex(abs(x)) == r"\|x_0\|" assert expr2latex(ufl.sin(x)) == r"\sin(x_0)" assert expr2latex(ufl.cos(x)) == r"\cos(x_0)" assert expr2latex(ufl.tan(x)) == r"\tan(x_0)" assert expr2latex(ufl.asin(x)) == r"\arcsin(x_0)" assert expr2latex(ufl.acos(x)) == r"\arccos(x_0)" assert expr2latex(ufl.atan(x)) == r"\arctan(x_0)"
def test_cpp_formatting_of_cmath(): x, y = ufl.SpatialCoordinate(ufl.triangle) # Test cmath functions assert expr2cpp(ufl.exp(x)) == "exp(x[0])" assert expr2cpp(ufl.ln(x)) == "log(x[0])" assert expr2cpp(ufl.sqrt(x)) == "sqrt(x[0])" assert expr2cpp(abs(x)) == "fabs(x[0])" assert expr2cpp(ufl.sin(x)) == "sin(x[0])" assert expr2cpp(ufl.cos(x)) == "cos(x[0])" assert expr2cpp(ufl.tan(x)) == "tan(x[0])" assert expr2cpp(ufl.asin(x)) == "asin(x[0])" assert expr2cpp(ufl.acos(x)) == "acos(x[0])" assert expr2cpp(ufl.atan(x)) == "atan(x[0])"
def assemble_solution(self, t): # returns Womersley sol for time t if self.tc is not None: self.tc.start('assembleSol') sol = Function(self.solutionSpace) dofs2 = self.solutionSpace.sub(2).dofmap().dofs() # gives field of indices corresponding to z axis sol.assign(Constant(("0.0", "0.0", "0.0"))) # QQ not needed sol.vector()[dofs2] += self.factor * self.bessel_parabolic.vector().array() # parabolic part of sol for idx in range(8): # add modes of Womersley sol sol.vector()[dofs2] += self.factor * cos(self.coefs_exp[idx] * pi * t) * self.bessel_real[idx].vector().array() sol.vector()[dofs2] += self.factor * -sin(self.coefs_exp[idx] * pi * t) * self.bessel_complex[idx].vector().array() if self.tc is not None: self.tc.end('assembleSol') return sol
def test_estimated_degree(): cell = ufl.tetrahedron mesh = ufl.Mesh(ufl.VectorElement('P', cell, 1)) V = ufl.FunctionSpace(mesh, ufl.FiniteElement('P', cell, 1)) f = ufl.Coefficient(V) u = ufl.TrialFunction(V) v = ufl.TestFunction(V) a = u * v * ufl.tanh(ufl.sqrt(ufl.sinh(f) / ufl.sin(f**f))) * ufl.dx handler = MockHandler() logger.addHandler(handler) with pytest.raises(RuntimeError): compile_form(a) logger.removeHandler(handler)
def test_is_zero_simple_scalar_expressions(): mesh = UnitSquareMesh(4, 4) V = FunctionSpace(mesh, 'CG', 1) v = TestFunction(V) u = TrialFunction(V) check_is_zero(Zero() * u * v, 0) check_is_zero(Constant(0) * u * v, 1) check_is_zero(Zero() * v, 0) check_is_zero(Constant(0) * v, 1) check_is_zero(0 * u * v, 0) check_is_zero(0 * v, 0) check_is_zero(ufl.sin(0) * v, 0) check_is_zero(ufl.cos(0) * v, 1)
def test_cpp_formatting_precedence_handling(): x, y = ufl.SpatialCoordinate(ufl.triangle) # Test precedence handling with sums # Note that the automatic sorting is reflected in formatting! assert expr2cpp(y + (2 + x)) == "x[1] + (2 + x[0])" assert expr2cpp((x + 2) + y) == "x[1] + (2 + x[0])" assert expr2cpp((2 + x) + (3 + y)) == "(2 + x[0]) + (3 + x[1])" assert expr2cpp((x + 3) + 2 + y) == "x[1] + (2 + (3 + x[0]))" assert expr2cpp(2 + (x + 3) + y) == "x[1] + (2 + (3 + x[0]))" assert expr2cpp(2 + (3 + x) + y) == "x[1] + (2 + (3 + x[0]))" assert expr2cpp(y + (2 + (3 + x))) == "x[1] + (2 + (3 + x[0]))" assert expr2cpp(2 + x + 3 + y) == "x[1] + (3 + (2 + x[0]))" assert expr2cpp(2 + x + 3 + y) == "x[1] + (3 + (2 + x[0]))" # Test precedence handling with divisions # This is more stable than sums since there is no sorting. assert expr2cpp((x / 2) / 3) == "(x[0] / 2) / 3" assert expr2cpp(x / (y / 3)) == "x[0] / (x[1] / 3)" assert expr2cpp((x / 2) / (y / 3)) == "(x[0] / 2) / (x[1] / 3)" assert expr2cpp(x / (2 / y) / 3) == "(x[0] / (2 / x[1])) / 3" # Test precedence handling with highest level types assert expr2cpp(ufl.sin(x)) == "sin(x[0])" assert expr2cpp(ufl.cos(x + 2)) == "cos(2 + x[0])" assert expr2cpp(ufl.tan(x / 2)) == "tan(x[0] / 2)" assert expr2cpp(ufl.acos(x + 3 * y)) == "acos(x[0] + 3 * x[1])" assert expr2cpp(ufl.asin(ufl.atan(x**4))) == "asin(atan(pow(x[0], 4)))" assert expr2cpp(ufl.sin(y) + ufl.tan(x)) == "sin(x[1]) + tan(x[0])" # Test precedence handling with mixed types assert expr2cpp(3 * (2 + x)) == "3 * (2 + x[0])" assert expr2cpp((2 * x) + (3 * y)) == "2 * x[0] + 3 * x[1]" assert expr2cpp(2 * (x + 3) * y) == "x[1] * (2 * (3 + x[0]))" assert expr2cpp(2 * (x + 3)**4 * y) == "x[1] * (2 * pow(3 + x[0], 4))"
def test_complex_assembly(): """Test assembly of complex matrices and vectors""" mesh = dolfin.generation.UnitSquareMesh(dolfin.MPI.comm_world, 10, 10) P2 = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), 2) V = dolfin.function.functionspace.FunctionSpace(mesh, P2) u = dolfin.function.argument.TrialFunction(V) v = dolfin.function.argument.TestFunction(V) g = dolfin.function.constant.Constant(-2 + 3.0j) j = dolfin.function.constant.Constant(1.0j) a_real = inner(u, v) * dx L1 = inner(g, v) * dx bnorm = dolfin.fem.assemble(L1).norm(dolfin.cpp.la.Norm.l1) b_norm_ref = abs(-2 + 3.0j) assert np.isclose(bnorm, b_norm_ref) A0_norm = dolfin.fem.assemble(a_real).norm(dolfin.cpp.la.Norm.frobenius) x = dolfin.SpatialCoordinate(mesh) a_imag = j * inner(u, v) * dx f = 1j * ufl.sin(2 * np.pi * x[0]) L0 = inner(f, v) * dx A1_norm = dolfin.fem.assemble(a_imag).norm(dolfin.cpp.la.Norm.frobenius) assert np.isclose(A0_norm, A1_norm) b1_norm = dolfin.fem.assemble(L0).norm(dolfin.cpp.la.Norm.l2) a_complex = (1 + j) * inner(u, v) * dx f = ufl.sin(2 * np.pi * x[0]) L2 = inner(f, v) * dx A2_norm = dolfin.fem.assemble(a_complex).norm(dolfin.cpp.la.Norm.frobenius) assert np.isclose(A1_norm, A2_norm / np.sqrt(2)) b2_norm = dolfin.fem.assemble(L2).norm(dolfin.cpp.la.Norm.l2) assert np.isclose(b2_norm, b1_norm)
def test_comparison_checker(self): cell = triangle element = FiniteElement("Lagrange", cell, 1) u = TrialFunction(element) v = TestFunction(element) a = conditional(ge(abs(u), imag(v)), u, v) b = conditional(le(sqrt(abs(u)), imag(v)), as_ufl(1), as_ufl(1j)) c = conditional(gt(abs(u), pow(imag(v), 0.5)), sin(u), cos(v)) d = conditional(lt(as_ufl(-1), as_ufl(1)), u, v) e = max_value(as_ufl(0), real(u)) f = min_value(sin(u), cos(v)) g = min_value(sin(pow(u, 3)), cos(abs(v))) assert do_comparison_check(a) == conditional(ge(real(abs(u)), real(imag(v))), u, v) with pytest.raises(ComplexComparisonError): b = do_comparison_check(b) with pytest.raises(ComplexComparisonError): c = do_comparison_check(c) assert do_comparison_check(d) == conditional(lt(real(as_ufl(-1)), real(as_ufl(1))), u, v) assert do_comparison_check(e) == max_value(real(as_ufl(0)), real(real(u))) assert do_comparison_check(f) == min_value(real(sin(u)), real(cos(v))) assert do_comparison_check(g) == min_value(real(sin(pow(u, 3))), real(cos(abs(v))))
def test_latex_formatting_precedence_handling(): x, y = ufl.SpatialCoordinate(ufl.triangle) # Test precedence handling with sums # Note that the automatic sorting is reflected in formatting! assert expr2latex(y + (2 + x)) == "x_1 + (2 + x_0)" assert expr2latex((x + 2) + y) == "x_1 + (2 + x_0)" assert expr2latex((2 + x) + (3 + y)) == "(2 + x_0) + (3 + x_1)" assert expr2latex((x + 3) + 2 + y) == "x_1 + (2 + (3 + x_0))" assert expr2latex(2 + (x + 3) + y) == "x_1 + (2 + (3 + x_0))" assert expr2latex(2 + (3 + x) + y) == "x_1 + (2 + (3 + x_0))" assert expr2latex(y + (2 + (3 + x))) == "x_1 + (2 + (3 + x_0))" assert expr2latex(2 + x + 3 + y) == "x_1 + (3 + (2 + x_0))" assert expr2latex(2 + x + 3 + y) == "x_1 + (3 + (2 + x_0))" # Test precedence handling with divisions # This is more stable than sums since there is no sorting. assert expr2latex((x / 2) / 3) == r"\frac{(\frac{x_0}{2})}{3}" assert expr2latex(x / (y / 3)) == r"\frac{x_0}{(\frac{x_1}{3})}" assert expr2latex((x / 2) / (y / 3)) == r"\frac{(\frac{x_0}{2})}{(\frac{x_1}{3})}" assert expr2latex(x / (2 / y) / 3) == r"\frac{(\frac{x_0}{(\frac{2}{x_1})})}{3}" # Test precedence handling with highest level types assert expr2latex(ufl.sin(x)) == r"\sin(x_0)" assert expr2latex(ufl.cos(x + 2)) == r"\cos(2 + x_0)" assert expr2latex(ufl.tan(x / 2)) == r"\tan(\frac{x_0}{2})" assert expr2latex(ufl.acos(x + 3 * y)) == r"\arccos(x_0 + 3 x_1)" assert expr2latex(ufl.asin(ufl.atan(x**4))) == r"\arcsin(\arctan({x_0}^{4}))" assert expr2latex(ufl.sin(y) + ufl.tan(x)) == r"\sin(x_1) + \tan(x_0)" # Test precedence handling with mixed types assert expr2latex(3 * (2 + x)) == "3 (2 + x_0)" assert expr2latex((2 * x) + (3 * y)) == "2 x_0 + 3 x_1" assert expr2latex(2 * (x + 3) * y) == "x_1 (2 (3 + x_0))"
def test_latex_formatting_of_derivatives(): xx = ufl.SpatialCoordinate(ufl.triangle) x = xx[0] # Test derivatives of basic operators assert expr2latex(x.dx(0)) == "1" assert expr2latex(x.dx(1)) == "0" assert expr2latex(ufl.grad(xx)[0, 0]) == "1" assert expr2latex(ufl.grad(xx)[0, 1]) == "0" assert expr2latex(ufl.sin(x).dx(0)) == r"\cos(x_0)" # Test derivatives of form arguments V = ufl.FiniteElement("CG", ufl.triangle, 1) f = ufl.Coefficient(V, count=0) assert expr2latex(f.dx(0)) == r"\overset{0}{w}_{, 0}" v = ufl.Argument(V, number=3) assert expr2latex(v.dx(1)) == r"\overset{3}{v}_{, 1}"
def test_cpp_formatting_of_derivatives(): xx = ufl.SpatialCoordinate(ufl.triangle) x, y = xx # Test derivatives of basic operators assert expr2cpp(x.dx(0)) == "1" assert expr2cpp(x.dx(1)) == "0" assert expr2cpp(ufl.grad(xx)[0, 0]) == "1" assert expr2cpp(ufl.grad(xx)[0, 1]) == "0" assert expr2cpp(ufl.sin(x).dx(0)) == "cos(x[0])" # Test derivatives of target specific test fakes V = ufl.FiniteElement("CG", ufl.triangle, 1) f = ufl.Coefficient(V, count=0) assert expr2cpp(f.dx(0)) == "d1_w0[0]" v = ufl.Argument(V, number=3) assert expr2cpp(v.dx(1)) == "d1_v3[1]" # NOT renumbered to 0...
def __init__(self, mesh, k: int, omega, c, c0, lumped): P = ufl.FiniteElement("Lagrange", mesh.ufl_cell(), k) self.V = FunctionSpace(mesh, P) self.u, self.v = Function(self.V), Function(self.V) self.g1 = Function(self.V) self.g2 = Function(self.V) self.omega = omega self.c = c self.c0 = c0 n = FacetNormal(mesh) # Pieces for plane wave incident field x = ufl.geometry.SpatialCoordinate(mesh) cos_wave = ufl.cos(self.omega / self.c0 * x[0]) sin_wave = ufl.sin(self.omega / self.c0 * x[0]) plane_wave = self.g1 * cos_wave + self.g2 * sin_wave dv, p = TrialFunction(self.V), TestFunction(self.V) self.L1 = - inner(grad(self.u), grad(p)) * dx(degree=k) \ - (1 / self.c) * inner(self.v, p) * ds \ - (1 / self.c**2) * (-self.omega**2) * inner(plane_wave, p) * dx \ - inner(grad(plane_wave), grad(p)) * dx \ + inner(dot(grad(plane_wave), n), p) * ds # Vector to be re-used for assembly self.b = None # TODO: precompile/pre-process Form L self.lumped = lumped if self.lumped: a = (1 / self.c**2) * p * dx(degree=k) self.M = dolfinx.fem.assemble_vector(a) self.M.ghostUpdate(addv=PETSc.InsertMode.ADD, mode=PETSc.ScatterMode.REVERSE) else: a = (1 / self.c**2) * inner(dv, p) * dx(degree=k) M = dolfinx.fem.assemble_matrix(a) M.assemble() self.solver = PETSc.KSP().create(mesh.mpi_comm()) opts = PETSc.Options() opts["ksp_type"] = "cg" opts["ksp_rtol"] = 1.0e-8 self.solver.setFromOptions() self.solver.setOperators(M)
def test_Dt_linear(V, typ): u = Coefficient(V) v = TestFunction(V) c = Coefficient(V) F = (inner(grad(u), grad(v)) + inner(c, v) + inner(Dt(u), v)) * dx if typ == "mul": F += inner(Dt(u), c) * inner(Dt(u), v) * dx elif typ == "div": F += inner(Dt(u), v) / Dt(u)[0] * dx elif typ == "sin": F += inner(sin(Dt(u)[0]), v[0]) * dx with pytest.raises(ValueError): check_integrals(F.integrals(), expect_time_derivative=True)
def test_block(V1, V2, squaremesh_5, nest): mesh = squaremesh_5 u0 = dolfinx.Function(V1, name="u0") u1 = dolfinx.Function(V2, name="u1") v0 = ufl.TestFunction(V1) v1 = ufl.TestFunction(V2) Phi = (ufl.sin(u0) - 0.5)**2 * ufl.dx(mesh) + (4.0 * u0 - u1)**2 * ufl.dx(mesh) F0 = ufl.derivative(Phi, u0, v0) F1 = ufl.derivative(Phi, u1, v1) F = [F0, F1] u = [u0, u1] opts = PETSc.Options("block") opts.setValue('snes_type', 'newtontr') opts.setValue('snes_rtol', 1.0e-08) opts.setValue('snes_max_it', 12) if nest: opts.setValue('ksp_type', 'cg') opts.setValue('pc_type', 'fieldsplit') opts.setValue('fieldsplit_pc_type', 'lu') opts.setValue('ksp_rtol', 1.0e-10) else: opts.setValue('ksp_type', 'preonly') opts.setValue('pc_type', 'lu') opts.setValue('pc_factor_mat_solver_type', 'mumps') problem = dolfiny.snesblockproblem.SNESBlockProblem(F, u, nest=nest, prefix="block") sol = problem.solve() assert problem.snes.getConvergedReason() > 0 assert np.isclose((sol[0].vector - np.arcsin(0.5)).norm(), 0.0) assert np.isclose((sol[1].vector - 4.0 * np.arcsin(0.5)).norm(), 0.0)
def assemble_solution(self, t): # returns """ :param t: time :return: Womersley flow (analytic solution) at time t analytic solution at any time is a steady parabolic flow + linear combination of 8 modes modes were precomputed as 8 functions on given mesh and stored in hdf5 file """ if self.tc is not None: self.tc.start('assembleSol') sol = Function(self.solutionSpace) # analytic solution has zero x and y components dofs2 = self.solutionSpace.sub(2).dofmap().dofs() # gives field of indices corresponding to z axis sol.assign(Constant(("0.0", "0.0", "0.0"))) # QQ not needed sol.vector()[dofs2] += self.factor * self.bessel_parabolic.vector().array() # parabolic part of sol for idx in range(8): # add modes of Womersley sol sol.vector()[dofs2] += self.factor * cos(self.coefs_exp[idx] * pi * t) * self.bessel_real[idx].vector().array() sol.vector()[dofs2] += self.factor * -sin(self.coefs_exp[idx] * pi * t) * self.bessel_complex[idx].vector().array() if self.tc is not None: self.tc.end('assembleSol') return sol
def test_monolithic(V1, V2, squaremesh_5): mesh = squaremesh_5 Wel = ufl.MixedElement([V1.ufl_element(), V2.ufl_element()]) W = dolfinx.FunctionSpace(mesh, Wel) u = dolfinx.Function(W) u0, u1 = ufl.split(u) v = ufl.TestFunction(W) v0, v1 = ufl.split(v) Phi = (ufl.sin(u0) - 0.5)**2 * ufl.dx(mesh) + (4.0 * u0 - u1)**2 * ufl.dx(mesh) F = ufl.derivative(Phi, u, v) opts = PETSc.Options("monolithic") opts.setValue('snes_type', 'newtonls') opts.setValue('snes_linesearch_type', 'basic') opts.setValue('snes_rtol', 1.0e-10) opts.setValue('snes_max_it', 20) opts.setValue('ksp_type', 'preonly') opts.setValue('pc_type', 'lu') opts.setValue('pc_factor_mat_solver_type', 'mumps') problem = dolfiny.snesblockproblem.SNESBlockProblem([F], [u], prefix="monolithic") sol, = problem.solve() u0, u1 = sol.split() u0 = u0.collapse() u1 = u1.collapse() assert np.isclose((u0.vector - np.arcsin(0.5)).norm(), 0.0) assert np.isclose((u1.vector - 4.0 * np.arcsin(0.5)).norm(), 0.0)
def test_nonlinear_possion(poly_order): # Solve a standard Poisson problem with known solution which has # rotational symmetry of pi/2 at (x, y) = (0.5, 0.5). Therefore we may # impose MPCs on those DoFs which lie on the symmetry plane(s) and test # our numerical approximation. We do not impose any constraints at the # rotationally degenerate point (x, y) = (0.5, 0.5). N_vals = np.array([4, 8, 16], dtype=np.int32) l2_error = np.zeros_like(N_vals, dtype=np.double) for run_no, N in enumerate(N_vals): mesh = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, N, N) V = dolfinx.fem.FunctionSpace(mesh, ("Lagrange", poly_order)) def boundary(x): return np.ones_like(x[0], dtype=np.int8) u_bc = dolfinx.fem.Function(V) with u_bc.vector.localForm() as u_local: u_local.set(0.0) facets = dolfinx.mesh.locate_entities_boundary(mesh, 1, boundary) topological_dofs = dolfinx.fem.locate_dofs_topological(V, 1, facets) zero = np.array(0, dtype=PETSc.ScalarType) bc = dolfinx.fem.dirichletbc(zero, topological_dofs, V) bcs = [bc] # Define variational problem u = dolfinx.fem.Function(V) v = ufl.TestFunction(V) x = ufl.SpatialCoordinate(mesh) u_soln = ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) f = -ufl.div((1 + u_soln**2) * ufl.grad(u_soln)) F = ufl.inner((1 + u**2) * ufl.grad(u), ufl.grad(v)) * ufl.dx \ - ufl.inner(f, v) * ufl.dx J = ufl.derivative(F, u) # -- Impose the pi/2 rotational symmetry of the solution as a constraint, # -- except at the centre DoF def periodic_boundary(x): eps = 1e-10 return np.isclose(x[0], 0.5) & ((x[1] < 0.5 - eps) | (x[1] > 0.5 + eps)) def periodic_relation(x): out_x = np.zeros(x.shape) out_x[0] = x[1] out_x[1] = x[0] out_x[2] = x[2] return out_x mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_periodic_constraint_geometrical(V, periodic_boundary, periodic_relation, bcs) mpc.finalize() # Sanity check that the MPC class has some constraints to impose num_slaves_global = mesh.comm.allreduce(len(mpc.slaves), op=MPI.SUM) num_masters_global = mesh.comm.allreduce(len(mpc.masters.array), op=MPI.SUM) assert num_slaves_global > 0 assert num_masters_global == num_slaves_global problem = NonlinearMPCProblem(F, u, mpc, bcs=bcs, J=J) solver = NewtonSolverMPC(mesh.comm, problem, mpc) # Ensure the solver works with nonzero initial guess u.interpolate(lambda x: x[0]**2 * x[1]**2) solver.solve(u) l2_error_local = dolfinx.fem.assemble_scalar( dolfinx.fem.form((u - u_soln)**2 * ufl.dx)) l2_error_global = mesh.comm.allreduce(l2_error_local, op=MPI.SUM) l2_error[run_no] = l2_error_global**0.5 rates = np.log(l2_error[:-1] / l2_error[1:]) / np.log(2.0) assert np.all(rates > poly_order + 0.9)
# :py:class:`FunctionSpace # <dolfin.functions.functionspace.FunctionSpace>` ``V``. # # Further, the source :math:`f` and the boundary normal derivative # :math:`g` are involved in the variational forms, and hence we must # specify these. # # With these ingredients, we can write down the bilinear form ``a`` and # the linear form ``L`` (using UFL operators). In summary, this reads :: # Define variational problem u = TrialFunction(V) v = TestFunction(V) x = SpatialCoordinate(mesh) f = 10 * ufl.exp(-((x[0] - 0.5)**2 + (x[1] - 0.5)**2) / 0.02) g = ufl.sin(5 * x[0]) a = inner(grad(u), grad(v)) * dx L = inner(f, v) * dx + inner(g, v) * ds # Now, we have specified the variational forms and can consider the # solution of the variational problem. First, we need to define a # :py:class:`Function <dolfin.functions.function.Function>` ``u`` to # represent the solution. (Upon initialization, it is simply set to the # zero function.) A :py:class:`Function # <dolfin.functions.function.Function>` represents a function living in # a finite element function space. Next, we can call the :py:func:`solve # <dolfin.fem.solving.solve>` function with the arguments ``a == L``, # ``u`` and ``bc`` as follows: :: # Compute solution u = Function(V)
dt = dune.ufl.Constant(5e-2, "timeStep") t = dune.ufl.Constant(0.0, "time") # define storage for discrete solutions uh = space.interpolate(0, name="uh") uh_old = uh.copy() # initial solution initial = 0 # problem definition # moving oven ROven = 0.6 omegaOven = 0.01 * pi * t P = ufl.as_vector([ROven*cos(omegaOven*t), ROven*sin(omegaOven*t)]) rOven = 0.2 ovenEnergy = 8 chiOven = ufl.conditional(dot(x-P, x-P) < rOven**2, 1, 0) ovenLoad = ovenEnergy * chiOven # desk in corner of room deskCenter = [-0.8, -0.8] deskSize = 0.2 chiDesk = ufl.conditional(abs(x[0]-deskCenter[0]) < deskSize, 1, 0)\ * ufl.conditional(abs(x[1] - deskCenter[1]) < deskSize, 1, 0) # Robin condition for window windowWidth = 0.5 transmissionCoefficient = 1.2 outerTemperature = -5.0
def test_diff_then_integrate(): # Define 1D geometry n = 21 mesh = UnitIntervalMesh(MPI.comm_world, n) # Shift and scale mesh x0, x1 = 1.5, 3.14 mesh.coordinates()[:] *= (x1 - x0) mesh.coordinates()[:] += x0 x = SpatialCoordinate(mesh)[0] xs = 0.1 + 0.8 * x / x1 # scaled to be within [0.1,0.9] # Define list of expressions to test, and configure # accuracies these expressions are known to pass with. # The reason some functions are less accurately integrated is # likely that the default choice of quadrature rule is not perfect F_list = [] def reg(exprs, acc=10): for expr in exprs: F_list.append((expr, acc)) # FIXME: 0*dx and 1*dx fails in the ufl-ffc-jit framework somewhere # reg([Constant(0.0, cell=cell)]) # reg([Constant(1.0, cell=cell)]) monomial_list = [x**q for q in range(2, 6)] reg(monomial_list) reg([2.3 * p + 4.5 * q for p in monomial_list for q in monomial_list]) reg([x**x]) reg([x**(x**2)], 8) reg([x**(x**3)], 6) reg([x**(x**4)], 2) # Special functions: reg([atan(xs)], 8) reg([sin(x), cos(x), exp(x)], 5) reg([ln(xs), pow(x, 2.7), pow(2.7, x)], 3) reg([asin(xs), acos(xs)], 1) reg([tan(xs)], 7) try: import scipy except ImportError: scipy = None if hasattr(math, 'erf') or scipy is not None: reg([erf(xs)]) else: print( "Warning: skipping test of erf, old python version and no scipy.") # if 0: # print("Warning: skipping tests of bessel functions, doesn't build on all platforms.") # elif scipy is None: # print("Warning: skipping tests of bessel functions, missing scipy.") # else: # for nu in (0, 1, 2): # # Many of these are possibly more accurately integrated, # # but 4 covers all and is sufficient for this test # reg([bessel_J(nu, xs), bessel_Y(nu, xs), bessel_I(nu, xs), bessel_K(nu, xs)], 4) # To handle tensor algebra, make an x dependent input tensor # xx and square all expressions def reg2(exprs, acc=10): for expr in exprs: F_list.append((inner(expr, expr), acc)) xx = as_matrix([[2 * x**2, 3 * x**3], [11 * x**5, 7 * x**4]]) x3v = as_vector([3 * x**2, 5 * x**3, 7 * x**4]) cc = as_matrix([[2, 3], [4, 5]]) reg2([xx]) reg2([x3v]) reg2([cross(3 * x3v, as_vector([-x3v[1], x3v[0], x3v[2]]))]) reg2([xx.T]) reg2([tr(xx)]) reg2([det(xx)]) reg2([dot(xx, 0.1 * xx)]) reg2([outer(xx, xx.T)]) reg2([dev(xx)]) reg2([sym(xx)]) reg2([skew(xx)]) reg2([elem_mult(7 * xx, cc)]) reg2([elem_div(7 * xx, xx + cc)]) reg2([elem_pow(1e-3 * xx, 1e-3 * cc)]) reg2([elem_pow(1e-3 * cc, 1e-3 * xx)]) reg2([elem_op(lambda z: sin(z) + 2, 0.03 * xx)], 2) # pretty inaccurate... # FIXME: Add tests for all UFL operators: # These cause discontinuities and may be harder to test in the # above fashion: # 'inv', 'cofac', # 'eq', 'ne', 'le', 'ge', 'lt', 'gt', 'And', 'Or', 'Not', # 'conditional', 'sign', # 'jump', 'avg', # 'LiftingFunction', 'LiftingOperator', # FIXME: Test other derivatives: (but algorithms for operator # derivatives are the same!): # 'variable', 'diff', # 'Dx', 'grad', 'div', 'curl', 'rot', 'Dn', 'exterior_derivative', # Run through all operators defined above and compare integrals debug = 0 for F, acc in F_list: # Apply UFL differentiation f = diff(F, SpatialCoordinate(mesh))[..., 0] if debug: print(F) print(x) print(f) # Apply integration with DOLFIN # (also passes through form compilation and jit) M = f * dx f_integral = assemble_scalar(M) # noqa f_integral = MPI.sum(mesh.mpi_comm(), f_integral) # Compute integral of f manually from anti-derivative F # (passes through PyDOLFIN interface and uses UFL evaluation) F_diff = F((x1, )) - F((x0, )) # Compare results. Using custom relative delta instead # of decimal digits here because some numbers are >> 1. delta = min(abs(f_integral), abs(F_diff)) * 10**-acc assert f_integral - F_diff <= delta
def test_div_grad_then_integrate_over_cells_and_boundary(): # Define 2D geometry n = 10 mesh = RectangleMesh(Point(0.0, 0.0), Point(2.0, 3.0), 2 * n, 3 * n) x, y = SpatialCoordinate(mesh) xs = 0.1 + 0.8 * x / 2 # scaled to be within [0.1,0.9] # ys = 0.1 + 0.8 * y / 3 # scaled to be within [0.1,0.9] n = FacetNormal(mesh) # Define list of expressions to test, and configure accuracies # these expressions are known to pass with. The reason some # functions are less accurately integrated is likely that the # default choice of quadrature rule is not perfect F_list = [] def reg(exprs, acc=10): for expr in exprs: F_list.append((expr, acc)) # FIXME: 0*dx and 1*dx fails in the ufl-ffc-jit framework somewhere # reg([Constant(0.0, cell=cell)]) # reg([Constant(1.0, cell=cell)]) monomial_list = [x**q for q in range(2, 6)] reg(monomial_list) reg([2.3 * p + 4.5 * q for p in monomial_list for q in monomial_list]) reg([xs**xs]) reg( [xs**(xs**2)], 8 ) # Note: Accuracies here are from 1D case, not checked against 2D results. reg([xs**(xs**3)], 6) reg([xs**(xs**4)], 2) # Special functions: reg([atan(xs)], 8) reg([sin(x), cos(x), exp(x)], 5) reg([ln(xs), pow(x, 2.7), pow(2.7, x)], 3) reg([asin(xs), acos(xs)], 1) reg([tan(xs)], 7) # To handle tensor algebra, make an x dependent input tensor # xx and square all expressions def reg2(exprs, acc=10): for expr in exprs: F_list.append((inner(expr, expr), acc)) xx = as_matrix([[2 * x**2, 3 * x**3], [11 * x**5, 7 * x**4]]) xxs = as_matrix([[2 * xs**2, 3 * xs**3], [11 * xs**5, 7 * xs**4]]) x3v = as_vector([3 * x**2, 5 * x**3, 7 * x**4]) cc = as_matrix([[2, 3], [4, 5]]) reg2( [xx] ) # TODO: Make unit test for UFL from this, results in listtensor with free indices reg2([x3v]) reg2([cross(3 * x3v, as_vector([-x3v[1], x3v[0], x3v[2]]))]) reg2([xx.T]) reg2([tr(xx)]) reg2([det(xx)]) reg2([dot(xx, 0.1 * xx)]) reg2([outer(xx, xx.T)]) reg2([dev(xx)]) reg2([sym(xx)]) reg2([skew(xx)]) reg2([elem_mult(7 * xx, cc)]) reg2([elem_div(7 * xx, xx + cc)]) reg2([elem_pow(1e-3 * xxs, 1e-3 * cc)]) reg2([elem_pow(1e-3 * cc, 1e-3 * xx)]) reg2([elem_op(lambda z: sin(z) + 2, 0.03 * xx)], 2) # pretty inaccurate... # FIXME: Add tests for all UFL operators: # These cause discontinuities and may be harder to test in the # above fashion: # 'inv', 'cofac', # 'eq', 'ne', 'le', 'ge', 'lt', 'gt', 'And', 'Or', 'Not', # 'conditional', 'sign', # 'jump', 'avg', # 'LiftingFunction', 'LiftingOperator', # FIXME: Test other derivatives: (but algorithms for operator # derivatives are the same!): # 'variable', 'diff', # 'Dx', 'grad', 'div', 'curl', 'rot', 'Dn', 'exterior_derivative', # Run through all operators defined above and compare integrals debug = 0 if debug: F_list = F_list[1:] for F, acc in F_list: if debug: print('\n', "F:", str(F)) # Integrate over domain and its boundary int_dx = assemble(div(grad(F)) * dx(mesh)) # noqa int_ds = assemble(dot(grad(F), n) * ds(mesh)) # noqa if debug: print(int_dx, int_ds) # Compare results. Using custom relative delta instead of # decimal digits here because some numbers are >> 1. delta = min(abs(int_dx), abs(int_ds)) * 10**-acc assert int_dx - int_ds <= delta
# + comm = MPI.COMM_SELF # - # Create a mesh and function space msh = mesh.create_rectangle(comm=comm, points=((0.0, 0.0), (2.0, 1.0)), n=(32, 16), cell_type=mesh.CellType.triangle) V = fem.FunctionSpace(msh, ("Lagrange", 1)) # Define a variartional problem u, v = ufl.TrialFunction(V), ufl.TestFunction(V) x = ufl.SpatialCoordinate(msh) fr = 10 * ufl.exp(-((x[0] - 0.5) ** 2 + (x[1] - 0.5) ** 2) / 0.02) fc = ufl.sin(2 * np.pi * x[0]) + 10 * ufl.sin(4 * np.pi * x[1]) * 1j gr = ufl.sin(5 * x[0]) gc = ufl.sin(5 * x[0]) * 1j a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx L = ufl.inner(fr + fc, v) * ufl.dx + ufl.inner(gr + gc, v) * ufl.ds # In preparation for constructing Dirichlet boundary conditions, locate # facets on the constrained boundary and the corresponding # degrees-of-freedom facets = mesh.locate_entities_boundary(msh, dim=1, marker=lambda x: np.logical_or(np.isclose(x[0], 0.0), np.isclose(x[0], 2.0))) dofs = fem.locate_dofs_topological(V=V, entity_dim=1, entities=facets)
# DERIVATIVE with respect to arc-length coordinate s of straight reference configuration: du/ds = du/dx * dx/dr * dr/ds def GRAD(u): return ufl.dot(ufl.grad(u), J0[:, 0]) * 1 / ufl.geometry.JacobianDeterminant(mesh) # Undeformed configuration: stretch (at the principal axis) λ0 = ufl.sqrt(ufl.dot(GRAD(x0), GRAD(x0))) # from geometry (!= 1) # Undeformed configuration: curvature κ0 = -B0i[0, 0] # from curvature tensor B0i # Deformed configuration: stretch components (at the principal axis) λs = (1.0 + GRAD(x0[0]) * GRAD(u) + GRAD(x0[2]) * GRAD(w)) * ufl.cos(r) + \ (GRAD(x0[2]) * GRAD(u) - GRAD(x0[0]) * GRAD(w)) * ufl.sin(r) λξ = (1.0 + GRAD(x0[0]) * GRAD(u) + GRAD(x0[2]) * GRAD(w)) * ufl.sin(r) - \ (GRAD(x0[2]) * GRAD(u) - GRAD(x0[0]) * GRAD(w)) * ufl.cos(r) # Deformed configuration: curvature κ = GRAD(r) # Green-Lagrange strains (total): determined by deformation kinematics e_total = 1 / 2 * (λs**2 + λξ**2 - λ0**2) g_total = λξ k_total = λs * κ + (λs - λ0) * κ0 # Green-Lagrange strains (elastic): e_total = e_elast + e_presc e = e_elast = e_total g = g_elast = g_total k = k_elast = k_total
x0 = np.ones(W.dim()) res = minimize( min_f, x0, method="L-BFGS-B", jac=True, tol=1e-9, bounds=((0, 0.8),) * W.dim(), options={"gtol": 1e-10, "ftol": 0, "disp": True, "maxiter": 50}, ) # Define the expressions of the analytical solution alpha = 1e-6 x = ufl.SpatialCoordinate(mesh) w = ufl.sin(ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) f_analytic = 1 / (1 + alpha * 4 * ufl.pi ** 4) * w u_analytic = 1 / (2 * ufl.pi ** 2) * f_analytic f_opt = from_numpy(res.x, fn.Function(W)) u = fn.Function(V) v = fn.TestFunction(V) F = (ufl.inner(ufl.grad(u), ufl.grad(v)) - f_opt * v) * ufl.dx bc = fn.DirichletBC(V, 0.0, "on_boundary") fn.solve(F == 0, u, bc) print(f"norm of f_opt is {fn.norm(f_opt)}") # interpolatation of UFL forms does not work in FEniCS, hence projection CG3 = fn.FunctionSpace(mesh, "CG", 3) control_error = fn.errornorm(fn.project(f_analytic, CG3), f_opt) state_error = fn.errornorm(fn.project(u_analytic, CG3), u)
# condition. # <codecell> from ufl import sin from dune.ufl import DirichletBC from dune.fem.plotting import plotComponents from matplotlib import ticker vecSpace = solutionSpace(gridView, dimRange=2, order=2) x = SpatialCoordinate(vecSpace) vec = vecSpace.interpolate([0,0], name='u_h') uVec,vVec = TrialFunction(vecSpace), TestFunction(vecSpace) a = ( inner(grad(uVec), grad(vVec)) + inner(uVec,vVec) ) * dx f = ( uVec[0]*(1-uVec[1])*vVec[0] + uVec[1]*(1-uVec[0])*vVec[1] ) * dx f = f + uVec[0]*uVec[0] * vVec[1] * ds bc = DirichletBC(vecSpace,[sin(4*(x[0]+x[1])),None]) vecScheme = solutionScheme( [a == f, bc], parameters={"newton.linear.tolerance": 1e-9} ) vecScheme.solve(target=vec) plotComponents(vec, gridLines=None, level=2, colorbar={"orientation":"horizontal", "ticks":ticker.MaxNLocator(nbins=4)}) # <markdowncell> # To prescribe $u_2=0$ at the bottom boundary is also straightforward # <codecell> bcBottom = DirichletBC(vecSpace,[sin(4*(x[0]+x[1])),0],x[1]<1e-10) vecScheme = solutionScheme( [a == f, bc, bcBottom], parameters={"newton.linear.tolerance": 1e-9} ) vecScheme.solve(target=vec) plotComponents(vec, gridLines=None, level=2,
from dune.fem.scheme import galerkin as solutionScheme order = 3 storage = "istl" # setup reference surface referenceView = leafGridView("sphere.dgf", dimgrid=2, dimworld=3) space = solutionSpace(referenceView, dimRange=referenceView.dimWorld, order=order, storage=storage) # setup deformed surface x = ufl.SpatialCoordinate(space) # positions = space.interpolate(x, name="position") positions = space.interpolate( x * (1 + 0.5 * sin(2 * pi * (x[0] + x[1])) * cos(0.25 * pi * x[2])), name="position") gridView = geometryGridView(positions) space = solutionSpace(gridView, dimRange=gridView.dimWorld, order=order, storage=storage) u = ufl.TrialFunction(space) phi = ufl.TestFunction(space) dt = dune.ufl.Constant(0.01, "timeStep") t = dune.ufl.Constant(0.0, "time") # define storage for discrete solutions uh = space.interpolate(x, name="uh") uh_old = uh.copy()
def test_pipeline(u_from_mpc): # Create mesh and function space mesh = create_unit_square(MPI.COMM_WORLD, 5, 5) V = fem.FunctionSpace(mesh, ("Lagrange", 1)) # Solve Problem without MPC for reference u = ufl.TrialFunction(V) v = ufl.TestFunction(V) d = fem.Constant(mesh, PETSc.ScalarType(0.01)) x = ufl.SpatialCoordinate(mesh) f = ufl.sin(2 * ufl.pi * x[0]) * ufl.sin(ufl.pi * x[1]) a = ufl.inner(ufl.grad(u), ufl.grad(v)) * ufl.dx - d * ufl.inner(u, v) * ufl.dx rhs = ufl.inner(f, v) * ufl.dx bilinear_form = fem.form(a) linear_form = fem.form(rhs) # Generate reference matrices A_org = fem.petsc.assemble_matrix(bilinear_form) A_org.assemble() L_org = fem.petsc.assemble_vector(linear_form) L_org.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE) # Create multipoint constraint def periodic_relation(x): out_x = np.copy(x) out_x[0] = 1 - x[0] return out_x def PeriodicBoundary(x): return np.isclose(x[0], 1) facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, PeriodicBoundary) arg_sort = np.argsort(facets) mt = meshtags(mesh, mesh.topology.dim - 1, facets[arg_sort], np.full(len(facets), 2, dtype=np.int32)) mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_periodic_constraint_topological(V, mt, 2, periodic_relation, [], 1) mpc.finalize() if u_from_mpc: uh = fem.Function(mpc.function_space) problem = dolfinx_mpc.LinearProblem(bilinear_form, linear_form, mpc, bcs=[], u=uh, petsc_options={"ksp_type": "preonly", "pc_type": "lu"}) problem.solve() root = 0 dolfinx_mpc.utils.compare_mpc_lhs(A_org, problem.A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(L_org, problem.b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(A_org, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(L_org, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(uh.vector, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc) else: uh = fem.Function(V) with pytest.raises(ValueError): problem = dolfinx_mpc.LinearProblem(bilinear_form, linear_form, mpc, bcs=[], u=uh, petsc_options={"ksp_type": "preonly", "pc_type": "lu"}) problem.solve()
# Interpolate curvature tensor dolfiny.interpolation.interpolate(B0, B0i) # ---------------------------------------------------------------------------- # DERIVATIVE with respect to arc-length coordinate s of straight reference configuration: du/ds = du/dx * dx/dr * dr/ds GRAD = lambda u: ufl.dot(ufl.grad( u), J0[:, 0]) * 1 / ufl.geometry.JacobianDeterminant(mesh) # noqa: E731 # Undeformed configuration: stretch (at the principal axis) λ0 = ufl.sqrt(ufl.dot(GRAD(x0), GRAD(x0))) # from geometry (!= 1) # Undeformed configuration: curvature κ0 = -B0i[0, 0] # from curvature tensor B0i # Deformed configuration: stretch components (at the principal axis) λs = (1.0 + GRAD(x0[0]) * GRAD(u) + GRAD(x0[2]) * GRAD(w)) * ufl.cos(r) + \ ( GRAD(x0[2]) * GRAD(u) - GRAD(x0[0]) * GRAD(w)) * ufl.sin(r) # noqa: E201 λξ = (1.0 + GRAD(x0[0]) * GRAD(u) + GRAD(x0[2]) * GRAD(w)) * ufl.sin(r) - \ ( GRAD(x0[2]) * GRAD(u) - GRAD(x0[0]) * GRAD(w)) * ufl.cos(r) # noqa: E201 # Deformed configuration: curvature κ = GRAD(r) # Reissner strains (total): determined by deformation kinematics ε_total = λs - λ0 γ_total = λξ κ_total = κ # Reissner strains (elastic): e_total = e_elast + e_presc ε = ε_elast = ε_total γ = γ_elast = γ_total κ = κ_elast = κ_total
# This example is based on # http://www.dolfin-adjoint.org/en/latest/documentation/tutorial.html import firedrake as fd from firedrake.petsc import PETSc from firedrake import dmhooks import ufl import firedrake_ts equation = "burgers" # 'burgers' or 'heat' n = 50 mesh = fd.UnitSquareMesh(n, n) V = fd.VectorFunctionSpace(mesh, "CG", 2) x = ufl.SpatialCoordinate(mesh) expr = ufl.as_vector([ufl.sin(2 * ufl.pi * x[0]), ufl.cos(2 * ufl.pi * x[1])]) u = fd.interpolate(expr, V) u_dot = fd.Function(V) v = fd.TestFunction(V) nu = fd.Constant(0.0001) # for burgers if equation == "heat": nu = fd.Constant(0.1) # for heat M = fd.derivative(fd.inner(u, v) * fd.dx, u) R = -(fd.inner(fd.grad(u) * u, v) + nu * fd.inner(fd.grad(u), fd.grad(v))) * fd.dx if equation == "heat": R = -nu * fd.inner(fd.grad(u), fd.grad(v)) * fd.dx F = fd.action(M, u_dot) - R
def demo_periodic3D(celltype: CellType): # Create mesh and finite element if celltype == CellType.tetrahedron: # Tet setup N = 10 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N) V = fem.VectorFunctionSpace(mesh, ("CG", 1)) else: # Hex setup N = 10 mesh = create_unit_cube(MPI.COMM_WORLD, N, N, N, CellType.hexahedron) V = fem.VectorFunctionSpace(mesh, ("CG", 2)) def dirichletboundary(x: NDArray[np.float64]) -> NDArray[np.bool_]: return np.logical_or( np.logical_or(np.isclose(x[1], 0), np.isclose(x[1], 1)), np.logical_or(np.isclose(x[2], 0), np.isclose(x[2], 1))) # Create Dirichlet boundary condition zero = PETSc.ScalarType([0, 0, 0]) geometrical_dofs = fem.locate_dofs_geometrical(V, dirichletboundary) bc = fem.dirichletbc(zero, geometrical_dofs, V) bcs = [bc] def PeriodicBoundary(x): return np.isclose(x[0], 1) facets = locate_entities_boundary(mesh, mesh.topology.dim - 1, PeriodicBoundary) arg_sort = np.argsort(facets) mt = meshtags(mesh, mesh.topology.dim - 1, facets[arg_sort], np.full(len(facets), 2, dtype=np.int32)) def periodic_relation(x): out_x = np.zeros(x.shape) out_x[0] = 1 - x[0] out_x[1] = x[1] out_x[2] = x[2] return out_x with Timer("~~Periodic: Compute mpc condition"): mpc = dolfinx_mpc.MultiPointConstraint(V) mpc.create_periodic_constraint_topological(V.sub(0), mt, 2, periodic_relation, bcs, 1) mpc.finalize() # Define variational problem u = TrialFunction(V) v = TestFunction(V) a = inner(grad(u), grad(v)) * dx x = SpatialCoordinate(mesh) dx_ = x[0] - 0.9 dy_ = x[1] - 0.5 dz_ = x[2] - 0.1 f = as_vector((x[0] * sin(5.0 * pi * x[1]) + 1.0 * exp(-(dx_ * dx_ + dy_ * dy_ + dz_ * dz_) / 0.02), 0.1 * dx_ * dz_, 0.1 * dx_ * dy_)) rhs = inner(f, v) * dx petsc_options: Dict[str, Union[str, float, int]] if complex_mode: rtol = 1e-16 petsc_options = {"ksp_type": "preonly", "pc_type": "lu"} else: rtol = 1e-8 petsc_options = { "ksp_type": "cg", "ksp_rtol": rtol, "pc_type": "hypre", "pc_hypre_typ": "boomeramg", "pc_hypre_boomeramg_max_iter": 1, "pc_hypre_boomeramg_cycle_type": "v", "pc_hypre_boomeramg_print_statistics": 1 } problem = LinearProblem(a, rhs, mpc, bcs, petsc_options=petsc_options) u_h = problem.solve() # --------------------VERIFICATION------------------------- print("----Verification----") u_ = fem.Function(V) u_.x.array[:] = 0 org_problem = fem.petsc.LinearProblem(a, rhs, u=u_, bcs=bcs, petsc_options=petsc_options) with Timer("~Periodic: Unconstrained solve"): org_problem.solve() it = org_problem.solver.getIterationNumber() print(f"Unconstrained solver iterations: {it}") # Write solutions to file ext = "tet" if celltype == CellType.tetrahedron else "hex" u_.name = "u_" + ext + "_unconstrained" # NOTE: Workaround as tabulate dof coordinates does not like extra ghosts u_out = fem.Function(V) old_local = u_out.x.map.size_local * u_out.x.bs old_ghosts = u_out.x.map.num_ghosts * u_out.x.bs mpc_local = u_h.x.map.size_local * u_h.x.bs assert (old_local == mpc_local) u_out.x.array[:old_local + old_ghosts] = u_h.x.array[:mpc_local + old_ghosts] u_out.name = "u_" + ext fname = f"results/demo_periodic3d_{ext}.bp" out_periodic = VTXWriter(MPI.COMM_WORLD, fname, u_out) out_periodic.write(0) out_periodic.close() root = 0 with Timer("~Demo: Verification"): dolfinx_mpc.utils.compare_mpc_lhs(org_problem.A, problem.A, mpc, root=root) dolfinx_mpc.utils.compare_mpc_rhs(org_problem.b, problem.b, mpc, root=root) # Gather LHS, RHS and solution on one process A_csr = dolfinx_mpc.utils.gather_PETScMatrix(org_problem.A, root=root) K = dolfinx_mpc.utils.gather_transformation_matrix(mpc, root=root) L_np = dolfinx_mpc.utils.gather_PETScVector(org_problem.b, root=root) u_mpc = dolfinx_mpc.utils.gather_PETScVector(u_h.vector, root=root) if MPI.COMM_WORLD.rank == root: KTAK = K.T * A_csr * K reduced_L = K.T @ L_np # Solve linear system d = scipy.sparse.linalg.spsolve(KTAK, reduced_L) # Back substitution to full solution vector uh_numpy = K @ d assert np.allclose(uh_numpy, u_mpc, rtol=rtol)
def compute(space, epsilon, weakBnd, skeleton, mol=None): u = TrialFunction(space) v = TestFunction(space) n = FacetNormal(space) he = avg(CellVolume(space)) / FacetArea(space) hbnd = CellVolume(space) / FacetArea(space) x = SpatialCoordinate(space) exact = uflFunction(space.gridView, name="exact", order=3, ufl=sin(x[0] * x[1])) uh = space.interpolate(exact, name="solution") # diffusion factor eps = Constant(epsilon, "eps") # transport direction and upwind flux b = as_vector([1, 0]) hatb = (dot(b, n) + abs(dot(b, n))) / 2.0 # characteristic function for left/right boundary dD = conditional((1 + x[0]) * (1 - x[0]) < 1e-10, 1, 0) # penalty parameter beta = Constant(20 * space.order**2, "beta") rhs = -(div(eps * grad(exact) - b * exact)) * v * dx aInternal = dot(eps * grad(u) - b * u, grad(v)) * dx aInternal -= eps * dot(grad(exact), n) * v * (1 - dD) * ds diffSkeleton = eps*beta/he*jump(u)*jump(v)*dS -\ eps*dot(avg(grad(u)),n('+'))*jump(v)*dS -\ eps*jump(u)*dot(avg(grad(v)),n('+'))*dS if weakBnd: diffSkeleton += eps*beta/hbnd*(u-exact)*v*dD*ds -\ eps*dot(grad(exact),n)*v*dD*ds advSkeleton = jump(hatb * u) * jump(v) * dS if weakBnd: advSkeleton += (hatb * u + (dot(b, n) - hatb) * exact) * v * dD * ds if skeleton: form = aInternal + diffSkeleton + advSkeleton else: form = aInternal if weakBnd and skeleton: strongBC = None else: strongBC = DirichletBC(space, exact, dD) if space.storage[0] == "numpy": solver = { "solver": ("suitesparse", "umfpack"), "parameters": { "newton.verbose": True, "newton.linear.verbose": False, "newton.linear.tolerance": 1e-5, } } else: solver = { "solver": "bicgstab", "parameters": { "newton.linear.preconditioning.method": "ilu", "newton.linear.tolerance": 1e-13, "newton.verbose": True, "newton.linear.verbose": False } } if mol == 'mol': scheme = molSolutionScheme([form == rhs, strongBC], **solver) else: scheme = solutionScheme([form == rhs, strongBC], **solver) eoc = [] info = scheme.solve(target=uh) error = dot(uh - exact, uh - exact) error0 = math.sqrt(integrate(gridView, error, order=5)) print(error0, " # output", flush=True) for i in range(3): gridView.hierarchicalGrid.globalRefine(1) uh.interpolate(exact) scheme.solve(target=uh) error = dot(uh - exact, uh - exact) error1 = math.sqrt(integrate(gridView, error, order=5)) eoc += [math.log(error1 / error0) / math.log(0.5)] print(i, error0, error1, eoc, " # output", flush=True) error0 = error1 # print(space.order,epsilon,eoc) if (eoc[-1] - (space.order + 1)) < -0.1: print("ERROR:", space.order, epsilon, eoc) return eoc