Skip to content

Commit 8fc3284

Browse files
committed
Add fill-value CTests
1 parent f622423 commit 8fc3284

2 files changed

Lines changed: 264 additions & 0 deletions

File tree

components/omega/test/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,17 @@ add_omega_test(
495495
"-n;8"
496496
)
497497

498+
##################
499+
# Fill Value test
500+
##################
501+
502+
add_omega_test(
503+
FILL_VALUE_TEST
504+
testFillValue.exe
505+
ocn/FillValueTest.cpp
506+
"-n;8"
507+
)
508+
498509
##########################
499510
# Vert Mix test
500511
##########################
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
//===-- Test driver for Omega fill value standardization --------*- C++ -*-===//
2+
//
3+
/// \file
4+
/// \brief Test driver for Omega fill value constants and auto-fill behavior
5+
///
6+
/// Tests:
7+
/// 1. FillValueI4/I8/R4/R8 constants match the NetCDF-C NC_FILL_* values
8+
/// 2. Field::attachData() auto-fills the array with the declared fill value
9+
/// 3. Inactive layers (k >= MaxLayerCell) contain FillValueReal after
10+
/// VertCoord initialization and compute
11+
/// 4. Active NormalVelocity layers at boundary edges are NOT fill values
12+
/// after OceanState initialization (guards against the zero-init
13+
/// assumption)
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "AuxiliaryState.h"
18+
#include "DataTypes.h"
19+
#include "Decomp.h"
20+
#include "Dimension.h"
21+
#include "Error.h"
22+
#include "Field.h"
23+
#include "Halo.h"
24+
#include "HorzMesh.h"
25+
#include "IO.h"
26+
#include "IOStream.h"
27+
#include "Logging.h"
28+
#include "MachEnv.h"
29+
#include "OceanState.h"
30+
#include "OmegaKokkos.h"
31+
#include "PGrad.h"
32+
#include "Pacer.h"
33+
#include "Tendencies.h"
34+
#include "TimeMgr.h"
35+
#include "TimeStepper.h"
36+
#include "Tracers.h"
37+
#include "VertCoord.h"
38+
#include "mpi.h"
39+
40+
#include <netcdf.h>
41+
42+
using namespace OMEGA;
43+
44+
//------------------------------------------------------------------------------
45+
// Full initialization needed for OceanState (matches StateTest.cpp pattern)
46+
void initFillValueTest() {
47+
48+
MachEnv::init(MPI_COMM_WORLD);
49+
MachEnv *DefEnv = MachEnv::getDefault();
50+
MPI_Comm DefComm = DefEnv->getComm();
51+
52+
initLogging(DefEnv);
53+
54+
Config("Omega");
55+
Config::readAll("omega.yml");
56+
57+
TimeStepper::init1();
58+
TimeStepper *DefStepper = TimeStepper::getDefault();
59+
Clock *ModelClock = DefStepper->getClock();
60+
61+
IO::init(DefComm);
62+
63+
Field::init(ModelClock);
64+
IOStream::init(ModelClock);
65+
66+
Decomp::init();
67+
68+
int Err = Halo::init();
69+
if (Err != 0)
70+
ABORT_ERROR("FillValueTest: error initializing default halo");
71+
72+
HorzMesh::init(ModelClock);
73+
VertCoord::init();
74+
Tracers::init();
75+
AuxiliaryState::init();
76+
PressureGrad::init();
77+
Tendencies::init();
78+
TimeStepper::init2();
79+
80+
Err = OceanState::init();
81+
if (Err != 0)
82+
ABORT_ERROR("FillValueTest: error initializing OceanState");
83+
84+
bool StreamsValid = IOStream::validateAll();
85+
if (!StreamsValid)
86+
ABORT_ERROR("FillValueTest: error validating IO streams");
87+
}
88+
89+
//------------------------------------------------------------------------------
90+
int main(int argc, char *argv[]) {
91+
92+
Error ErrAll;
93+
94+
MPI_Init(&argc, &argv);
95+
Kokkos::initialize();
96+
Pacer::initialize(MPI_COMM_WORLD);
97+
Pacer::setPrefix("Omega:");
98+
{
99+
initFillValueTest();
100+
101+
auto *DefMesh = HorzMesh::getDefault();
102+
auto *DefVertCoord = VertCoord::getDefault();
103+
auto *DefDecomp = Decomp::getDefault();
104+
auto *DefState = OceanState::getDefault();
105+
106+
// ------------------------------------------------------------------
107+
// Test 1: FillValue constants match NetCDF-C NC_FILL_* values
108+
// ------------------------------------------------------------------
109+
{
110+
int Err = 0;
111+
if (FillValueI4 != static_cast<I4>(NC_FILL_INT))
112+
++Err;
113+
if (FillValueI8 != static_cast<I8>(NC_FILL_INT64))
114+
++Err;
115+
if (static_cast<double>(FillValueR4) !=
116+
static_cast<double>(NC_FILL_FLOAT))
117+
++Err;
118+
if (FillValueR8 != static_cast<R8>(NC_FILL_DOUBLE))
119+
++Err;
120+
121+
if (Err == 0) {
122+
LOG_INFO("FillValueTest: fill constant values PASS");
123+
} else {
124+
ErrAll += Error(ErrorCode::Fail,
125+
"FillValueTest: fill constant values FAIL");
126+
}
127+
}
128+
129+
// ------------------------------------------------------------------
130+
// Test 2: attachData() auto-fills the array with the declared fill value
131+
// ------------------------------------------------------------------
132+
{
133+
// Create a small non-distributed test dimension and field
134+
I4 NTest = 10;
135+
Dimension::create("FVTestDim", NTest, NTest,
136+
std::vector<I4>(NTest, 0));
137+
auto TestField =
138+
Field::create("FVTestField", "fill value test", "1", "", -1.0e40,
139+
1.0e40, FillValueR8, 1, {"FVTestDim"}, false);
140+
141+
// Allocate a host array set to 0.0 (not the fill value)
142+
HostArray1DR8 TestArr("FVTestArr", NTest);
143+
Kokkos::deep_copy(TestArr, 0.0);
144+
145+
// attachData() should automatically fill with FillValueR8
146+
TestField->attachData<HostArray1DR8>(TestArr);
147+
148+
int Err = 0;
149+
for (int I = 0; I < NTest; ++I) {
150+
if (TestArr(I) != FillValueR8)
151+
++Err;
152+
}
153+
154+
if (Err == 0) {
155+
LOG_INFO("FillValueTest: attachData auto-fill PASS");
156+
} else {
157+
ErrAll += Error(ErrorCode::Fail,
158+
"FillValueTest: attachData auto-fill FAIL");
159+
}
160+
}
161+
162+
// ------------------------------------------------------------------
163+
// Test 3: Inactive layers (k >= MaxLayerCell) contain FillValueReal
164+
// in a VertCoord field (GeomZMid) after initialization
165+
// ------------------------------------------------------------------
166+
{
167+
I4 NCellsOwned = DefMesh->NCellsOwned;
168+
I4 NVertLayers = DefVertCoord->NVertLayers;
169+
170+
auto GeomZMidH = createHostMirrorCopy(DefVertCoord->GeomZMid);
171+
172+
int Err = 0;
173+
for (int ICell = 0; ICell < NCellsOwned; ++ICell) {
174+
I4 KMax = DefVertCoord->MaxLayerCellH(ICell);
175+
for (int K = KMax; K < NVertLayers; ++K) {
176+
if (GeomZMidH(ICell, K) != FillValueReal)
177+
++Err;
178+
}
179+
}
180+
181+
if (Err == 0) {
182+
LOG_INFO("FillValueTest: inactive layers contain fill value PASS");
183+
} else {
184+
ErrAll +=
185+
Error(ErrorCode::Fail,
186+
"FillValueTest: inactive layers contain fill value FAIL");
187+
}
188+
}
189+
190+
// ------------------------------------------------------------------
191+
// Test 4: Active NormalVelocity layers at boundary edges are NOT
192+
// fill values after OceanState initialization.
193+
// Boundary edges: where MaxLayerEdgeTop < NVertLayers and
194+
// the edge straddles at least one land-adjacent cell.
195+
// For a quiescent initial state, active layers should be 0.
196+
// ------------------------------------------------------------------
197+
{
198+
I4 NEdgesOwned = DefMesh->NEdgesOwned;
199+
I4 NVertLayers = DefVertCoord->NVertLayers;
200+
201+
auto NVH = createHostMirrorCopy(DefState->NormalVelocity[0]);
202+
auto MaxLayerEdgeTopH =
203+
createHostMirrorCopy(DefVertCoord->MaxLayerEdgeTop);
204+
205+
int ErrFill = 0; // active layers at fill value (bad)
206+
207+
for (int IEdge = 0; IEdge < NEdgesOwned; ++IEdge) {
208+
I4 KTop = MaxLayerEdgeTopH(IEdge);
209+
for (int K = 0; K < KTop; ++K) {
210+
if (NVH(IEdge, K) == FillValueReal)
211+
++ErrFill;
212+
}
213+
}
214+
215+
if (ErrFill == 0) {
216+
LOG_INFO("FillValueTest: NormalVelocity active layers not fill "
217+
"value PASS");
218+
} else {
219+
ErrAll +=
220+
Error(ErrorCode::Fail,
221+
"FillValueTest: NormalVelocity active layers not fill "
222+
"value FAIL ({} active entries equal FillValueReal)",
223+
ErrFill);
224+
}
225+
}
226+
227+
// ------------------------------------------------------------------
228+
// Finalize
229+
// ------------------------------------------------------------------
230+
OceanState::clear();
231+
Tendencies::clear();
232+
PressureGrad::clear();
233+
AuxiliaryState::clear();
234+
Tracers::clear();
235+
IOStream::finalize();
236+
TimeStepper::clear();
237+
HorzMesh::clear();
238+
VertCoord::clear();
239+
Field::clear();
240+
Dimension::clear();
241+
Halo::clear();
242+
Decomp::clear();
243+
MachEnv::removeAll();
244+
}
245+
Pacer::finalize();
246+
Kokkos::finalize();
247+
MPI_Finalize();
248+
249+
CHECK_ERROR_ABORT(ErrAll, "FillValue unit tests FAIL");
250+
251+
return 0;
252+
}
253+
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)