|
36 | 36 | from festim.helpers import as_fenics_constant, get_interpolation_points |
37 | 37 | from festim.mesh import Mesh |
38 | 38 |
|
39 | | -__all__ = ["HTransportProblemDiscontinuous", "HydrogenTransportProblem"] |
| 39 | +__all__ = ["HydrogenTransportProblemDiscontinuous", "HydrogenTransportProblem"] |
40 | 40 |
|
41 | 41 |
|
42 | 42 | class HydrogenTransportProblem(problem.ProblemBase): |
@@ -948,10 +948,10 @@ def post_processing(self): |
948 | 948 | vtxfile.write(float(self.t)) |
949 | 949 |
|
950 | 950 |
|
951 | | -class HTransportProblemDiscontinuous(HydrogenTransportProblem): |
| 951 | +class HydrogenTransportProblemDiscontinuous(HydrogenTransportProblem): |
952 | 952 | interfaces: list[_subdomain.Interface] |
953 | | - petsc_options: dict |
954 | 953 | surface_to_volume: dict |
| 954 | + method_interface: str = "penalty" |
955 | 955 |
|
956 | 956 | def __init__( |
957 | 957 | self, |
@@ -1002,15 +1002,10 @@ def __init__( |
1002 | 1002 | settings, |
1003 | 1003 | exports, |
1004 | 1004 | traps, |
| 1005 | + petsc_options=petsc_options, |
1005 | 1006 | ) |
1006 | 1007 | self.interfaces = interfaces or [] |
1007 | 1008 | self.surface_to_volume = surface_to_volume or {} |
1008 | | - default_petsc_options = { |
1009 | | - "ksp_type": "preonly", |
1010 | | - "pc_type": "lu", |
1011 | | - "pc_factor_mat_solver_type": "mumps", |
1012 | | - } |
1013 | | - self.petsc_options = petsc_options or default_petsc_options |
1014 | 1009 | self._vtxfiles: list[dolfinx.io.VTXWriter] = [] |
1015 | 1010 |
|
1016 | 1011 | def initialise(self): |
@@ -1343,36 +1338,79 @@ def mixed_term(u, v, n): |
1343 | 1338 | self.mesh.mesh, self.temperature_fenics(res[1]), H |
1344 | 1339 | ) |
1345 | 1340 |
|
1346 | | - F_0 = -0.5 * mixed_term((u_b + u_t), v_b, n_0) * dInterface( |
1347 | | - interface.id |
1348 | | - ) - 0.5 * mixed_term(v_b, (u_b / K_b - u_t / K_t), n_0) * dInterface( |
1349 | | - interface.id |
1350 | | - ) |
| 1341 | + if self.method_interface == "penalty": |
| 1342 | + if ( |
| 1343 | + subdomain_0.material.solubility_law |
| 1344 | + == subdomain_1.material.solubility_law |
| 1345 | + ): |
| 1346 | + left = u_b / K_b |
| 1347 | + right = u_t / K_t |
| 1348 | + else: |
| 1349 | + if subdomain_0.material.solubility_law == "henry": |
| 1350 | + left = u_b / K_b |
| 1351 | + elif subdomain_0.material.solubility_law == "sievert": |
| 1352 | + left = (u_b / K_b) ** 2 |
| 1353 | + else: |
| 1354 | + raise ValueError( |
| 1355 | + f"Unknown material law {subdomain_0.material.solubility_law}" |
| 1356 | + ) |
1351 | 1357 |
|
1352 | | - F_1 = +0.5 * mixed_term((u_b + u_t), v_t, n_0) * dInterface( |
1353 | | - interface.id |
1354 | | - ) - 0.5 * mixed_term(v_t, (u_b / K_b - u_t / K_t), n_0) * dInterface( |
1355 | | - interface.id |
1356 | | - ) |
1357 | | - F_0 += ( |
1358 | | - 2 |
1359 | | - * gamma |
1360 | | - / (h_0 + h_1) |
1361 | | - * (u_b / K_b - u_t / K_t) |
1362 | | - * v_b |
1363 | | - * dInterface(interface.id) |
1364 | | - ) |
1365 | | - F_1 += ( |
1366 | | - -2 |
1367 | | - * gamma |
1368 | | - / (h_0 + h_1) |
1369 | | - * (u_b / K_b - u_t / K_t) |
1370 | | - * v_t |
1371 | | - * dInterface(interface.id) |
1372 | | - ) |
| 1358 | + if subdomain_1.material.solubility_law == "henry": |
| 1359 | + right = u_t / K_t |
| 1360 | + elif subdomain_1.material.solubility_law == "sievert": |
| 1361 | + right = (u_t / K_t) ** 2 |
| 1362 | + else: |
| 1363 | + raise ValueError( |
| 1364 | + f"Unknown material law {subdomain_1.material.solubility_law}" |
| 1365 | + ) |
| 1366 | + |
| 1367 | + equality = right - left |
1373 | 1368 |
|
1374 | | - subdomain_0.F += F_0 |
1375 | | - subdomain_1.F += F_1 |
| 1369 | + F_0 = ( |
| 1370 | + interface.penalty_term |
| 1371 | + * ufl.inner(equality, v_b) |
| 1372 | + * dInterface(interface.id) |
| 1373 | + ) |
| 1374 | + F_1 = ( |
| 1375 | + -interface.penalty_term |
| 1376 | + * ufl.inner(equality, v_t) |
| 1377 | + * dInterface(interface.id) |
| 1378 | + ) |
| 1379 | + |
| 1380 | + subdomain_0.F += F_0 |
| 1381 | + subdomain_1.F += F_1 |
| 1382 | + |
| 1383 | + elif self.method_interface == "nietsche": |
| 1384 | + F_0 = -0.5 * mixed_term((u_b + u_t), v_b, n_0) * dInterface( |
| 1385 | + interface.id |
| 1386 | + ) - 0.5 * mixed_term(v_b, (u_b / K_b - u_t / K_t), n_0) * dInterface( |
| 1387 | + interface.id |
| 1388 | + ) |
| 1389 | + |
| 1390 | + F_1 = +0.5 * mixed_term((u_b + u_t), v_t, n_0) * dInterface( |
| 1391 | + interface.id |
| 1392 | + ) - 0.5 * mixed_term(v_t, (u_b / K_b - u_t / K_t), n_0) * dInterface( |
| 1393 | + interface.id |
| 1394 | + ) |
| 1395 | + F_0 += ( |
| 1396 | + 2 |
| 1397 | + * gamma |
| 1398 | + / (h_0 + h_1) |
| 1399 | + * (u_b / K_b - u_t / K_t) |
| 1400 | + * v_b |
| 1401 | + * dInterface(interface.id) |
| 1402 | + ) |
| 1403 | + F_1 += ( |
| 1404 | + -2 |
| 1405 | + * gamma |
| 1406 | + / (h_0 + h_1) |
| 1407 | + * (u_b / K_b - u_t / K_t) |
| 1408 | + * v_t |
| 1409 | + * dInterface(interface.id) |
| 1410 | + ) |
| 1411 | + |
| 1412 | + subdomain_0.F += F_0 |
| 1413 | + subdomain_1.F += F_1 |
1376 | 1414 |
|
1377 | 1415 | J = [] |
1378 | 1416 | # this is the symbolic differentiation of the Jacobian |
@@ -1520,110 +1558,6 @@ def __del__(self): |
1520 | 1558 | vtxfile.close() |
1521 | 1559 |
|
1522 | 1560 |
|
1523 | | -class HTransportProblemPenalty(HTransportProblemDiscontinuous): |
1524 | | - def create_formulation(self): |
1525 | | - """ |
1526 | | - Takes all the formulations for each subdomain and adds the interface conditions. |
1527 | | -
|
1528 | | - Finally compute the jacobian matrix and store it in the ``J`` attribute, |
1529 | | - adds the ``entity_maps`` to the forms and store them in the ``forms`` attribute |
1530 | | - """ |
1531 | | - mesh = self.mesh.mesh |
1532 | | - mt = self.facet_meshtags |
1533 | | - |
1534 | | - for interface in self.interfaces: |
1535 | | - interface.mesh = mesh |
1536 | | - interface.mt = mt |
1537 | | - |
1538 | | - integral_data = [ |
1539 | | - interface.compute_mapped_interior_facet_data(mesh) |
1540 | | - for interface in self.interfaces |
1541 | | - ] |
1542 | | - [interface.pad_parent_maps() for interface in self.interfaces] |
1543 | | - dInterface = ufl.Measure("dS", domain=mesh, subdomain_data=integral_data) |
1544 | | - |
1545 | | - entity_maps = { |
1546 | | - sd.submesh: sd.parent_to_submesh for sd in self.volume_subdomains |
1547 | | - } |
1548 | | - for interface in self.interfaces: |
1549 | | - subdomain_0, subdomain_1 = interface.subdomains |
1550 | | - res = interface.restriction |
1551 | | - |
1552 | | - all_mobile_species = [spe for spe in self.species if spe.mobile] |
1553 | | - if len(all_mobile_species) > 1: |
1554 | | - raise NotImplementedError("Multiple mobile species not implemented") |
1555 | | - H = all_mobile_species[0] |
1556 | | - v_b = H.subdomain_to_test_function[subdomain_0](res[0]) |
1557 | | - v_t = H.subdomain_to_test_function[subdomain_1](res[1]) |
1558 | | - |
1559 | | - u_b = H.subdomain_to_solution[subdomain_0](res[0]) |
1560 | | - u_t = H.subdomain_to_solution[subdomain_1](res[1]) |
1561 | | - |
1562 | | - K_b = subdomain_0.material.get_solubility_coefficient( |
1563 | | - self.mesh.mesh, self.temperature_fenics(res[0]), H |
1564 | | - ) |
1565 | | - K_t = subdomain_1.material.get_solubility_coefficient( |
1566 | | - self.mesh.mesh, self.temperature_fenics(res[1]), H |
1567 | | - ) |
1568 | | - |
1569 | | - if ( |
1570 | | - subdomain_0.material.solubility_law |
1571 | | - == subdomain_1.material.solubility_law |
1572 | | - ): |
1573 | | - left = u_b / K_b |
1574 | | - right = u_t / K_t |
1575 | | - else: |
1576 | | - if subdomain_0.material.solubility_law == "henry": |
1577 | | - left = u_b / K_b |
1578 | | - elif subdomain_0.material.solubility_law == "sievert": |
1579 | | - left = (u_b / K_b) ** 2 |
1580 | | - else: |
1581 | | - raise ValueError( |
1582 | | - f"Unknown material law {subdomain_0.material.solubility_law}" |
1583 | | - ) |
1584 | | - |
1585 | | - if subdomain_1.material.solubility_law == "henry": |
1586 | | - right = u_t / K_t |
1587 | | - elif subdomain_1.material.solubility_law == "sievert": |
1588 | | - right = (u_t / K_t) ** 2 |
1589 | | - else: |
1590 | | - raise ValueError( |
1591 | | - f"Unknown material law {subdomain_1.material.solubility_law}" |
1592 | | - ) |
1593 | | - |
1594 | | - equality = right - left |
1595 | | - |
1596 | | - F_0 = ( |
1597 | | - interface.penalty_term |
1598 | | - * ufl.inner(equality, v_b) |
1599 | | - * dInterface(interface.id) |
1600 | | - ) |
1601 | | - F_1 = ( |
1602 | | - -interface.penalty_term |
1603 | | - * ufl.inner(equality, v_t) |
1604 | | - * dInterface(interface.id) |
1605 | | - ) |
1606 | | - |
1607 | | - subdomain_0.F += F_0 |
1608 | | - subdomain_1.F += F_1 |
1609 | | - |
1610 | | - J = [] |
1611 | | - # this is the symbolic differentiation of the Jacobian |
1612 | | - for subdomain1 in self.volume_subdomains: |
1613 | | - jac = [] |
1614 | | - for subdomain2 in self.volume_subdomains: |
1615 | | - jac.append( |
1616 | | - ufl.derivative(subdomain1.F, subdomain2.u), |
1617 | | - ) |
1618 | | - J.append(jac) |
1619 | | - # compile jacobian (J) and residual (F) |
1620 | | - self.forms = dolfinx.fem.form( |
1621 | | - [subdomain.F for subdomain in self.volume_subdomains], |
1622 | | - entity_maps=entity_maps, |
1623 | | - ) |
1624 | | - self.J = dolfinx.fem.form(J, entity_maps=entity_maps) |
1625 | | - |
1626 | | - |
1627 | 1561 | class HydrogenTransportProblemDiscontinuousChangeVar(HydrogenTransportProblem): |
1628 | 1562 | species: List[_species.Species] |
1629 | 1563 |
|
|
0 commit comments