Skip to content

Commit 3cb4a28

Browse files
authored
Merge pull request #456 from xylar/omega/fix-del4-curl-operator
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 (#428) 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.
2 parents 0b24888 + 23dd90b commit 3cb4a28

3 files changed

Lines changed: 32 additions & 14 deletions

File tree

components/omega/src/ocn/AuxiliaryState.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,8 @@ void AuxiliaryState::computeMomAux(const OceanState *State,
117117

118118
OMEGA_SCOPE(MinLayerCell, VCoord->MinLayerCell);
119119
OMEGA_SCOPE(MaxLayerCell, VCoord->MaxLayerCell);
120-
OMEGA_SCOPE(MinLayerVertexBot, VCoord->MinLayerVertexBot);
121120
OMEGA_SCOPE(MinLayerVertexTop, VCoord->MinLayerVertexTop);
122121
OMEGA_SCOPE(MaxLayerVertexBot, VCoord->MaxLayerVertexBot);
123-
OMEGA_SCOPE(MaxLayerVertexTop, VCoord->MaxLayerVertexTop);
124122
OMEGA_SCOPE(MinLayerEdgeTop, VCoord->MinLayerEdgeTop);
125123
OMEGA_SCOPE(MinLayerEdgeBot, VCoord->MinLayerEdgeBot);
126124
OMEGA_SCOPE(MaxLayerEdgeBot, VCoord->MaxLayerEdgeBot);
@@ -204,8 +202,12 @@ void AuxiliaryState::computeMomAux(const OceanState *State,
204202
parallelForOuter(
205203
"vertexAuxState2", {Mesh->NVerticesAll},
206204
KOKKOS_LAMBDA(int IVertex, const TeamMember &Team) {
207-
const int KMin = MinLayerVertexBot(IVertex);
208-
const int KMax = MaxLayerVertexTop(IVertex);
205+
// Del2RelVortVertex is computed over the full vertex valid range
206+
// [MinLayerVertexTop, MaxLayerVertexBot] so that boundary-vertex
207+
// layers read by the biharmonic velocity tendency are valid rather
208+
// than fill values (see VelocityDel2AuxVars::computeVarsOnVertex).
209+
const int KMin = MinLayerVertexTop(IVertex);
210+
const int KMax = MaxLayerVertexBot(IVertex);
209211
const int KRange = vertRangeChunked(KMin, KMax);
210212

211213
parallelForInner(

components/omega/src/ocn/auxiliaryVars/VelocityDel2AuxVars.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ VelocityDel2AuxVars::VelocityDel2AuxVars(const std::string &AuxStateSuffix,
2424
AreaTriangle(Mesh->AreaTriangle), VertexDegree(Mesh->VertexDegree),
2525
MinLayerEdgeBot(VCoord->MinLayerEdgeBot),
2626
MaxLayerEdgeTop(VCoord->MaxLayerEdgeTop),
27-
MinLayerVertexBot(VCoord->MinLayerVertexBot),
28-
MaxLayerVertexTop(VCoord->MaxLayerVertexTop),
27+
MinLayerEdgeTop(VCoord->MinLayerEdgeTop),
28+
MaxLayerEdgeBot(VCoord->MaxLayerEdgeBot),
29+
MinLayerVertexTop(VCoord->MinLayerVertexTop),
30+
MaxLayerVertexBot(VCoord->MaxLayerVertexBot),
2931
MinLayerCell(VCoord->MinLayerCell), MaxLayerCell(VCoord->MaxLayerCell) {}
3032

3133
void VelocityDel2AuxVars::registerFields(const std::string &AuxGroupName,

components/omega/src/ocn/auxiliaryVars/VelocityDel2AuxVars.h

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,25 +75,37 @@ class VelocityDel2AuxVars {
7575
}
7676

7777
KOKKOS_FUNCTION void computeVarsOnVertex(int IVertex, int KChunk) const {
78-
const int KStart = chunkStart(KChunk, MinLayerVertexBot(IVertex));
79-
const int KLen = chunkLength(KChunk, KStart, MaxLayerVertexTop(IVertex));
78+
// Compute over the full vertex valid range [MinLayerVertexTop,
79+
// MaxLayerVertexBot] so that boundary-vertex layers (where only some
80+
// surrounding cells are active) receive a valid value. Each edge's
81+
// contribution is clamped to that edge's valid range [MinLayerEdgeTop,
82+
// MaxLayerEdgeBot], where Del2Edge has been computed or zeroed; this
83+
// matches VorticityAuxVars::computeVarsOnVertex and avoids reading
84+
// uninitialized (fill-value) layers of Del2Edge for deeper edges.
85+
const int KStartVertex = chunkStart(KChunk, MinLayerVertexTop(IVertex));
86+
const int KLenVertex =
87+
chunkLength(KChunk, KStartVertex, MaxLayerVertexBot(IVertex));
88+
const int KEndVertex = KStartVertex + KLenVertex - 1;
8089

8190
const Real InvAreaTriangle = 1._Real / AreaTriangle(IVertex);
8291

8392
Real Del2RelVortVertexTmp[VecLength] = {0};
8493

8594
for (int J = 0; J < VertexDegree; ++J) {
8695
const int JEdge = EdgesOnVertex(IVertex, J);
87-
for (int KVec = 0; KVec < KLen; ++KVec) {
88-
const int K = KStart + KVec;
96+
const int KStartEdge =
97+
Kokkos::max(KStartVertex, MinLayerEdgeTop(JEdge));
98+
const int KEndEdge = Kokkos::min(KEndVertex, MaxLayerEdgeBot(JEdge));
99+
for (int K = KStartEdge; K <= KEndEdge; ++K) {
100+
const int KVec = K - KStartVertex;
89101
Del2RelVortVertexTmp[KVec] += InvAreaTriangle * DcEdge(JEdge) *
90102
EdgeSignOnVertex(IVertex, J) *
91103
Del2Edge(JEdge, K);
92104
}
93105
}
94106

95-
for (int KVec = 0; KVec < KLen; ++KVec) {
96-
const int K = KStart + KVec;
107+
for (int KVec = 0; KVec < KLenVertex; ++KVec) {
108+
const int K = KStartVertex + KVec;
97109
Del2RelVortVertex(IVertex, K) = Del2RelVortVertexTmp[KVec];
98110
}
99111
}
@@ -118,8 +130,10 @@ class VelocityDel2AuxVars {
118130
I4 VertexDegree;
119131
Array1DI4 MinLayerEdgeBot;
120132
Array1DI4 MaxLayerEdgeTop;
121-
Array1DI4 MinLayerVertexBot;
122-
Array1DI4 MaxLayerVertexTop;
133+
Array1DI4 MinLayerEdgeTop;
134+
Array1DI4 MaxLayerEdgeBot;
135+
Array1DI4 MinLayerVertexTop;
136+
Array1DI4 MaxLayerVertexBot;
123137
Array1DI4 MinLayerCell;
124138
Array1DI4 MaxLayerCell;
125139
};

0 commit comments

Comments
 (0)