Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
768efd1
Add wind forcing aux vars
mwarusz Mar 4, 2025
2c2e681
Refactor test helpers to also handle 1D fields
mwarusz Mar 7, 2025
e388683
Add a test for WindForcingAux
mwarusz Mar 7, 2025
2032459
Add wind forcing tendency term
mwarusz Mar 11, 2025
7e59f74
Test wind forcing tendency term
mwarusz Mar 11, 2025
2bd5ae0
Fix single precision tend test not running on planar mesh
mwarusz Mar 25, 2025
3e5bc43
Add bottom drag tendency term
mwarusz Mar 25, 2025
b20d41b
Add unit test for bottom drag tendency term
mwarusz Mar 25, 2025
7903896
Add computation of normal wind to wind forcing aux
mwarusz Mar 25, 2025
b467a8f
Add option to use absolute tolerance in test helpers
mwarusz Apr 2, 2025
c8f0607
Reformulate wind forcing in terms of stress
mwarusz Apr 2, 2025
28b1a0a
Add wind forcing and bottom drag to Tendencies
mwarusz Apr 2, 2025
da040da
Remove "Default" in aux vars names
mwarusz Apr 7, 2025
d75b2e6
Rename wind stress input fields
mwarusz Apr 7, 2025
e0ba780
Update docs
mwarusz Apr 7, 2025
b502913
Add exchangeHalo function to AuxiliaryState
mwarusz Apr 8, 2025
602c6b1
Exchange auxiliary state halo in ocnInit
mwarusz Apr 8, 2025
fa7e3e5
Fix names of wind forcing aux vars in docs
mwarusz May 13, 2025
b4ed972
Use density from config in wind forcing tendency
mwarusz May 13, 2025
3b549a0
Add InterpCellToEdge horizontal operator
mwarusz May 13, 2025
677d981
Use InterpCellToEdge in WindForcingAux
mwarusz May 13, 2025
1d3c340
Init Pacer in time stepper tests
mwarusz May 15, 2025
3b2cced
Remove halo exchange of wind stress at every step
mwarusz May 15, 2025
e98791a
Compute wind forcing aux in 1d parallelFor
mwarusz May 15, 2025
2bd6c87
Fix time stepper test
mwarusz May 15, 2025
f5599f3
Compute bottom drag in 1d parallelFor
mwarusz May 15, 2025
97139ab
Merge branch 'develop' into omega/wind-forcing-and-bottom-drag
philipwjones Jun 4, 2025
45f937c
fix bugs and linting errors introduced during WindForcing merge
philipwjones Jun 4, 2025
dfbd2c6
add readConfigOptions for testAuxState
mark-petersen Jun 11, 2025
388b3cc
add default for Enabled in BottomDragOnEdge constructor
mark-petersen Jun 12, 2025
4c1caf6
fix spacing
mark-petersen Jun 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion components/omega/configs/Default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ Omega:
Advection:
FluxThicknessType: Center
FluxTracerType: Center
WindStress:
InterpType: Isotropic
Tendencies:
ThicknessFluxTendencyEnable: true
PVTendencyEnable: true
Expand All @@ -26,6 +28,10 @@ Omega:
VelHyperDiffTendencyEnable: true
ViscDel4: 1.2e11
DivFactor: 1.0
WindForcingTendencyEnable: false
Density0: 1026.0
BottomDragTendencyEnable: false
BottomDragCoeff: 0.0
TracerHorzAdvTendencyEnable: true
TracerDiffTendencyEnable: true
EddyDiff2: 10.0
Expand Down Expand Up @@ -91,7 +97,7 @@ Omega:
Contents:
- Tracers
- State
- SshCellDefault
- SshCell
Highfreq:
UsePointerFile: false
Filename: ocn.hifreq.$Y-$M
Expand Down
3 changes: 3 additions & 0 deletions components/omega/doc/devGuide/AuxiliaryVariables.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,6 @@ The following auxiliary variable groups are currently implemented:
|| Del2RelVortVertex ||
| TracerAuxVars | HTracersEdge | Center or Upwind|
|| Del2TracersCell ||
| WindForcingAuxVars | ZonalStressCell ||
|| MeridStressCell ||
|| NormalStressEdge ||
2 changes: 2 additions & 0 deletions components/omega/doc/devGuide/TendencyTerms.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ implemented:
- `TracerHorzAdvOnCell`
- `TracerDiffOnCell`
- `TracerHyperDiffOnCell`
- `WindForcingOnEdge`
- `BottomDragOnEdge`
3 changes: 3 additions & 0 deletions components/omega/doc/userGuide/AuxiliaryVariables.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ The following auxiliary variables are currently available:
| VelDel2RelVortVertex | curl of laplacian of horizontal velocity on cells
| HTracersEdge | thickness-weighted tracers used for fluxes through edges. May be centered, upwinded or a combination of the two
| Del2TracersCell | laplacian of tracers on cells
| ZonalStressCell | zonal component of wind stress on cells
| MeridStressCell | meridional component of wind stress on cells
| NormalStressEdge | normal component of wind stress on edge
Copy link
Collaborator

Choose a reason for hiding this comment

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

generic comment - do we want this in AuxState? Would it make sense to have a 'forcing module' where this lives?

Copy link
Member Author

Choose a reason for hiding this comment

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

These are grouped in the WindForcingAuxVars class, so they aren't directly members of the aux state class. This is mentioned in the dev docs, but maybe it should also included be in the user docs.

5 changes: 5 additions & 0 deletions components/omega/doc/userGuide/TendencyTerms.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ tendency terms are currently implemented:
| TracerHorzAdvOnCell | horizontal advection of thickness-weighted tracers
| TracerDiffOnCell | horizontal diffusion of thickness-weighted tracers
| TracerHyperDiffOnCell | biharmonic horizontal mixing of thickness-weighted tracers
| WindForcingOnEdge | forcing by wind stress, defined on edges
| BottomDragOnEdge | bottom drag, defined on edges

Among the internal data stored by each functor is a `bool` which can enable or
disable the contribution of that particular term to the tendency. These flags
Expand Down Expand Up @@ -45,3 +47,6 @@ the currently available tendency terms:
| | EddyDiff2 | horizontal diffusion coefficient
| TracerHyperDiffOnCell | TracerHyperDiffTendencyEnable | enable/disable term
| | EddyDiff4 | biharmonic horizontal mixing coeffienct for tracers
| WindForcingOnEdge | WindForcingTendencyEnable | enable/disable term
| BottomDragOnEdge | BottomDragTendencyEnable | enable/disable term
| | BottomDragCoeff | bottom drag coefficient
71 changes: 59 additions & 12 deletions components/omega/src/ocn/AuxiliaryState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,21 @@ AuxiliaryState *AuxiliaryState::DefaultAuxState = nullptr;
std::map<std::string, std::unique_ptr<AuxiliaryState>>
AuxiliaryState::AllAuxStates;

static std::string stripDefault(const std::string &Name) {
return Name != "Default" ? Name : "";
}

// Constructor. Constructs the member auxiliary variables and registers their
// fields with IOStreams
AuxiliaryState::AuxiliaryState(const std::string &Name, const HorzMesh *Mesh,
int NVertLevels, int NTracers)
: Mesh(Mesh), Name(Name), KineticAux(Name, Mesh, NVertLevels),
LayerThicknessAux(Name, Mesh, NVertLevels),
VorticityAux(Name, Mesh, NVertLevels),
VelocityDel2Aux(Name, Mesh, NVertLevels),
TracerAux(Name, Mesh, NVertLevels, NTracers) {
Halo *MeshHalo, int NVertLevels, int NTracers)
: Mesh(Mesh), MeshHalo(MeshHalo), Name(stripDefault(Name)),
KineticAux(stripDefault(Name), Mesh, NVertLevels),
LayerThicknessAux(stripDefault(Name), Mesh, NVertLevels),
VorticityAux(stripDefault(Name), Mesh, NVertLevels),
VelocityDel2Aux(stripDefault(Name), Mesh, NVertLevels),
WindForcingAux(stripDefault(Name), Mesh),
TracerAux(stripDefault(Name), Mesh, NVertLevels, NTracers) {

GroupName = "AuxiliaryState";
if (Name != "Default") {
Expand All @@ -32,6 +38,7 @@ AuxiliaryState::AuxiliaryState(const std::string &Name, const HorzMesh *Mesh,
LayerThicknessAux.registerFields(GroupName, AuxMeshName);
VorticityAux.registerFields(GroupName, AuxMeshName);
VelocityDel2Aux.registerFields(GroupName, AuxMeshName);
WindForcingAux.registerFields(GroupName, AuxMeshName);
TracerAux.registerFields(GroupName, AuxMeshName);
}

Expand All @@ -42,6 +49,7 @@ AuxiliaryState::~AuxiliaryState() {
LayerThicknessAux.unregisterFields();
VorticityAux.unregisterFields();
VelocityDel2Aux.unregisterFields();
WindForcingAux.unregisterFields();
TracerAux.unregisterFields();

int Err = FieldGroup::destroy(GroupName);
Expand All @@ -64,6 +72,7 @@ void AuxiliaryState::computeMomAux(const OceanState *State, int ThickTimeLevel,
OMEGA_SCOPE(LocLayerThicknessAux, LayerThicknessAux);
OMEGA_SCOPE(LocVorticityAux, VorticityAux);
OMEGA_SCOPE(LocVelocityDel2Aux, VelocityDel2Aux);
OMEGA_SCOPE(LocWindForcingAux, WindForcingAux);

parallelFor(
"vertexAuxState1", {Mesh->NVerticesAll, NChunks},
Expand All @@ -82,7 +91,12 @@ void AuxiliaryState::computeMomAux(const OceanState *State, int ThickTimeLevel,
const auto &RelVortVertex = VorticityAux.RelVortVertex;

parallelFor(
"edgeAuxState1", {Mesh->NEdgesAll, NChunks},
"edgeAuxState1", {Mesh->NEdgesAll}, KOKKOS_LAMBDA(int IEdge) {
LocWindForcingAux.computeVarsOnEdge(IEdge);
});

parallelFor(
"edgeAuxState2", {Mesh->NEdgesAll, NChunks},
KOKKOS_LAMBDA(int IEdge, int KChunk) {
LocVorticityAux.computeVarsOnEdge(IEdge, KChunk);
LocLayerThicknessAux.computeVarsOnEdge(IEdge, KChunk, LayerThickCell,
Expand Down Expand Up @@ -153,16 +167,17 @@ void AuxiliaryState::computeAll(const OceanState *State,

// Create a non-default auxiliary state
AuxiliaryState *AuxiliaryState::create(const std::string &Name,
const HorzMesh *Mesh, int NVertLevels,
const int NTracers) {
const HorzMesh *Mesh, Halo *MeshHalo,
int NVertLevels, const int NTracers) {
if (AllAuxStates.find(Name) != AllAuxStates.end()) {
LOG_ERROR("Attempted to create a new AuxiliaryState with name {} but it "
"already exists",
Name);
return nullptr;
}

auto *NewAuxState = new AuxiliaryState(Name, Mesh, NVertLevels, NTracers);
auto *NewAuxState =
new AuxiliaryState(Name, Mesh, MeshHalo, NVertLevels, NTracers);
AllAuxStates.emplace(Name, NewAuxState);

return NewAuxState;
Expand All @@ -172,12 +187,13 @@ AuxiliaryState *AuxiliaryState::create(const std::string &Name,
// initialized.
void AuxiliaryState::init() {
const HorzMesh *DefMesh = HorzMesh::getDefault();
Halo *DefHalo = Halo::getDefault();

int NVertLevels = DefMesh->NVertLevels;
int NTracers = Tracers::getNumTracers();

AuxiliaryState::DefaultAuxState =
AuxiliaryState::create("Default", DefMesh, NVertLevels, NTracers);
AuxiliaryState::DefaultAuxState = AuxiliaryState::create(
"Default", DefMesh, DefHalo, NVertLevels, NTracers);

Config *OmegaConfig = Config::getOmegaConfig();
DefaultAuxState->readConfigOptions(OmegaConfig);
Expand Down Expand Up @@ -248,6 +264,37 @@ void AuxiliaryState::readConfigOptions(Config *OmegaConfig) {
} else {
ABORT_ERROR("AuxiliaryState: Unknown FluxTracerType requested");
}

Config WindStressConfig("WindStress");
Err += OmegaConfig->get(WindStressConfig);

std::string WindStressInterpTypeStr;
Err += WindStressConfig.get("InterpType", WindStressInterpTypeStr);
CHECK_ERROR_ABORT(
Err, "AuxiliaryState: InterpType not found in WindStressConfig");

if (WindStressInterpTypeStr == "Isotropic") {
this->WindForcingAux.InterpChoice = InterpCellToEdgeOption::Isotropic;
} else if (WindStressInterpTypeStr == "Anisotropic") {
this->WindForcingAux.InterpChoice = InterpCellToEdgeOption::Anisotropic;
} else {
ABORT_ERROR("AuxiliaryState: Unknown InterpType requested");
}
}

//------------------------------------------------------------------------------
// Perform auxiliary state halo exchange
// Note that only non-computed auxiliary variables needs to be exchanged
I4 AuxiliaryState::exchangeHalo() {
I4 Err = 0;

Err +=
MeshHalo->exchangeFullArrayHalo(WindForcingAux.ZonalStressCell, OnCell);
Err +=
MeshHalo->exchangeFullArrayHalo(WindForcingAux.MeridStressCell, OnCell);

return Err;

} // end exchangeHalo

} // namespace OMEGA
11 changes: 9 additions & 2 deletions components/omega/src/ocn/AuxiliaryState.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "Config.h"
#include "DataTypes.h"
#include "Halo.h"
#include "HorzMesh.h"
#include "OceanState.h"
#include "Tracers.h"
Expand All @@ -11,6 +12,7 @@
#include "auxiliaryVars/TracerAuxVars.h"
#include "auxiliaryVars/VelocityDel2AuxVars.h"
#include "auxiliaryVars/VorticityAuxVars.h"
#include "auxiliaryVars/WindForcingAuxVars.h"

#include <memory>
#include <string>
Expand All @@ -36,6 +38,7 @@ class AuxiliaryState {
TracerAuxVars TracerAux;
VorticityAuxVars VorticityAux;
VelocityDel2AuxVars VelocityDel2Aux;
WindForcingAuxVars WindForcingAux;

~AuxiliaryState();

Expand All @@ -46,7 +49,7 @@ class AuxiliaryState {

// Create a non-default auxiliary state
static AuxiliaryState *create(const std::string &Name, const HorzMesh *Mesh,
int NVertLevels, int NTracers);
Halo *MeshHalo, int NVertLevels, int NTracers);

/// Get the default auxiliary state
static AuxiliaryState *getDefault();
Expand All @@ -63,6 +66,9 @@ class AuxiliaryState {
/// Read and set config options
void readConfigOptions(Config *OmegaConfig);

/// Exchange halo
I4 exchangeHalo();

// Compute all auxiliary variables needed for momentum equation
void computeMomAux(const OceanState *State, int ThickTimeLevel,
int VelTimeLevel) const;
Expand All @@ -75,13 +81,14 @@ class AuxiliaryState {
int TimeLevel) const;

private:
AuxiliaryState(const std::string &Name, const HorzMesh *Mesh,
AuxiliaryState(const std::string &Name, const HorzMesh *Mesh, Halo *MeshHalo,
int NVertLevels, int NTracers);

AuxiliaryState(const AuxiliaryState &) = delete;
AuxiliaryState(AuxiliaryState &&) = delete;

const HorzMesh *Mesh;
Halo *MeshHalo;
static AuxiliaryState *DefaultAuxState;
static std::map<std::string, std::unique_ptr<AuxiliaryState>> AllAuxStates;
};
Expand Down
6 changes: 6 additions & 0 deletions components/omega/src/ocn/HorzOperators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ TangentialReconOnEdge::TangentialReconOnEdge(HorzMesh const *Mesh)
: NEdgesOnEdge(Mesh->NEdgesOnEdge), EdgesOnEdge(Mesh->EdgesOnEdge),
WeightsOnEdge(Mesh->WeightsOnEdge) {}

InterpCellToEdge::InterpCellToEdge(const HorzMesh *Mesh)
: CellsOnEdge(Mesh->CellsOnEdge), VerticesOnEdge(Mesh->VerticesOnEdge),
CellsOnVertex(Mesh->CellsOnVertex),
KiteAreasOnVertex(Mesh->KiteAreasOnVertex),
VertexDegree(Mesh->VertexDegree) {}

} // namespace OMEGA
52 changes: 52 additions & 0 deletions components/omega/src/ocn/HorzOperators.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,57 @@ class TangentialReconOnEdge {
Array2DReal WeightsOnEdge;
};

enum class InterpCellToEdgeOption { Anisotropic, Isotropic };

class InterpCellToEdge {
public:
InterpCellToEdge(const HorzMesh *Mesh);

KOKKOS_FUNCTION Real operator()(int IEdge, const Array1DReal &ArrayCell,
InterpCellToEdgeOption Option) const {
switch (Option) {
case InterpCellToEdgeOption::Anisotropic:
return interpolateAnisotropic(IEdge, ArrayCell);
case InterpCellToEdgeOption::Isotropic:
return interpolateIsotropic(IEdge, ArrayCell);
}
};

KOKKOS_FUNCTION Real
interpolateAnisotropic(int IEdge, const Array1DReal &ArrayCell) const {
const int JCell0 = CellsOnEdge(IEdge, 0);
const int JCell1 = CellsOnEdge(IEdge, 1);

return 0.5_Real * (ArrayCell(JCell0) + ArrayCell(JCell1));
};

KOKKOS_FUNCTION Real
interpolateIsotropic(int IEdge, const Array1DReal &ArrayCell) const {

Real Accum = 0;
Real AreaAccum = 0;
for (int J = 0; J < 2; ++J) {
const int JVertex = VerticesOnEdge(IEdge, J);
for (int L = 0; L < VertexDegree; ++L) {
const Real KiteArea = KiteAreasOnVertex(JVertex, L);
const int LCell = CellsOnVertex(JVertex, L);

Accum += ArrayCell(LCell) * KiteArea;
AreaAccum += KiteArea;
}
}

const Real InvAreaAccum = 1._Real / AreaAccum;
return Accum * InvAreaAccum;
};

private:
Array2DI4 CellsOnEdge;
Array2DI4 VerticesOnEdge;
Array2DI4 CellsOnVertex;
Array2DReal KiteAreasOnVertex;
I4 VertexDegree;
};

} // namespace OMEGA
#endif
6 changes: 5 additions & 1 deletion components/omega/src/ocn/OceanInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,17 @@ int initOmegaModules(MPI_Comm Comm) {
}
}

// Update Halos and Host arrays with new state and tracer fields
// Update Halos and Host arrays with new state, auxiliary state, and tracer
// fields

OceanState *DefState = OceanState::getDefault();
I4 CurTimeLevel = 0;
DefState->exchangeHalo(CurTimeLevel);
DefState->copyToHost(CurTimeLevel);

AuxiliaryState *DefAuxState = AuxiliaryState::getDefault();
DefAuxState->exchangeHalo();

// Now update tracers - assume using same time level index
Err = Tracers::exchangeHalo(CurTimeLevel);
if (Err != 0) {
Expand Down
Loading
Loading