Skip to content

Commit 9054c43

Browse files
Merge pull request #170 from hyungyukang/omega/add-manufactured-tendencies
Add manufactured solution tendency terms to Omega
2 parents cdaabc3 + 11846a0 commit 9054c43

File tree

5 files changed

+361
-1
lines changed

5 files changed

+361
-1
lines changed

components/omega/configs/Default.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ Omega:
3030
EddyDiff2: 10.0
3131
TracerHyperDiffTendencyEnable: true
3232
EddyDiff4: 0.0
33+
UseCustomTendency: false
34+
ManufacturedSolutionTendency: false
3335
Tracers:
3436
Base: [Temperature, Salinity]
3537
Debug: [Debug1, Debug2, Debug3]
@@ -102,3 +104,7 @@ Omega:
102104
EndTime: 0001-06-30_00:00:00
103105
Contents:
104106
- Tracers
107+
ManufacturedSolution:
108+
WavelengthX: 5.0e6
109+
WavelengthY: 4.33013e6
110+
Amplitude: 1.0
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
//===-- ocn/CustomTendencyTerms.cpp - Custom tendency terms -----*- C++ -*-===//
2+
//
3+
// The customized tendency terms can be added to the tendency terms based
4+
// based on an option 'UseCustomTendency' in Tendencies Config group.
5+
// This file contains functions for initializing customized tendency terms.
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "CustomTendencyTerms.h"
10+
#include "Config.h"
11+
#include "TimeStepper.h"
12+
13+
namespace OMEGA {
14+
15+
//===-----------------------------------------------------------------------===/
16+
// Initialize the manufactured solution tendency terms.
17+
//===-----------------------------------------------------------------------===/
18+
int ManufacturedSolution::init() {
19+
int Err;
20+
21+
// Get ManufacturedSolConfig group
22+
Config *OmegaConfig = Config::getOmegaConfig();
23+
Config ManufacturedSolConfig("ManufacturedSolution");
24+
Err = OmegaConfig->get(ManufacturedSolConfig);
25+
if (Err != 0) {
26+
LOG_CRITICAL("ManufacturedSolution:: ManufacturedSolution group "
27+
"not found in Config");
28+
return Err;
29+
}
30+
31+
// Get TendConfig group
32+
Config TendConfig("Tendencies");
33+
Err = OmegaConfig->get(TendConfig);
34+
if (Err != 0) {
35+
LOG_CRITICAL("ManufacturedSolution:: Tendencies group "
36+
"not found in Config");
37+
return Err;
38+
}
39+
40+
// Get manufactured solution parameters from Config
41+
R8 WavelengthX;
42+
R8 WavelengthY;
43+
R8 Amplitude;
44+
45+
Err = ManufacturedSolConfig.get("WavelengthX", WavelengthX);
46+
if (Err != 0) {
47+
LOG_ERROR("ManufacturedSolution:: WavelengthX not found in "
48+
"ManufacturedSolConfig");
49+
return Err;
50+
}
51+
52+
Err = ManufacturedSolConfig.get("WavelengthY", WavelengthY);
53+
if (Err != 0) {
54+
LOG_ERROR("ManufacturedSolution:: WavelengthY not found in "
55+
"ManufacturedSolConfig");
56+
return Err;
57+
}
58+
59+
Err = ManufacturedSolConfig.get("Amplitude", Amplitude);
60+
if (Err != 0) {
61+
LOG_ERROR("ManufacturedSolution:: Amplitude not found in "
62+
"ManufacturedSolConfig");
63+
return Err;
64+
}
65+
66+
// Get Tendendices parameters for del2 and del4 source terms
67+
Err = TendConfig.get("VelDiffTendencyEnable",
68+
ManufacturedVelTend.VelDiffTendencyEnable);
69+
Err += TendConfig.get("VelHyperDiffTendencyEnable",
70+
ManufacturedVelTend.VelHyperDiffTendencyEnable);
71+
Err += TendConfig.get("ViscDel2", ManufacturedVelTend.ViscDel2);
72+
Err += TendConfig.get("ViscDel4", ManufacturedVelTend.ViscDel4);
73+
74+
if (Err != 0) {
75+
LOG_ERROR("ManufacturedSolution::Error reading Tendencies config");
76+
return Err;
77+
}
78+
79+
// Get the reference time to compute the model elapsed time
80+
/// Get model clock from time stepper
81+
TimeStepper *DefStepper = TimeStepper::getDefault();
82+
Clock *ModelClock = DefStepper->getClock();
83+
ManufacturedThickTend.ReferenceTime = ModelClock->getCurrentTime();
84+
ManufacturedVelTend.ReferenceTime = ManufacturedThickTend.ReferenceTime;
85+
86+
// Get BottomDepth for the resting thickness
87+
/// This test case assumes that the restingThickness is horizontally uniform
88+
/// and that only one vertical level is used so only one set of indices is
89+
/// used here.
90+
HorzMesh *DefHorzMesh = HorzMesh::getDefault();
91+
R8 H0 = DefHorzMesh->BottomDepthH(0);
92+
93+
// Define and compute common constants
94+
R8 Grav = 9.80665_Real; // Gravity acceleration
95+
R8 Pii = 3.141592653589793_Real; // Pi
96+
R8 Kx = 2.0_Real * Pii / WavelengthX; // Wave in X-dir
97+
R8 Ky = 2.0_Real * Pii / WavelengthY; // Wave in Y-dir
98+
R8 AngFreq = sqrt(H0 * Grav * (Kx * Kx + Ky * Ky)); // Angular frequency
99+
100+
// Assign constants for thickness tendency function
101+
ManufacturedThickTend.H0 = H0;
102+
ManufacturedThickTend.Eta0 = Amplitude;
103+
ManufacturedThickTend.Kx = Kx;
104+
ManufacturedThickTend.Ky = Ky;
105+
ManufacturedThickTend.AngFreq = AngFreq;
106+
107+
// Assign constants for velocity tendency function
108+
ManufacturedVelTend.Grav = Grav;
109+
ManufacturedVelTend.Eta0 = Amplitude;
110+
ManufacturedVelTend.Kx = Kx;
111+
ManufacturedVelTend.Ky = Ky;
112+
ManufacturedVelTend.AngFreq = AngFreq;
113+
114+
return Err;
115+
116+
} // end ManufacturedSolution init
117+
118+
//===--------------------------------------------------------------------===/
119+
// Manufactured tendency term for the thickness equation
120+
//===--------------------------------------------------------------------===/
121+
void ManufacturedSolution::ManufacturedThicknessTendency::operator()(
122+
Array2DReal ThicknessTend, const OceanState *State,
123+
const AuxiliaryState *AuxState, int ThickTimeLevel, int VelTimeLevel,
124+
TimeInstant Time) const {
125+
126+
// Get elapsed time since reference time
127+
R8 ElapsedTimeSec;
128+
TimeInterval ElapsedTimeInterval = Time - ReferenceTime;
129+
ElapsedTimeInterval.get(ElapsedTimeSec, TimeUnits::Seconds);
130+
131+
auto *Mesh = HorzMesh::getDefault();
132+
auto NVertLevels = ThicknessTend.extent_int(1);
133+
134+
Array1DReal XCell = Mesh->XCell;
135+
Array1DReal YCell = Mesh->YCell;
136+
137+
OMEGA_SCOPE(LocH0, H0);
138+
OMEGA_SCOPE(LocEta0, Eta0);
139+
OMEGA_SCOPE(LocKx, Kx);
140+
OMEGA_SCOPE(LocKy, Ky);
141+
OMEGA_SCOPE(LocAngFreq, AngFreq);
142+
143+
parallelFor(
144+
{Mesh->NCellsAll, NVertLevels}, KOKKOS_LAMBDA(int ICell, int KLevel) {
145+
R8 X = XCell(ICell);
146+
R8 Y = YCell(ICell);
147+
R8 Phase = LocKx * X + LocKy * Y - LocAngFreq * ElapsedTimeSec;
148+
ThicknessTend(ICell, KLevel) +=
149+
LocEta0 *
150+
(-LocH0 * (LocKx + LocKy) * sin(Phase) - LocAngFreq * cos(Phase) +
151+
LocEta0 * (LocKx + LocKy) * cos(2.0_Real * Phase));
152+
});
153+
154+
} // end void ManufacturedThicknessTendency
155+
156+
//===--------------------------------------------------------------------===/
157+
// Manufactured tendency term for the momentum equation
158+
//===--------------------------------------------------------------------===/
159+
void ManufacturedSolution::ManufacturedVelocityTendency::operator()(
160+
Array2DReal NormalVelTend, const OceanState *State,
161+
const AuxiliaryState *AuxState, int ThickTimeLevel, int VelTimeLevel,
162+
TimeInstant Time) const {
163+
164+
// Get elapsed time since reference time
165+
R8 ElapsedTimeSec;
166+
TimeInterval ElapsedTimeInterval = Time - ReferenceTime;
167+
ElapsedTimeInterval.get(ElapsedTimeSec, TimeUnits::Seconds);
168+
169+
auto *Mesh = HorzMesh::getDefault();
170+
auto NVertLevels = NormalVelTend.extent_int(1);
171+
172+
Array1DReal FEdge = Mesh->FEdge;
173+
Array1DReal XEdge = Mesh->XEdge;
174+
Array1DReal YEdge = Mesh->YEdge;
175+
Array1DReal AngleEdge = Mesh->AngleEdge;
176+
177+
OMEGA_SCOPE(LocGrav, Grav);
178+
OMEGA_SCOPE(LocEta0, Eta0);
179+
OMEGA_SCOPE(LocKx, Kx);
180+
OMEGA_SCOPE(LocKy, Ky);
181+
OMEGA_SCOPE(LocAngFreq, AngFreq);
182+
OMEGA_SCOPE(LocViscDel2, ViscDel2);
183+
OMEGA_SCOPE(LocViscDel4, ViscDel4);
184+
OMEGA_SCOPE(LocVelDiffTendencyEnable, VelDiffTendencyEnable);
185+
OMEGA_SCOPE(LocVelHyperDiffTendencyEnable, VelHyperDiffTendencyEnable);
186+
187+
R8 LocKx2 = LocKx * LocKx;
188+
R8 LocKy2 = LocKy * LocKy;
189+
R8 LocKx4 = LocKx2 * LocKx2;
190+
R8 LocKy4 = LocKy2 * LocKy2;
191+
192+
parallelFor(
193+
{Mesh->NEdgesAll, NVertLevels}, KOKKOS_LAMBDA(int IEdge, int KLevel) {
194+
R8 X = XEdge(IEdge);
195+
R8 Y = YEdge(IEdge);
196+
197+
R8 Phase = LocKx * X + LocKy * Y - LocAngFreq * ElapsedTimeSec;
198+
R8 SourceTerm0 = LocAngFreq * sin(Phase) - 0.5_Real * LocEta0 *
199+
(LocKx + LocKy) *
200+
sin(2.0_Real * Phase);
201+
202+
R8 U = LocEta0 *
203+
((-FEdge(IEdge) + LocGrav * LocKx) * cos(Phase) + SourceTerm0);
204+
R8 V = LocEta0 *
205+
((FEdge(IEdge) + LocGrav * LocKy) * cos(Phase) + SourceTerm0);
206+
207+
// Del2 and del4 source terms
208+
if (LocVelDiffTendencyEnable) {
209+
U += LocViscDel2 * LocEta0 * (LocKx2 + LocKy2) * cos(Phase);
210+
V += LocViscDel2 * LocEta0 * (LocKx2 + LocKy2) * cos(Phase);
211+
}
212+
if (LocVelHyperDiffTendencyEnable) {
213+
U -= LocViscDel4 * LocEta0 *
214+
((LocKx4 + LocKy4 + LocKx2 * LocKy2) * cos(Phase));
215+
V -= LocViscDel4 * LocEta0 *
216+
((LocKx4 + LocKy4 + LocKx2 * LocKy2) * cos(Phase));
217+
}
218+
219+
R8 NormalCompSourceTerm =
220+
cos(AngleEdge(IEdge)) * U + sin(AngleEdge(IEdge)) * V;
221+
NormalVelTend(IEdge, KLevel) += NormalCompSourceTerm;
222+
});
223+
224+
} // end void ManufacturedVelocityTendency
225+
226+
} // end namespace OMEGA
227+
228+
//=-------------------------------------------------------------------------===/
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#ifndef OMEGA_CUSTOMTENDENCYTERMS_H
2+
#define OMEGA_CUSTOMTENDENCYTERMS_H
3+
//===-- ocn/CustomTendencyTerms.h - Custom tendency terms -------*- C++ -*-===//
4+
//
5+
/// \file
6+
/// \brief Contains customized tendency terms for the thickness and momentum
7+
/// equations
8+
///
9+
/// For details on the manufactured solution class, see Bishnu et al. (2024)
10+
/// (https://doi.org/10.1029/2022MS003545) and the manufactured solution test
11+
/// case in Polaris. The Polaris package leverages this feature to validate
12+
/// an expected order of convergence of Omega.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#include "HorzMesh.h"
17+
#include "TendencyTerms.h"
18+
#include "TimeMgr.h"
19+
20+
namespace OMEGA {
21+
22+
//===-----------------------------------------------------------------------===/
23+
// A class for the manufactured solution tendency terms
24+
//===-----------------------------------------------------------------------===/
25+
class ManufacturedSolution {
26+
27+
public:
28+
//===--------------------------------------------------------------------===/
29+
// Manufactured tendency term for the thickness equation
30+
//===--------------------------------------------------------------------===/
31+
struct ManufacturedThicknessTendency {
32+
33+
// Constants defined in 'init'
34+
TimeInstant ReferenceTime;
35+
R8 H0;
36+
R8 Eta0;
37+
R8 Kx;
38+
R8 Ky;
39+
R8 AngFreq;
40+
41+
void operator()(Array2DReal ThicknessTend, const OceanState *State,
42+
const AuxiliaryState *AuxState, int ThickTimeLevel,
43+
int VelTimeLevel, TimeInstant Time) const;
44+
}; // end struct ManufacturedThicknessTendency
45+
46+
//===--------------------------------------------------------------------===/
47+
// Manufactured tendency term for the momentum equation
48+
//===--------------------------------------------------------------------===/
49+
struct ManufacturedVelocityTendency {
50+
51+
// Constants defined in 'init'
52+
TimeInstant ReferenceTime;
53+
R8 Grav;
54+
R8 Eta0;
55+
R8 Kx;
56+
R8 Ky;
57+
R8 AngFreq;
58+
R8 ViscDel2;
59+
R8 ViscDel4;
60+
bool VelDiffTendencyEnable;
61+
bool VelHyperDiffTendencyEnable;
62+
63+
void operator()(Array2DReal NormalVelTend, const OceanState *State,
64+
const AuxiliaryState *AuxState, int ThickTimeLevel,
65+
int VelTimeLevel, TimeInstant Time) const;
66+
67+
}; // end struct ManufacturedVelocityTendency
68+
69+
// Instances of manufactured tendencies
70+
ManufacturedThicknessTendency ManufacturedThickTend;
71+
ManufacturedVelocityTendency ManufacturedVelTend;
72+
73+
int init();
74+
75+
}; // end class ManufacturedSolution
76+
77+
} // end namespace OMEGA
78+
79+
//===-----------------------------------------------------------------------===/
80+
81+
#endif

components/omega/src/ocn/HorzMesh.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ void HorzMesh::copyToDevice() {
690690
WeightsOnEdge = createDeviceMirrorCopy(WeightsOnEdgeH);
691691
FVertex = createDeviceMirrorCopy(FVertexH);
692692
BottomDepth = createDeviceMirrorCopy(BottomDepthH);
693+
FEdge = createDeviceMirrorCopy(FEdgeH);
693694
XCell = createDeviceMirrorCopy(XCellH);
694695
YCell = createDeviceMirrorCopy(YCellH);
695696
XEdge = createDeviceMirrorCopy(XEdgeH);

components/omega/src/ocn/Tendencies.cpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//===----------------------------------------------------------------------===//
1010

1111
#include "Tendencies.h"
12+
#include "CustomTendencyTerms.h"
1213
#include "Tracers.h"
1314

1415
namespace OMEGA {
@@ -35,8 +36,51 @@ int Tendencies::init() {
3536
return Err;
3637
}
3738

39+
// Check if use the customized tendencies
40+
bool UseCustomTendency = false;
41+
Err = TendConfig.get("UseCustomTendency", UseCustomTendency);
42+
if (Err != 0) {
43+
LOG_ERROR("Tendencies:: UseCustomTendency not found in Config");
44+
return Err;
45+
}
46+
47+
/// Instances of custom tendencies - empty by default
48+
CustomTendencyType CustomThickTend;
49+
CustomTendencyType CustomVelTend;
50+
51+
if (UseCustomTendency) {
52+
// Check if use manufactured tendency terms
53+
bool ManufacturedTend = false;
54+
I4 ManufacturedTendErr =
55+
TendConfig.get("ManufacturedSolutionTendency", ManufacturedTend);
56+
57+
if (ManufacturedTendErr != 0 && ManufacturedTend) {
58+
LOG_CRITICAL("Tendencies: ManufacturedSolutionTendency "
59+
"not found in TendConfig");
60+
return ManufacturedTendErr;
61+
}
62+
63+
if (ManufacturedTend) {
64+
ManufacturedSolution ManufacturedSol;
65+
I4 ManufacturedInitErr = ManufacturedSol.init();
66+
67+
if (ManufacturedInitErr != 0) {
68+
LOG_CRITICAL("Error in initializing the manufactured solution "
69+
"tendency terms");
70+
return ManufacturedInitErr;
71+
}
72+
73+
CustomThickTend = ManufacturedSol.ManufacturedThickTend;
74+
CustomVelTend = ManufacturedSol.ManufacturedVelTend;
75+
76+
} // if ManufacturedTend
77+
78+
} // end if UseCustomTendency
79+
80+
// Ceate default tendencies
3881
Tendencies::DefaultTendencies =
39-
create("Default", DefHorzMesh, NVertLevels, NTracers, &TendConfig);
82+
create("Default", DefHorzMesh, NVertLevels, NTracers, &TendConfig,
83+
CustomThickTend, CustomVelTend);
4084

4185
Err = DefaultTendencies->readTendConfig(&TendConfig);
4286

0 commit comments

Comments
 (0)