Skip to content

Adds the thermo coupling #461

Open
alicebarthel wants to merge 11 commits into
E3SM-Project:developfrom
alicebarthel:omega/add-thermo-forcing
Open

Adds the thermo coupling #461
alicebarthel wants to merge 11 commits into
E3SM-Project:developfrom
alicebarthel:omega/add-thermo-forcing

Conversation

@alicebarthel

@alicebarthel alicebarthel commented Jul 6, 2026

Copy link
Copy Markdown

This (draft) PR adds the thermo coupling - from forcing terms to thickness and tracer tendencies.
The energy of mass fluxes and phase changes are hard-coded into the tendency conversions, like it was in MPAS-O. Hopefully the documentation (inline or otherwise) clarifies the meaning of each term.

This PR is 3/3 to make #418 more digestible.

Checklist

  • Documentation:
  • Linting
  • Building
    • CMake build does not produce any new warnings from changes in this PR
  • Testing
    • CTest unit tests: "All tests passed" on pm-cpu (gnu) and pm-gpu.

    • The Polaris omega_pr test suite
      has passed, using the Polaris e3sm_submodules/Omega baseline

    • New tests:

      • new CTest unit tests: thickness and tracer tendencies are tested by building a baseline then turning the tendencies on and comparing to baseline. This was done because vertical tendencies do not have a flag to be turned off.

@alicebarthel alicebarthel requested a review from vanroekel July 6, 2026 22:49
- Surface stress forcing (e.g. wind stress)
- Surface tracer restoring
- Surface flux forcing (actively coupled or data-forced)
- Surface tracer restoring (soon to be ported)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

somewhere, I don't think it needs to be in this PR, but we should separate out salinity restoring (or explicitly call it out) and note we plan to do this in the coupler instead of the framework from mpas.

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.

The plan is to do restoring in the Forcing infrastructure too, as its own tendencies. I was planning to do a simple port into Forcing like I did for winds. With the timeline getting a little tight, I decided to prioritize implementing the new capability rather than spending time on the port.
The original PR (#418) had all the terms moved over but it was too big to test and review cleanly.
Are you thinking that you'd prefer a different design?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yep this sounds right, not saying it needs to be higher priority. And I was wanting us to note when we do restoring that the time varying salinity will come from the coupler not from a Omega forcing framework like we have for MPAS. I don't think that changes anything you plan, just where you get the restoring target from.

- `SensibleHeatFlux`: sensible heat transfer
- `LongWaveHeatFluxUp`: upward longwave radiation
- `LongWaveHeatFluxDown`: downward longwave radiation
- `SeaIceHeatFlux`: heat from sea-ice interaction

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't understand what you mean by sea ice interaction, can you clarify?

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.

I'll clarify. This includes the direct heat fluxes (conduction, etc.) and the enthalpy of liquid water from sea ice melt.

- `SnowFlux`: precipitation from snow
- `RainFlux`: precipitation from rain
- `EvaporationFlux`: evaporative water loss
- `SeaIceFreshWaterFlux`: freshwater input from sea-ice melt or formation

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

do we want to say freshwater input here since it can get positive and negative? Maybe just 'mass input from sea ice melt/formation?

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.

Good point, maybe "water mass flux from sea ice metl/formation"?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I like that.

values to Omega.
- The reference density used here ($\rho_{sw}$) is not a Boussinesq density, it is the
conversion factor from mass to pseudo-thickness.
- No iceberg fluxes are included for now.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

would the iceberg flux be a modification to iceRunoffFlux?

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.

The iceberg fluxes are their own additional terms. It's not hard to add an extra term, but given that we clearly stated that icebergs were out of scope for Omega, I thought I could skip defining/including them for now.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yes you can for sure. I was mostly curious

Mesh->NCellsSize),
SeaIceHeatFluxCell("seaIceHeatFlux" + Suffix, Mesh->NCellsSize),
ShortWaveHeatFluxCell("shortWaveHeatFlux" + Suffix, Mesh->NCellsSize),
SeaIceSaltFluxCell("seaIceSalinityFlux" + Suffix, Mesh->NCellsSize),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why is there a SeaIceSalinityFlux here? Is this because it's assuming that's the form in forcing.nc?

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.

Good catch. yes, it's a remnant from previous versions because I used to run a test reading from forcing.nc and loading the terms. This test has been removed so I can modify that to align it with the coupler terms.

Comment thread components/omega/src/ocn/Forcing.cpp Outdated
Err += MeshHalo->exchangeFullArrayHalo(SfcStressForcing.MeridStressCell,
OnCell);

Err += MeshHalo->exchangeFullArrayHalo(TracerForcing.SnowFluxCell, OnCell);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can you explain why a halo exchange is needed for on cell quantities? I would have thought the owned cells is enough

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.

Good catch. Cell centered variables should not need the halo exchange.

fluxes, and 1 salt flux component
- Fields initialized to zero and registered in `Forcing` field group
- `SfcThicknessForcingOnCell` tendency term
- Computes freshwater flux contribution: $\sum (\text{SnowFlux} + \text{RainFlux} + \text{EvaporationFlux} + \text{SeaIceFreshWaterFlux} + \text{IceRunoffFlux} + \text{RiverRunoffFlux} + \text{SeaIceSaltFlux}) / \rho_{sw}$

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

even though I think this works out, is SeaIceSaltFlux/\rho_{sw} the right form? It's kg Salt instead of water. Should we be specific about that? I recall you are elsewhere. I also recall the conversion factor works out to 1 to go from kg salt to kg water, so maybe it's not a big deal

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

actually isn't this a direct salt flux and maybe shouldn't appear here at all?

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.

I clarified the text: these are all the mass contributions to the layer. The salt mass flux is taken into account in the same way as freshwater mass fluxes.

This page documents the user-facing configuration and behavior for current forcing in Omega:

- Surface stress forcing (e.g. wind stress)
- Coupled flux forcing

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

surface stress is a momentum flux, so perhaps 'coupled thermodynamic and mass flux forcing'?


## Surface flux forcing

Surface flux forcing applies ocean-atmosphere and ocean-sea ice fluxes from the other model

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

similar comment, I don't think we should use surface flux and surface stress

Additional information on forcing (currently wind forcing and surface tracer
restoring) is detailed in [](omega-user-forcing).
Additional information on forcing, including surface stress forcing,
surface flux forcing, and surface tracer restoring, is detailed in

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

flagging surface flux again

SeaIceFreshWaterFlux(ICell) +
IceRunoffFlux(ICell) + RiverRunoffFlux(ICell);

Tend(ICell, KTop) += (FreshWaterFlux + SeaIceSaltFlux(ICell)) / RhoSw;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

i'm still unsure why this appears as a thickness flux

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.

@vanroekel the variable is pseudo-thickness, which is directly proportional to layer mass. So the question is: do we explicitly add the salt mass to the layer mass?
It changes the interplay between equations but isn't it more rigorous to include it?
I've been pondering this on the frazil side too.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

oh yes right. good point. What is the SeaIceSaltFlux term in the ocean? If I recall right it's the consequence of the 4PSU assumption, do you understand why it's a separate field and not directly included with the SeaIceFreshwaterFlux?

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.

The sea ice stores the freshwater and salt into 2 separate channels. In omega, both are mass (SI unit: kg) fluxes that come straight from the coupler (no 4psu assumption), with mass of salt and mass of pure freshwater as separate coupling terms. Both terms are added to the layer mass evolution, but only salt mass is added to the salinity tendency.
The use of "variable salinity coupling" will allow for time-varying salt flux due to sea ice drainage (i.e. prognostic salinity within the sea ice - translated to mass fluxes for coupling).

(note: if seaIceHeatFlux did not already include the enthalpy of melted water, we would use SeaIceFreshWaterFlux in the temperature tendency - here we don't because it would double count)

const Real PTopDb = PressureMid(ICell, KTop) * Pa2Db;
const Real SaTop = SaltIndex >= 0
? TracerCell(SaltIndex, ICell, KTop)
: 0.0_Real; // not sure we want zero here?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think 0 is a fine limit. Does this form of code preclude logging when we go below this threshold?

@vanroekel

Copy link
Copy Markdown
Collaborator

overall this looks quite good @alicebarthel I only had pretty minor comments

@alicebarthel alicebarthel force-pushed the omega/add-thermo-forcing branch from f814b7a to 47abc12 Compare July 13, 2026 20:01
@alicebarthel alicebarthel marked this pull request as ready for review July 13, 2026 20:07
@alicebarthel alicebarthel force-pushed the omega/add-thermo-forcing branch from 47abc12 to 2e13052 Compare July 13, 2026 20:15
@alicebarthel

alicebarthel commented Jul 13, 2026

Copy link
Copy Markdown
Author

One key test to do is to verify that omega_pr is BFB with develop baseline since we do not currently have a polaris test using the surface tracer forcing. @katsmith133

Here is my current test report:

Polaris omega_pr suite

  • Baseline workdir: /global/homes/a/abarthel/pscratch/polaris-scratch/baseline-current-develop-cpu
  • Baseline build: /global/homes/a/abarthel/pscratch/omega_scratch/develop-cpu
  • PR build: /global/homes/a/abarthel/pscratch/omega_scratch/add-thermo-forcing-cpu-gnu
  • PR workdir: /global/homes/a/abarthel/pscratch/polaris-scratch/add-thermo-cpu_vsbaseline
  • Machine: pm-cpu
  • Compiler: gnu
  • Build type: Debug
  • Log: not found
  • Result:
    • Diffs (1 of 12):
      • ocean/planar/barotropic_gyre/munk/free-slip

@alicebarthel

Copy link
Copy Markdown
Author

the log is at
/pscratch/sd/a/abarthel/polaris-scratch/add-thermo-cpu_vsbaseline/case_outputs/ocean_planar_barotropic_gyre_munk_free-slip.log
if that can be helpful

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.

2 participants