Skip to content

Enable subcycle time stepping in CarpetX schedule#371

Open
lwJi wants to merge 38 commits intomainfrom
lwji/sc
Open

Enable subcycle time stepping in CarpetX schedule#371
lwJi wants to merge 38 commits intomainfrom
lwji/sc

Conversation

@lwJi
Copy link
Copy Markdown
Contributor

@lwJi lwJi commented Nov 25, 2025

Summary Refactored driver.cxx and schedule.cxx to enable subcycling support in CarpetX.

Change Log

  1. Regression Test: Added a WaveToyX test (3 refinement levels) to ensure backward compatibility.

  2. Parameter Scope: Promoted use_subcycling_wip to RESTRICTED scope for external thorn usage.

  3. Driver Logic: Enabled subcycling during regridding (provided levels align) in driver.cxx.

  4. Schedule Logic: Updated schedule.cxx to support the new subcycling flow.

  5. Unit Test: Added a new test case specifically for subcycle time stepping.

@lwJi lwJi requested review from eschnett and rhaas80 November 25, 2025 19:56
Copy link
Copy Markdown
Member

@rhaas80 rhaas80 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no further objections from me. But I have not looked deeply into the parts that Erik already commented on.

CarpetX::out_tsv_vars = "
TestSubcycling::iteration
CarpetXRegrid::regrid_error
"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need .x., .y. and .z. output for all variables? Or would .y. be sufficient alone to guard against regressions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would still claim that the files are pretty small ;)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the canary

    CCTK_REAL canary = 100 + 10 * cctk_iteration + 1 * cctk_level;
    iteration(pt.I) = canary;

is actually constant and we do not do anything that varies is space, two suggestions:

  • can we get away with a single grid point?
  • output only one grid point

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no. we need mesh refinement to test the subcycle stepping. we can't do mesh refinement with only one grid point. the fact the it's constant making it easier for us to tell if the subcycle stepping is correct or not

Copy link
Copy Markdown
Collaborator

@eschnett eschnett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a few suggestions. Please look at them, then merge.

cctkGH->cctk_delta_time = dtfac * mindx;
cctkGH->cctk_delta_time =
dtfac *
(ghext->use_subcycling() ? get_coarse_mindx() : get_finest_mindx());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's been a while. Do we set cctkGH->cctk_timefac and cctkGH->cctk_levfac (probably needs to happen in enter/leave_level_mode or so.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cctk_levfac are the same between subcyeling and non-subcycling. Where does cctk_timefac used?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cctk_timefac is used in CCTK_DELTA_TIME:

src/include/cctk_core.h:#define CCTK_DELTA_TIME (cctk_delta_time/cctk_timefac)

we do actually update it:

CarpetX/src/schedule.cxx:  cctkGH->cctk_timefac = 1; // no subcycling
CarpetX/src/schedule.cxx:  cctkGH->cctk_timefac = sourceGH->cctk_timefac;
CarpetX/src/schedule.cxx:      cctkGH->cctk_timefac = ghext->use_subcycling ? (1 << min_level) : 1;

Are you using CCTK_DELTA_TIME in the ODESolvers? If so that is already a test for the value being set and being set correctly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Liwei says out-of-band that CCTK_DELTA_TIME is used.

}
min_active_level = level;
}
assert(min_active_level != -1);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Erik had pointed out (correctly out one assumes) that once one has found the coarsest level that steps forward this iteration then all levels finer than that one must also step forward, which could be added as an assert() on the logic of the code here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

though, looking at the // Find end of batch comment below, those that have a different timestep size would not be part of the batch, but of a different batch that will step this iteration.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should I do anything about it? or it's fine for now

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is fine. Erik's comment would then apply to the min_level variable. I will add a sanity check.

active_levels = make_optional<active_levels_t>(min_level, max_level);

if ((!restrict_during_sync) &&
(ghext->patchdata.at(0).leveldata.at(max_level - 1).delta_iteration ==
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ugly (b/c of the long series of . operations) and probably dicey in case patch 0 does not actually have max_level levels (that is if Lucas ever decides to make patch 0 to be not the Cartesian one or if we actually have mesh refinement in the curvilinear patches). What does that condition actually try to check? Bunch up the same levels we just stepped forward? it's not the set of levels we have decided have now caught up with each other. Couldn't active_levels contain levels for which this is not true? I am confused by this logic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are trying to do restriction (and POSTRESTRICT) only when the finest level finish the current time stepping.
For example,

----- ----- -----
             4/4
       4/4  -----
             3/4
 4/4  ----- -----
             2/4
       2/4  -----
             1/4
----- ----- -----

we don't want to call Restrict (and PostRestrict) when level_iteration=4/4 at level 1, but at level 2 (the finest level). The reset of active_levels one line above make it contains all the level (all of them have level_iteration=4/4).

We are using delta_iteration to decide if we are stepping the finest level or not.

CarpetX::out_tsv_vars = "
TestSubcycling::iteration
CarpetXRegrid::regrid_error
"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the canary

    CCTK_REAL canary = 100 + 10 * cctk_iteration + 1 * cctk_level;
    iteration(pt.I) = canary;

is actually constant and we do not do anything that varies is space, two suggestions:

  • can we get away with a single grid point?
  • output only one grid point

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants