Repository: idaholab/moose
Pull request #30443: Handle moving boundary inside a shared top parent of refined elements
Author: login: GiudGiud
Labels: name: PR: Failed but allowed
Created: 2025-05-03T23:36:21Z | Merged: 2025-05-07T03:29:02Z

closes #30275 

this does not work to find active neighbors of an element because of the possibility of being inside the top parent
```
auto neigh = elem->neighbor_ptr(side);
neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
```

@roystgnr maybe you have seen this done differently?

alternatively we could have this routine on the element:
```
  std::vector<const Elem *> active_neighs;
  elem->active_neighbors(active_neighs);
```


Linked issue #30275: Mesh modification: moving boundary does not seem to follow the subdomain changes when using boundary mesh refinement
## Issue
See title and related discussions post.

## How to reproduce
See input file in #30274 and apply the modification listed below

## Impact
External user simulation failures

I also tried to use the `BoundaryPreservedMarker', and it seems to work around the problems, but the `moving boundary` created was not correct. The simulation finally aborted at time step 241 (t=24.1, start of the 7th layer) with `YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault (signal 11)`.

```
[GlobalParams]
  displacements = 'disp_x disp_y'
  use_displaced_mesh = true
[]

[Mesh]
  displacements = 'disp_x disp_y'
[]

  [DirichletBC_top]
    type = DirichletBC
    variable = Temperature
    boundary = 'top_active'
    value = 330.0
    # use_displaced_mesh = false
  []
```
```
    [marker_boundary_preserve]
      block = 1
      type = BoundaryPreservedMarker
      preserved_boundary = 'top_active'
      marker = 'marker_error_frac_von_mises'
    []
```

The white horizontal lines are the moving border. As we can see, there are multiple lines rather than a single line.

**t = 4.1s (start of second layer)**
![image](https://github.com/user-attachments/assets/52fc7eee-fa8a-40c2-88b4-9ebaecc49110)

**t = 8.1s (start of third layer)**
![image](https://github.com/user-attachments/assets/dde9b454-8f49-42c4-8973-edd9689de408)

**t = 12.1s (start of 4th layer)**
![image](https://github.com/user-attachments/assets/8ebc55cd-5f8e-4132-9cd0-9cef35decd99)


**t = 16.1s (start of 5th layer)**
![image](https://github.com/user-attachments/assets/bec91592-483a-4a3a-8e21-cb00186ffd2c)

_Originally posted by @keassyguang in https://github.com/idaholab/moose/discussions/29699#discussioncomment-12763944_

Diff:
diff --git a/framework/src/meshmodifiers/ElementSubdomainModifierBase.C b/framework/src/meshmodifiers/ElementSubdomainModifierBase.C
index ed2e4afaaad2..b807afb339c7 100644
--- a/framework/src/meshmodifiers/ElementSubdomainModifierBase.C
+++ b/framework/src/meshmodifiers/ElementSubdomainModifierBase.C
@@ -314,8 +314,14 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
+          mooseAssert(!neigh->subactive(),
+                      "The case where the active neighbor is an ancestor of this neighbor is not "
+                      "handled at this time.");
+          neigh->active_family_tree_by_neighbor(active_neighs, elem);
+
           for (auto active_neigh : active_neighs)
             gatherMovingBoundaryChangesHelper(elem, side, active_neigh, neigh_side);
         }
@@ -480,6 +486,7 @@ ElementSubdomainModifierBase::findReinitializedElemsAndNodes(
 
   for (const auto & [elem_id, subdomain] : moved_elems)
   {
+    mooseAssert(_mesh.elemPtr(elem_id)->active(), "Moved elements should be active");
     // Default: any element that changes subdomain is reinitialized
     if (std::find(_subdomain_ids_to_reinitialize.begin(),
                   _subdomain_ids_to_reinitialize.end(),
diff --git a/test/tests/meshmodifiers/element_subdomain_modifier/gold/moving_boundary_h_refinement_out.csv b/test/tests/meshmodifiers/element_subdomain_modifier/gold/moving_boundary_h_refinement_out.csv
new file mode 100644
index 000000000000..0cc6b3ed982c
--- /dev/null
+++ b/test/tests/meshmodifiers/element_subdomain_modifier/gold/moving_boundary_h_refinement_out.csv
@@ -0,0 +1,82 @@
+time,area_top,area_top_other
+0,0.004,0.004
+1,0.004,0.004
+2,0.004,0.004
+3,0.004,0.004
+4,0.004,0.004
+5,0.004,0.004
+6,0.004,0.004
+7,0.004,0.004
+8,0.004,0.004
+9,0.004,0.004
+10,0.004,0.004
+11,0.004,0.004
+12,0.004,0.004
+13,0.004,0.004
+14,0.004,0.004
+15,0.004,0.004
+16,0.004,0.004
+17,0.004,0.004
+18,0.004,0.004
+19,0.004,0.004
+20,0.004,0.004
+21,0.004,0.004
+22,0.004,0.004
+23,0.004,0.004
+24,0.004,0.004
+25,0.004,0.004
+26,0.004,0.004
+27,0.004,0.004
+28,0.004,0.004
+29,0.004,0.004
+30,0.004,0.004
+31,0.004,0.004
+32,0.004,0.004
+33,0.004,0.004
+34,0.004,0.004
+35,0.004,0.004
+36,0.004,0.004
+37,0.004,0.004
+38,0.004,0.004
+39,0.004,0.004
+40,0.004,0.004
+41,0.004,0.004
+42,0.004,0.004
+43,0.004,0.004
+44,0.004,0.004
+45,0.004,0.004
+46,0.004,0.004
+47,0.004,0.004
+48,0.004,0.004
+49,0.004,0.004
+50,0.004,0.004
+51,0.004,0.004
+52,0.004,0.004
+53,0.004,0.004
+54,0.004,0.004
+55,0.004,0.004
+56,0.004,0.004
+57,0.004,0.004
+58,0.004,0.004
+59,0.004,0.004
+60,0.004,0.004
+61,0.004,0.004
+62,0.004,0.004
+63,0.004,0.004
+64,0.004,0.004
+65,0.004,0.004
+66,0.004,0.004
+67,0.004,0.004
+68,0.004,0.004
+69,0.004,0.004
+70,0.004,0.004
+71,0.004,0.004
+72,0.004,0.004
+73,0.004,0.004
+74,0.004,0.004
+75,0.004,0.004
+76,0.004,0.004
+77,0.004,0.004
+78,0,0
+79,0,0
+80,0,0
diff --git a/test/tests/meshmodifiers/element_subdomain_modifier/moving_boundary_h_refinement.i b/test/tests/meshmodifiers/element_subdomain_modifier/moving_boundary_h_refinement.i
new file mode 100644
index 000000000000..682a91b5545a
--- /dev/null
+++ b/test/tests/meshmodifiers/element_subdomain_modifier/moving_boundary_h_refinement.i
@@ -0,0 +1,113 @@
+
+[Problem]
+  kernel_coverage_check = false
+  boundary_restricted_node_integrity_check = false
+  boundary_restricted_elem_integrity_check = false
+  type = FEProblem
+[]
+
+[Mesh]
+  [gen]
+    type = GeneratedMeshGenerator
+    dim = 2
+    nx = 5
+    ny = 5
+    xmax = 4e-3
+    ymax = 4e-3
+  []
+  [active_domain] #the initially active domain
+    type = SubdomainBoundingBoxGenerator
+    input = 'gen'
+    block_id = 1
+    bottom_left = '0 0 0'
+    top_right = '4e-3 800e-6 0'
+  []
+  [inactive_domain] #the initially inactive domain
+    type = SubdomainBoundingBoxGenerator
+    input = active_domain
+    block_id = 2
+    bottom_left = '0 800e-6 0'
+    top_right = '4e-3 4e-3 0'
+  []
+  [sideset_top]
+    type = SideSetsBetweenSubdomainsGenerator
+    input = inactive_domain
+    new_boundary = 'sideset_top'
+    paired_block = 2
+    primary_block = 1
+  []
+  [sideset_top_other_side]
+    type = SideSetsBetweenSubdomainsGenerator
+    input = sideset_top
+    new_boundary = 'sideset_top_other_side'
+    paired_block = 1
+    primary_block = 2
+  []
+[]
+
+[Problem]
+  solve = false
+[]
+
+[AuxVariables]
+  [layerY]
+    [AuxKernel]
+      type = ParsedAux
+      expression = 'y - 50e-6 * ceil(t/1.000001)'
+      use_xyzt = true
+      execute_on = 'INITIAL TIMESTEP_BEGIN'
+    []
+  []
+[]
+
+[MeshModifiers]
+  [addLayer]
+    type = CoupledVarThresholdElementSubdomainModifier
+    coupled_var = 'layerY'
+    criterion_type = BELOW
+    threshold = 0
+    subdomain_id = 1
+    moving_boundaries = 'sideset_top sideset_top_other_side'
+    moving_boundary_subdomain_pairs = '1 2; 2 1'
+    execute_on = 'INITIAL TIMESTEP_BEGIN'
+  []
+[]
+
+[Executioner]
+  type = Transient
+  solve_type = PJFNK
+  end_time = 80
+  dt = 1
+  nl_rel_tol = 1e-10
+  nl_abs_tol = 1e-12
+[]
+
+[Outputs]
+  exodus = true
+  csv = true
+[]
+
+[Adaptivity]
+  [Markers]
+    [boundary_moving]
+      type = BoundaryMarker
+      next_to = 'sideset_top'
+      mark = refine
+    []
+  []
+  max_h_level = 3
+  marker = boundary_moving
+[]
+
+[Postprocessors]
+  [area_top]
+    type = AreaPostprocessor
+    boundary = 'sideset_top'
+    execute_on = 'INITIAL TIMESTEP_END'
+  []
+  [area_top_other]
+    type = AreaPostprocessor
+    boundary = 'sideset_top'
+    execute_on = 'INITIAL TIMESTEP_END'
+  []
+[]
diff --git a/test/tests/meshmodifiers/element_subdomain_modifier/tests b/test/tests/meshmodifiers/element_subdomain_modifier/tests
index 7f7c166ca473..b395f79849c2 100644
--- a/test/tests/meshmodifiers/element_subdomain_modifier/tests
+++ b/test/tests/meshmodifiers/element_subdomain_modifier/tests
@@ -1,5 +1,5 @@
 [Tests]
-  issues = '#15795 #17100 #17239 #21383 #27486'
+  issues = '#15795 #17100 #17239 #21383 #27486 #30275'
   design = 'CoupledVarThresholdElementSubdomainModifier.md VariableValueElementSubdomainModifier.md'
   [group]
     requirement = 'The framework shall include the ability to change element subdomain during simulation'
@@ -87,6 +87,13 @@
       exodiff = 'return_moving_boundary_out.e return_moving_boundary_out.e-s002 return_moving_boundary_out.e-s003'
       detail = 'continue updating the boundary if it temporarily contains no element sides, '
     []
+
+    [refined_boundary_refined_different_levels]
+      type = CSVDiff
+      input = 'moving_boundary_h_refinement.i'
+      csvdiff = 'moving_boundary_h_refinement_out.csv'
+      detail = 'update a boundary with element h-refinement happening with more refinement on the boundary primary side,'
+    []
   []
 
   [reinitialization]


Reviews:
user: login: roystgnr
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T13:29:00Z
user: login: GiudGiud
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T13:34:06Z
user: login: GiudGiud
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-04T13:34:40Z
user: login: roystgnr
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T12:53:34Z
user: login: GiudGiud
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-05T13:42:52Z
user: login: roystgnr
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T14:31:20Z
user: login: GiudGiud
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T15:39:37Z
user: login: GiudGiud
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T15:51:38Z
user: login: roystgnr
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T15:51:44Z
user: login: GiudGiud
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T16:07:51Z
user: login: roystgnr
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T16:22:25Z
user: login: GiudGiud
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T16:50:03Z

Review comments:
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: roystgnr
body: A subactive() element is sub (below) active - it will have active ancestors, but never active children or other descendants.

So something's wrong here.  What is the goal precisely?
created_at: 2025-05-04T13:28:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: GiudGiud
body: I think the ! makes the logic right.
it is not subactive (and it is not active, see right above), so it has active children
created_at: 2025-05-04T13:34:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: GiudGiud
body: the goal is to be able to follow the boundary as it enters an inactive top parent, and progresses through the refined elements
created_at: 2025-05-04T13:34:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: roystgnr
body: Well, missing the `!` was silly of me.  That simple case is correct, then.

The subactive case is still worrying me, though.

1.  How did we hit it?  This is getting called during mesh generation, right?  But we usually only have subactive elements when we're in the middle of some mesh coarsening (after elements are coarsened but before the systems finish projecting solutions) or geometric multigrid, and in either case we shouldn't be modifying the mesh.  Could we possibly just replace that whole branch with an assertion or error in the subactive case?

2.  "Active element we look for is coarser" isn't true in general.  Imagine a mesh with two quads, refined into 8 active quads with 2 ancestors, then half-coarsened into 5 active (4 fine, 1 coarse) quads but without yet removing the now-subactive 4.  Two of those 4 will have active neighbors at the same level as them, not coarser, and the other two will only have subactive neighbors.
created_at: 2025-05-05T12:53:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: GiudGiud
body: > How did we hit it? This is getting called during mesh generation, right?

nope during a solve. The user is moving a boundary and using AMR with a boundary marker at the same time. So we are refining elements, then moving the boundary within the refined element, and refining it more while inside as well. 

> Could we possibly just replace that whole branch with an assertion or error in the subactive case?

the subactive case is actually the one that matters here, see the coverage report. The others are harder to hit it seems!

> "Active element we look for is coarser" isn't true in general.

I understand what you are saying for the neighbor. 
But here, if an element is subactive, does it not mean that the active one is always a coarse parent of it?
created_at: 2025-05-05T13:42:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: roystgnr
body: This is really surprising.  The standard way to refine during a solve includes a call to `EquationSystems::reinit()` (because if you're refining your mesh mid-solve you'll need to be renumbering your DoFs and projecting your vectors and everything too), and unless we've specifically disabled it (which I don't see MOOSE doing) we do a `contract()` on the mesh and remove all the subactive elements before the `reinit()` returns.

This isn't just an academic worry - I don't recall that we go through much trouble to keep subactive elements' neighbor pointers valid, so seeing code relying on them is scary.

> But here, if an element is subactive, does it not mean that the active one is always a coarse parent of it?

Possibly a grandparent or higher if subactive elements have been retained through more than one coarsening step, but there should be some active ancestor at some point, yes.  I think I misunderstood your comment - I thought you were expecting to see coarser active neighbors, but you were talking about the coarser active parent.

What's the status of `elem` in this context?  If it's something we know, is it something we can assert?
created_at: 2025-05-06T14:31:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: GiudGiud
body: >  and remove all the subactive elements before the reinit() returns.

so I could just assert that we are not dealing with that, since I dont expect we would (and from coverage we are not)

> What's the status of elem in this context? If it's something we know, is it something we can assert?

elem is active and local afaik
created_at: 2025-05-06T15:39:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: GiudGiud
body: if you run the test locally and look at the exodus you ll see the context element-neighbor wise
created_at: 2025-05-06T15:51:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: roystgnr
body: Gah - I misunderstood you again, at "the subactive case is actually the one that matters here, see the coverage report" - you mean the `!subactive` case is the one that matters; now that I look at the report, we're not even hitting the subactive case.

> I could just assert that we are not dealing with that

Honestly I think that's the safest option.  I can't vouch for the subactive case's correctness here, and if it's not correct we'd basically just be leaving a red herring to confuse future users if there's some reason (e.g. preserving subactive elements during some kinds of transient AMR to reduce heap thrashing wouldn't be crazy) that code will ever be hit down the line.  My first impulse would be `else libmesh_not_implemented();` to make it clear that this isn't something we *can't* support, it's just not something we do support yet.  Maybe `libmesh_not_implemented_msg("Something about contacting developers");` to be nicer to whoever hits it.
created_at: 2025-05-06T15:51:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: GiudGiud
body: ok I did that
created_at: 2025-05-06T16:07:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -314,8 +314,29 @@ ElementSubdomainModifierBase::gatherMovingBoundaryChanges(
           gatherMovingBoundaryChangesHelper(elem, side, neigh, neigh_side);
         else
         {
+          // Find the active neighbors of the element
           std::vector<const Elem *> active_neighs;
-          neigh->top_parent()->active_family_tree_by_neighbor(active_neighs, elem);
+          // Neighbor has active children, they are neighbors of the element along that side
path: framework/src/meshmodifiers/ElementSubdomainModifierBase.C
user: login: GiudGiud
body: > > Could we possibly just replace that whole branch with an assertion or error in the subactive case?

> the subactive case is actually the one that matters here, see the coverage report. The others are harder to hit it seems!

ah no I missed a "not" there
created_at: 2025-05-06T16:50:03Z
author_association: CONTRIBUTOR

PR comments:
user: login: moosebuild
created_at: 2025-05-04T02:27:40Z
body: Job [Documentation](https://civet.inl.gov/job/2855912/), step Docs: sync website on 04d2966 wanted to post the following:

View the site [here](https://mooseframework.inl.gov/docs/PRs/30443/site)

This comment will be updated on new commits.
author_association: CONTRIBUTOR
user: login: moosebuild
created_at: 2025-05-04T03:27:10Z
body: Job [Coverage](https://civet.inl.gov/job/2855927/), step Generate coverage on 04d2966 wanted to post the following:


## Framework coverage

<table>
  <thead>
    <tr>
      <th></th>
      <th>6c09b2</th>
      <th colspan=4>#30443 04d296</th>
    </tr>
    <tr>
      <th></th>
      <th>Total</th>
      <th>Total</th>
      <th>+/-</th>
      <th>New</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><b>Rate</b></td>
      <td>85.46%</td>
      <td>85.46%</td>
      <td>-</td>
      <td>100.00%</td>
    </tr>
    <tr>
      <td><b>Hits</b></td>
      <td>112495</td>
      <td>112495</td>
      <td>-</td>
      <td>1</td>
    </tr>
    <tr>
      <td><b>Misses</b></td>
      <td>19138</td>
      <td>19138</td>
      <td>-</td>
      <td>0</td>
    </tr>
  </tbody>
</table>

[Diff coverage report](https://mooseframework.inl.gov/docs/PRs/30443/coverage_diff/framework)

[Full coverage report](https://mooseframework.inl.gov/docs/PRs/30443/coverage/framework)


## Modules coverage

Inconsistent report tags were found between the head and base reports.
This can happen when reports are missing from either the head or the base.

Inconsistent tags:
  module-phase_field-recover

## Full coverage reports

<details>
<summary>Reports</summary>

- [`framework`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/framework)
- [`chemical_reactions`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/chemical_reactions)
- [`combined`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/combined)
- [`contact`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/contact)
- [`electromagnetics`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/electromagnetics)
- [`external_petsc_solver`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/external_petsc_solver)
- [`fluid_properties`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/fluid_properties)
- [`fsi`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/fsi)
- [`functional_expansion_tools`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/functional_expansion_tools)
- [`geochemistry`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/geochemistry)
- [`heat_transfer`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/heat_transfer)
- [`level_set`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/level_set)
- [`misc`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/misc)
- [`navier_stokes`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/navier_stokes)
- [`optimization`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/optimization)
- [`peridynamics`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/peridynamics)
- [`phase_field`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/phase_field)
- [`porous_flow`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/porous_flow)
- [`ray_tracing`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/ray_tracing)
- [`rdg`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/rdg)
- [`reactor`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/reactor)
- [`richards`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/richards)
- [`scalar_transport`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/scalar_transport)
- [`solid_mechanics`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/solid_mechanics)
- [`solid_properties`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/solid_properties)
- [`stochastic_tools`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/stochastic_tools)
- [`subchannel`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/subchannel)
- [`thermal_hydraulics`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/thermal_hydraulics)
- [`xfem`](https://mooseframework.inl.gov/docs/PRs/30443/coverage/xfem)

</details>



This comment will be updated on new commits.
author_association: CONTRIBUTOR
user: login: GiudGiud
created_at: 2025-05-06T16:50:09Z
body: Thanks!
author_association: CONTRIBUTOR