|
1 | 1 | from mpi4py import MPI |
2 | 2 |
|
3 | 3 | import dolfinx |
| 4 | +import ufl |
4 | 5 | import numpy as np |
5 | 6 | import pytest |
6 | 7 |
|
7 | 8 | import festim as F |
8 | 9 |
|
9 | 10 | from .test_multi_mat_penalty import generate_mesh |
| 11 | +from .tools import error_L2 |
10 | 12 |
|
11 | 13 |
|
12 | 14 | def test_petsc_options(): |
@@ -389,3 +391,75 @@ def test_sub_temperature_as_function_mixed_domain_not_updated(): |
389 | 391 | my_model.run() |
390 | 392 |
|
391 | 393 | assert not np.allclose(avg_surf.data, 4.0) |
| 394 | + |
| 395 | + |
| 396 | +def test_MMS_weak_dirichlet(): |
| 397 | + """ |
| 398 | + MMS test with one mobile species at steady state, with Dirichlet BCs enforced weakly. |
| 399 | + """ |
| 400 | + |
| 401 | + def u_exact(mod): |
| 402 | + return lambda x: 1 + mod.sin(2 * mod.pi * x[0]) + mod.cos(2 * mod.pi * x[1]) |
| 403 | + |
| 404 | + H_analytical_ufl = u_exact(ufl) |
| 405 | + H_analytical_np = u_exact(np) |
| 406 | + |
| 407 | + mesh = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, 50, 50) |
| 408 | + |
| 409 | + V = dolfinx.fem.functionspace(mesh, ("Lagrange", 1)) |
| 410 | + T = dolfinx.fem.Function(V) |
| 411 | + |
| 412 | + D_0 = 1 |
| 413 | + E_D = 0.1 |
| 414 | + |
| 415 | + def T_expr(x): |
| 416 | + return 500 + 100 * x[0] |
| 417 | + |
| 418 | + T.interpolate(T_expr) |
| 419 | + D = D_0 * ufl.exp(-E_D / (F.k_B * T)) |
| 420 | + |
| 421 | + my_model = F.HydrogenTransportProblem() |
| 422 | + my_model.mesh = F.Mesh(mesh=mesh) |
| 423 | + |
| 424 | + my_mat = F.Material(name="mat", D_0=D_0, E_D=E_D) |
| 425 | + vol = F.VolumeSubdomain(id=1, material=my_mat) |
| 426 | + left = F.SurfaceSubdomain(id=1, locator=lambda x: np.isclose(x[0], 0)) |
| 427 | + right = F.SurfaceSubdomain(id=2, locator=lambda x: np.isclose(x[0], 1)) |
| 428 | + my_model.subdomains = [vol, left, right] |
| 429 | + |
| 430 | + H = F.Species("H") |
| 431 | + my_model.species = [H] |
| 432 | + |
| 433 | + my_model.temperature = T_expr |
| 434 | + |
| 435 | + my_model.boundary_conditions = [ |
| 436 | + F.FixedConcentrationBC( |
| 437 | + subdomain=left, |
| 438 | + value=H_analytical_ufl, |
| 439 | + species=H, |
| 440 | + enforce_weakly=True, |
| 441 | + penalty=300, |
| 442 | + ), |
| 443 | + F.FixedConcentrationBC( |
| 444 | + subdomain=right, |
| 445 | + value=H_analytical_ufl, |
| 446 | + species=H, |
| 447 | + enforce_weakly=True, |
| 448 | + penalty=300, |
| 449 | + ), |
| 450 | + ] |
| 451 | + |
| 452 | + x = ufl.SpatialCoordinate(mesh) |
| 453 | + f = -ufl.div(D * ufl.grad(H_analytical_ufl(x))) |
| 454 | + my_model.sources = [F.ParticleSource(value=f, volume=vol, species=H)] |
| 455 | + |
| 456 | + my_model.settings = F.Settings(atol=1e-10, rtol=1e-10, transient=False) |
| 457 | + |
| 458 | + my_model.initialise() |
| 459 | + my_model.run() |
| 460 | + |
| 461 | + H_computed = H.post_processing_solution |
| 462 | + |
| 463 | + L2_error = error_L2(H_computed, H_analytical_np) |
| 464 | + |
| 465 | + assert L2_error < 2e-3 |
0 commit comments