Skip to content

Add SfcCoupling class as an interface layer to the coupler #458

Open
andrewdnolan wants to merge 21 commits into
E3SM-Project:developfrom
andrewdnolan:omega/surface-coupling
Open

Add SfcCoupling class as an interface layer to the coupler #458
andrewdnolan wants to merge 21 commits into
E3SM-Project:developfrom
andrewdnolan:omega/surface-coupling

Conversation

@andrewdnolan

@andrewdnolan andrewdnolan commented Jul 2, 2026

Copy link
Copy Markdown

Adds SfcCoupling, which manages the variables exchanged to (o2x) and from (x2o) the coupler for a sub-domain of the global mesh.

Changes

  • New SfcCoupling class supporting both MCT and MOAB coupling layouts
  • CouplingLayout Enum allows for CTesting of MCT (column major) and MOAB (row major) layouts.
  • Import/export of raw coupler data via unmanaged Kokkos views
  • applyImportFields() to push imported fields into Forcing
  • updateExportFields() to accumulate running averages of export fields on-device

Known limitations

  • Exported velocities use a placeholder constant pending vector reconstruction
    • A small non-zero value is used to prevent infinite fluxes in the coupler

Checklist

  • Documentation:
  • Linting
  • Building
    • CMake build does not produce any new warnings from changes in this PR
  • Testing
    • Add a comment to the PR titled Testing with the following:
      • Which machines CTest unit tests
        have been run on and indicate that are all passing.
      • The Polaris omega_pr test suite
        has passed, using the Polaris e3sm_submodules/Omega baseline
      • Document machine(s), compiler(s), and the build path(s) used for -p for both the baseline (Polaris e3sm_submodules/Omega) and the PR build
      • Indicate "All tests passed" or document failing tests
      • Document testing used to verify the changes including any tests that are added/modified/impacted.
      • Performance related PRs: Please include a relevant PACE experiment link documenting performance before and after.
    • New tests:
      • CTest unit tests for new features have been added per the approved design.
      • Polaris tests for new features have been added per the approved design (and included in a test suite)
  • Stealth Features
    • If any stealth features are included in the PR, please confirm that they have been documented.

Host array for the OcnToCplFields class were made private to
protect from different units on host and device array. Needed to
balance performance with correct units.
@cbegeman

cbegeman commented Jul 6, 2026

Copy link
Copy Markdown

@andrewdnolan Besides the ctest, is testing this as a part of e3sm also possible (with cpl history output)?

@andrewdnolan

andrewdnolan commented Jul 6, 2026

Copy link
Copy Markdown
Author

@cbegeman Not quite yet, there will be some work to get the coupled driver branch hook up to use this branch. I can try to get that working, but that testing would be pretty ad-hoc. I think it'd be best to get this in with just the CTest testing, with the understanding that this PR is just a first pass, and a follow on will be needed to fully "hook things up".

That being said, I tried to be very thorough in the CTest and have mock pointers that mimic the raw attribute vectors passed by the coupler. I have tests for both unpacking (import) and packing (export) with both MCT and MOAB layouts. The data varies per-field and per cell, so a pretty reasonable test. I feel fairly confident in the code mechanics here, given the CTest, though there will absolutely be more work to get physically meaningful coupling. (But that will be dependent on a coupled driver).

@cbegeman

cbegeman commented Jul 6, 2026

Copy link
Copy Markdown

@andrewdnolan Thanks for clarifying! That all sounds good.

Comment on lines +136 to +137
std::map<std::string, int> ImportIdx;
std::map<std::string, int> ExportIdx;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
std::map<std::string, int> ImportIdx;
std::map<std::string, int> ExportIdx;
std::map<std::string, int> ImportIdxMap;
std::map<std::string, int> ExportIdxMap;

I'd like to use some variable name here and elsewhere that implies this contains multiple field-index mappings. To me ImportIdx suggests a single integer index.


// Kokkok views created with a label are zero-initialized by default.
// We reset the fields here anyway to be explicit about the fact that the
// OcnToCpl fields need to being a coupling interval with all zeros.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A missing word here in the comment?

int HaloErr = Halo::init();
if (HaloErr != 0) {
Err++;
LOG_ERROR("SfcCouplingTest: Error initializing defualt halo");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
LOG_ERROR("SfcCouplingTest: Error initializing defualt halo");
LOG_ERROR("SfcCouplingTest: Error initializing default halo");

Comment on lines +26 to +29
std::map<std::string, int> ImportIdx = {{"Foxx_taux", 3}, {"Foxx_tauy", 8}};
std::map<std::string, int> ExportIdx = {
{"So_t", 2}, {"So_s", 4}, {"So_u", 6}, {"So_v", 9}, {"So_ssh", 1}};
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

What's the ultimate plan for where these maps would be set?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

These maps will be created in the coupled driver; see here and here.

For the CTest's we just need maps where the key (string) matches the values provided from the coupler and then we just make up mock integer for testing. I've intentionally tried to make this non-continuous (i.e. uneven stride). I don't think we really need to have "mock" entries for every field, just a few per import and export, to test the packing and unpacking into the pointer arrays.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Got it. I agree. Thanks

deepCopy(InstSshCellH, SSHCellOwned);
}

// OcnToCpl fields need to being a coupling interval with all values set to 0.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I'm confused on what this is supposed to say... is it "...need to bring..."?

}

// OcnToCpl fields need to being a coupling interval with all values set to 0.
void OcnToCplFields::resetFields() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is resetting everything to 0 the safest thing here? Maybe I am misunderstanding, but is the a chance that these zeros could not be overwritten and get sent to the coupler?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Yes, we need to be able to reset all field to zero. The field contained in OcnToCpl are averaged fields, so each ocean time step (within the coupling interval) we calculate the update average. Given the average function: if we did not have a way to reset values to zero at the end of a coupling interval, these values would continue accumulating over the whole simulation, which is no good.

So this should only be called at then end of coupling interval, after the SfcCoupling::exportToCoupler has been called.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ok, that makes sense. Now I understand the need to reset. I guess is there a change nothing gets accumulated in those averages and we send 0 to the coupler? I think for ssh or velocity that would be fine, but not so much for temp or salt.

return Array;
}

// Shaed index formula for packing/unpacking from rae coupler buffer

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Shaed" = "Shared"? and "rae"?

auto SfcStressZonal_ = CplToOcn.SfcStressZonal;
auto SfcStressMerid_ = CplToOcn.SfcStressMerid;

/// TODO: Shouldn't be making direct calls to Kokkos here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Will this be a part of this PR or another follow on one?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This will have to be a follow on PR.

Updating the wrappers in src/infra/OmegaKokkos.h is a bit out of my comfort zone. Plus we'd need to support a hybrid (GPU + openmp) build, which is a larger can of worms.

///< So_t [K], in-situ approx (potential temp at P=0)
HostArray1DReal AvgSfcTemperatureH;

/// TODO: Export practical salinity (unitless) to coupler

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Will this be a part of this PR or another follow on one?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

EOS does not currently have a method for converting from absolute to practical salinity. So this will have to part of a follow on PR, after that's implemented.

@katsmith133

Copy link
Copy Markdown

Ran CTests on PM-CPU and GPU. All tests passed on CPU, but SFCCOUPLING_TEST failed on GPU. I don't see any error message pertaining to this failure and I don't see any compile messages that have to do with the files touched in this PR.

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.

3 participants