Support non-zero SurfacePressure#433
Conversation
|
This branch is based off of #428 |
TestingTesting was with E3SM-Project/polaris#610 Polaris
|
|
Documentation hasn't yet been updated. |
|
We need to add to this that we subtract |
32511f1 to
d18f6bd
Compare
|
I will instead define pressure fields clearly as relative pressure and drop the CF standard name |
6ef1c89 to
18c5e81
Compare
Updated TestingAgain with E3SM-Project/polaris#610 Polaris
|
|
@cbegeman, @andrewdnolan and @alicebarthel, sorry for the see-sawing on relative vs. absolute pressure. I have settled on relative pressure and that is documented here now. Please review and modify as needed (e.g. rebasing after #428 goes in). Please get @sbrus89 or someone else with the privileges to merge when you're happy, and once #428 has been merged. |
cbegeman
left a comment
There was a problem hiding this comment.
I agree with the code changes you made here. I will circle back for testing.
Adds `surfacePressure` to Omega initial conditions ... ...but does not add it to yaml files. Thus, `surfacePressure` is not used by the model. This relies on E3SM-Project/Omega#433. Adding `surfacePressure` to the yaml files for Omega-supported tests (that do not use `State`) will be done in a further PR. This PR also adds `surfacePressure` --> `SurfacePressure` mapping from MPAS-Ocean --> Omega. We need to add `SurfacePressure` explicitly to to manufactured solution initial state, since it does not use the `State` field group.
18c5e81 to
cd06a3b
Compare
|
Would the Forcing class be an option for where |
Compute the Laplacian of relative vorticity (Del2RelVortVertex) over the full vertex valid range [MinLayerVertexTop, MaxLayerVertexBot] and clamp each edge contribution to that edge's valid range [MinLayerEdgeTop, MaxLayerEdgeBot], matching VorticityAuxVars::computeVarsOnVertex. Previously Del2RelVortVertex was computed only over the narrower [MinLayerVertexBot, MaxLayerVertexTop] range (layers where every surrounding cell is active) and summed Del2Edge with no per-edge clamp. The biharmonic velocity tendency (VelocityHyperDiffOnEdge) reads Del2RelVortVertex over the edge range up to MaxLayerEdgeTop, which for a deep edge sharing a vertex with a shallower cell exceeds MaxLayerVertexTop. Those boundary-vertex layers were never computed, so on partial-bottom meshes the biharmonic term was under-computed there. This is a latent correctness bug on its own; on the fill-values branch the uncomputed layers hold FillValueReal, so the term instead blew up to ~1e45, corrupting NormalVelocity and, through the flux divergence and vertical advection, PseudoThickness and the tracers (surfaced by the new state validation in DRIVER_TEST). The wider range gives boundary vertices a valid, generally non-zero value from their active edges; inactive edges contribute zero via the per-edge clamp and Del2Edge's zeroed boundary band, so no fill value is read. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This merge adds 5 constexpr fill value constants (FillValueI4, FillValueI8, FillValueR4, FillValueR8, FillValueReal) in namespace OMEGA, wrapping PIO_FILL_* from SCORPIO.
This merge adds private fillWithValue<T>() template helper (using if constexpr on T::value_type) and a call to it at the end of attachData<T>(). Arrays are now auto-filled with the declared fill value at attach time.
This merge removes all local fill value declarations and replaces references with the centralized constants.
We don't want fill values at every boundary edge becausee these are also valid. Instead, we want zeros except for edges between two inactive cells (e.g. both adjacent cells are below bathymetry)
Rather than assuming that the NormalVelocity read from an initial condition has correct masking, we ensure that it has fill values for inactive layers, zeros at boundary edges (both adjacent to land and to bathymetry), and leave its values unchanged for active, non-boundary layers.
We need to ensure that it is zero at active boundary edges.
Co-authored-by: Maciej Waruszewski <mwarusz@igf.fuw.edu.pl>
Add Test 5 and Test 6 to FillValueTest.cpp covering the cell and vertex layer-mask methods added in 27c02f5. Each test fills a synthetic field with a sentinel value, applies the mask, and verifies the resulting zones: cells expect FillValueReal in inactive layers and the sentinel in active layers; vertices expect the 3-zone pattern (fill / 0 / sentinel) matching the existing edge-mask test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Document applyCellLayerMask and applyVertexLayerMask alongside the edge helpers in Section 4.5, and describe the OceanState::applyLayerMasks driver called from ocnInit. Correct stale facts in Section 5: the test lives at test/ocn/FillValueTest.cpp, uses direct comparison with Error accumulation, and now includes cell and vertex mask cases (5.5, 5.6); remove the unimplemented NetCDF attribute test. Update Requirement 2.7 for the expanded cell/vertex coverage. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a Layer masking subsection to the VertCoord devGuide describing zeroEdgeField, applyEdgeLayerMask, applyCellLayerMask, and applyVertexLayerMask, their zones, the inclusive active-layer convention, and the applyLayerMasks driver. Add a userGuide note explaining that inactive layers carry the fill value and boundary layers carry 0 in output. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SurfacePressure is the relative (gauge) pressure at the top of the ocean column and the top boundary condition of the pressure field, consumed only by VertCoord::computePressure. Give VertCoord ownership of the array (device and host mirror) instead of passing it a borrowed handle from OceanState: - VertCoord allocates and registers the SurfacePressure field and adds it to the State and Restart groups (creating them if VertCoord initializes before OceanState) so it is still read from the initial-state and restart files. - VertCoord::initSurfacePressure() exchanges the halo and copies to host after the stream read; OceanInit calls it in place of the old OceanState hook. - OceanState no longer owns SurfacePressure and guards its State-group creation since VertCoord may create the group first. Also clarify in Eos that the pressure argument is relative (gauge) pressure. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Retarget the SurfacePressure size and read checks in StateTest to the VertCoord-owned array and add a host-mirror size check to VertCoordTest. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the SurfacePressure documentation from the OceanState user and developer guides to the VertCoord guides, describing that VertCoord owns it, that it is read from the initial-state and restart files, and that initSurfacePressure() finalizes it after the read. Note it is relative (gauge) pressure. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
cd06a3b to
3fc9579
Compare
|
@sbrus89, I have refactored the PR to leave I need to do some retesting to make sure the refactor actually works as expected, I just wanted to give you a heads up about the outcome. I looked into it but I don't think the forcing is a good place for surface pressure to live. It can be updated based on coupling fields (atmospheric pressure, sea ice pressure, etc.) and still live in the vertical coordinate. |
Add a per-field "optional read" flag to Field so that a field may be absent from an input file. When a read stream does not contain an optional field's variable, IOStream::readFieldData now logs and returns success, leaving the attached array at the fill value set by attachData, instead of failing the whole stream read. Fields are required by default, so existing behavior is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a case to IOStreamTest that registers a field absent from the input file, marks it as an optional read, and adds it to the InitialState stream. Verify the stream read succeeds and the field array retains the fill value on all owned cells, confirming a missing optional field is skipped rather than failing the read. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Mark the VertCoord SurfacePressure field as an optional read so it is no longer required in the initial-condition or restart file. SurfacePressure stays in the State and Restart groups, so it is still written to history and restart files and read from the initial-state and restart files when present. When it is absent, initSurfacePressure detects the leftover fill value on the owned cells and defaults the field to zero before the halo exchange and host copy. Update the StateTest comment to note the field is now optional and defaults to zero. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Describe the new per-field optional-read capability in the Field and IOStreams dev guides and in the fill-values design doc: a field marked with setOptionalRead is skipped rather than failing when absent from an input file, keeping its fill value for the owning module to default. Update the VertCoord and OceanState guides to note that SurfacePressure is an optional read that defaults to zero when not present in the initial-condition or restart file. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
TestingI'm testing in combination with E3SM-Project/polaris#629, which includes a rebase of E3SM-Project/polaris#615 Polaris
|
|
As far as I'm concerned, this is ready for review and could go in once #428 is merged and this gets rebased onto develop. |
Register SurfacePressure as an input/output field owned by the vertical coordinate so it is read from the initial-condition and restart files, and define all Omega pressure fields as relative (gauge) pressure. SurfacePressure was previously a zeroed placeholder in VertCoord; it is now allocated, registered as a field, and added to the State and Restart field groups next to the other prognostic variables, with a post-read step to exchange halos and update its host mirror. Because VertCoord is the sole consumer of SurfacePressure when computing 3D pressure, it owns the array directly. SurfacePressure is registered as an optional read, so it is read from the initial condition or restart file when present but defaults to zero when absent rather than causing the read to fail. Supporting this adds a general per-field optional-read capability to the IO layer.
Changes
Register
SurfacePressureas aVertCoordIO fieldSurfacePressure/SurfacePressureHinVertCoordand remove the placeholderTODOzero-fillSurfacePressureas a 1D (NCells) field and add it to theStateandRestartfield groups so it is included in the initial-condition and restart streamsVertCoord, its only consumer, so no array needs to be shared between classes to compute 3D pressureVertCoordinitializes beforeOceanStateand both contribute to theStategroup, create theState/Restartgroups from whichever initializes first;OceanStateguards itsState-group creation accordinglyVertCoord::initSurfacePressure(Halo*)to exchange halos and sync device→host after the initial-state/restart stream read, and call it fromOceanInitafter the read so the host mirror and halo are ready before the model advancesSurfacePressureis marked as an optional read, so it is not required in the Omega initial condition or restart file. When it is absent, the stream read leaves it at its fill value andinitSurfacePressuredefaults it to zero (0 Pa), which is the correct value for standard atmospheric forcing.Add an optional-read capability to IO fields
Fields registered in a read stream are normally required to be present in the input file, which is why an owner like
VertCoordcould not simply defaultSurfacePressurewhen it lives in the sharedState/Restartread. This adds a general way to make a field optional.OptionalReadflag toField(setOptionalRead/isOptionalRead, required by default) so a field may be absent from an input fileIOStream::readFieldDatato skip a missing optional field — log, return success, and leave the array at the fill value set byattachData— instead of failing the whole stream read; required fields are unaffectedVertCoord::SurfacePressureas an optional read and default it to zero ininitSurfacePressurewhen its owned cells still hold the fill value after the read, so a missingSurfacePressureno longer aborts initializationIOStreamTestcase that reads a stream containing an optional field absent from the file and verifies the read succeeds with the array left at its fill valueFieldand IOStreams developer guides and the fill-values design docDefine all pressure fields as relative (gauge) pressure
Omega's pressure fields (
SurfacePressure,PressureInterface,PressureMid) are defined as relative pressure — absolute pressure minus the standard atmosphere (101325 Pa). Motivations:Eos.halready passesPressure * Pa2Dbwith no offset, consistent with this definition.ẑ = p / (ρ₀ g)equals zero at the sea surface under standard atmospheric forcing only whenpis relative pressure. Under absolute pressure the surface pseudo-height would already be ≈ −10 m, which is conceptually strange.sea_water_pressureis defined for absolute pressure, so it is not used for these fields; no CF standard name exists for relative pressure.Specific changes:
VertCoord.cpp: createSurfacePressurewith units Pa, long name "relative pressure at the top of the ocean column", and no CF standard name; remove thesea_water_pressureCF standard name fromPressureInterfaceandPressureMid, update their long names to "relative pressure (gauge pressure)", and set their minimum valid value to−AtmRefP(≈ −101325 Pa, since absolute pressure ≥ 0 implies relative pressure ≥ −standard atmosphere)Eos.h: document thatPressureinputs to the TEOS-10 specific-volume, freezing-temperature, and Brunt-Väisälä functors are relative pressureVertCoord.h/VertCoord.cpp: clarify thatcomputePressurecomputes relative pressure given relativeSurfacePressureVertCoord.md,OceanState.md): describe the pressure fields as relative, document thatSurfacePressureis owned byVertCoordand is an optional read that defaults to zero, and note that it is 0 Pa for standard atmospheric forcing and represents the atmospheric anomaly in coupled runsVertCoord.md,OceanState.md): document thatSurfacePressureis aVertCoordfield, is relative pressure, and is an optional read that defaults to zeroChecklist
Testingwith the following:have been run on and indicate that are all passing.
has passed, using the Polaris
e3sm_submodules/Omegabaseline-pfor both the baseline (Polarise3sm_submodules/Omega) and the PR build