Skip to content

Commit 83f2bfb

Browse files
Merge pull request #53 from nextsimdg/feat_mvm
Minimum viable model
2 parents b579f34 + 0535990 commit 83f2bfb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1901
-195
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@
55
/.settings/*
66
/src/modules/generated/moduleLoader*.ipp
77
/*/src/modules/generated/moduleLoader*.ipp
8+
/run/restart.nc
9+
/run/nextsim
10+
/run/.DS_Store

CMakeLists.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,20 @@ set(CMAKE_CXX_STANDARD 11)
44

55
project(framework_dg)
66

7+
set (NETCDF_CXX "YES")
78
find_package(netCDF REQUIRED)
9+
if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Darwin")
10+
set(NSDG_NetCDF_Library "netcdf-cxx4")
11+
else()
12+
set(NSDG_NetCDF_Library "netcdf_c++4")
13+
endif()
814
find_package(Boost COMPONENTS program_options REQUIRED)
915
find_package(Catch2 REQUIRED)
1016

1117
# To add netCDF to a target:
1218
# target_include_directories(target PUBLIC ${netCDF_INCLUDE_DIR})
1319
# target_link_directories(target PUBLIC ${netCDF_LIB_DIR})
14-
# target_link_libraries(target LINK_PUBLIC netcdf-cxx4)
20+
# target_link_libraries(target LINK_PUBLIC "${NSDG_NetCDF_Library}")
1521

1622
# Set the location of the ipp files used by ModuleLoader for the main build
1723
set(ModuleLoaderIppTargetDirectory
@@ -53,8 +59,10 @@ target_include_directories(nextsim PRIVATE
5359
"${Boost_INCLUDE_DIRS}"
5460
"${ModuleLoaderIppTargetDirectory}"
5561
"${NextsimIncludeDirs}"
62+
"${netCDF_INCLUDE_DIR}"
5663
)
57-
target_link_libraries(nextsim LINK_PUBLIC ${Boost_LIBRARIES})
64+
target_link_directories(nextsim PUBLIC "${netCDF_LIB_DIR}")
65+
target_link_libraries(nextsim LINK_PUBLIC ${Boost_LIBRARIES} "${NSDG_NetCDF_Library}")
5866

5967
#The parse_modules target is inherited from src
6068
add_dependencies(nextsim parse_modules)

core/src/CMakeLists.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,37 @@ set(BaseSources
1111
"ConfiguredModule.cpp"
1212
"CommandLineParser.cpp"
1313
"ModuleLoader.cpp"
14+
"ElementData.cpp"
1415
"PrognosticData.cpp"
1516
"ExternalData.cpp"
17+
"DevGridIO.cpp"
18+
"DevStep.cpp"
19+
"StructureFactory.cpp"
1620
)
1721

1822
list(TRANSFORM BaseSources PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/")
1923

24+
set(ModuleDir "${CMAKE_CURRENT_SOURCE_DIR}/modules")
25+
26+
set(StructureModuleSources
27+
"DevGrid.cpp"
28+
)
29+
30+
set(ModuleSources
31+
"${StructureModuleSources}"
32+
)
33+
34+
list(TRANSFORM ModuleSources PREPEND "${ModuleDir}/")
35+
2036
set(NextsimSources
2137
"${NextsimSources}"
2238
"${BaseSources}"
39+
"${ModuleSources}"
2340
PARENT_SCOPE)
2441

2542
set(NextsimIncludeDirs
2643
"${NextsimIncludeDirs}"
44+
"${ModuleDir}"
2745
"${CMAKE_CURRENT_SOURCE_DIR}"
2846
PARENT_SCOPE)
2947

core/src/DevGridIO.cpp

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/*!
2+
* @file DevGridIO.cpp
3+
*
4+
* @date Jan 14, 2022
5+
* @author Tim Spain <timothy.spain@nersc.no>
6+
*/
7+
8+
#include "include/DevGridIO.hpp"
9+
10+
#include "include/DevGrid.hpp"
11+
#include "include/ElementData.hpp"
12+
#include "include/IStructure.hpp"
13+
14+
#include <cstddef>
15+
#include <ncDim.h>
16+
#include <ncDouble.h>
17+
#include <ncFile.h>
18+
#include <ncVar.h>
19+
20+
#include <map>
21+
#include <vector>
22+
23+
namespace Nextsim {
24+
25+
// Forward declarations
26+
enum class StringName {
27+
METADATA_NODE,
28+
DATA_NODE,
29+
STRUCTURE,
30+
X_DIM,
31+
Y_DIM,
32+
Z_DIM,
33+
};
34+
35+
std::string hiceName = "hice";
36+
std::string ciceName = "cice";
37+
std::string hsnowName = "hsnow";
38+
std::string ticeName = "tice";
39+
std::string sstName = "sst";
40+
std::string sssName = "sss";
41+
42+
typedef std::map<StringName, std::string> NameMap;
43+
44+
void initGroup(std::vector<ElementData>& data, netCDF::NcGroup& grp, const NameMap& nameMap);
45+
void dumpGroup(const std::vector<ElementData>& data, netCDF::NcGroup& grp, const NameMap& nameMap);
46+
47+
// See https://isocpp.org/wiki/faq/pointers-to-members#macro-for-ptr-to-memfn
48+
#define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember))
49+
50+
// pointer to a member of PrognosticData that takes no arguments and returns a
51+
// double. See https://isocpp.org/wiki/faq/pointers-to-members#typedef-for-ptr-to-memfn
52+
typedef double (PrognosticData::*ProgDoubleFn)() const;
53+
54+
// Map between variable names and retrieval functions
55+
// See https://isocpp.org/wiki/faq/pointers-to-members#array-memfnptrs
56+
// clang-format off
57+
static const std::map<std::string, ProgDoubleFn> variableFunctions
58+
= { { hiceName, &PrognosticData::iceThickness },
59+
{ ciceName, &PrognosticData::iceConcentration },
60+
{ hsnowName, &PrognosticData::snowThickness },
61+
{ sstName, &PrognosticData::seaSurfaceTemperature },
62+
{ sssName, &PrognosticData::seaSurfaceSalinity } };
63+
// clang-format on
64+
65+
void DevGridIO::init(std::vector<ElementData>& data, const std::string& filePath) const
66+
{
67+
NameMap nameMap = {
68+
{ StringName::METADATA_NODE, IStructure::metadataNodeName() },
69+
{ StringName::DATA_NODE, IStructure::dataNodeName() },
70+
{ StringName::STRUCTURE, DevGrid::structureName },
71+
{ StringName::X_DIM, DevGrid::xDimName },
72+
{ StringName::Y_DIM, DevGrid::yDimName },
73+
{ StringName::Z_DIM, DevGrid::nIceLayersName },
74+
};
75+
netCDF::NcFile ncFile(filePath, netCDF::NcFile::read);
76+
initGroup(data, ncFile, nameMap);
77+
ncFile.close();
78+
}
79+
80+
void DevGridIO::dump(const std::vector<ElementData>& data, const std::string& filePath) const
81+
{
82+
NameMap nameMap = {
83+
{ StringName::METADATA_NODE, IStructure::metadataNodeName() },
84+
{ StringName::DATA_NODE, IStructure::dataNodeName() },
85+
{ StringName::STRUCTURE, DevGrid::structureName },
86+
{ StringName::X_DIM, DevGrid::xDimName },
87+
{ StringName::Y_DIM, DevGrid::yDimName },
88+
{ StringName::Z_DIM, DevGrid::nIceLayersName },
89+
};
90+
netCDF::NcFile ncFile(filePath, netCDF::NcFile::replace);
91+
dumpGroup(data, ncFile, nameMap);
92+
ncFile.close();
93+
}
94+
95+
void initMeta(std::vector<ElementData>& data, const netCDF::NcGroup& metaGroup)
96+
{
97+
int nx = DevGrid::nx;
98+
data.resize(nx * nx);
99+
}
100+
101+
void initData(std::vector<ElementData>& data, const netCDF::NcGroup& dataGroup)
102+
{
103+
// Get the number of ice layers from the ice temperature data
104+
const int layersDim = 2;
105+
int nLayers = dataGroup.getVar(ticeName).getDim(layersDim).getSize();
106+
int nx = DevGrid::nx;
107+
for (int i = 0; i < nx; ++i) {
108+
for (int j = 0; j < nx; ++j) {
109+
int linearIndex = i * nx + j;
110+
double hice;
111+
double cice;
112+
double hsnow;
113+
double sst;
114+
double sss;
115+
std::vector<std::size_t> loc = { std::size_t(i), std::size_t(j) };
116+
dataGroup.getVar(hiceName).getVar(loc, &hice);
117+
dataGroup.getVar(ciceName).getVar(loc, &cice);
118+
dataGroup.getVar(hsnowName).getVar(loc, &hsnow);
119+
dataGroup.getVar(sstName).getVar(loc, &sst);
120+
dataGroup.getVar(sssName).getVar(loc, &sss);
121+
// Retrieve ice temperature data
122+
123+
std::vector<double> tice(nLayers);
124+
for (int l = 0; l < nLayers; ++l) {
125+
std::vector<std::size_t> loc3 = { loc[0], loc[1], std::size_t(l) };
126+
dataGroup.getVar(ticeName).getVar(loc3, &tice[l]);
127+
}
128+
data[linearIndex]
129+
= PrognosticGenerator().hice(hice).cice(cice).sst(sst).sss(sss).hsnow(hsnow).tice(
130+
tice);
131+
}
132+
}
133+
134+
for (auto fnNamePair : variableFunctions) {
135+
const std::string& name = fnNamePair.first;
136+
netCDF::NcVar var(dataGroup.getVar(name));
137+
}
138+
}
139+
140+
void initGroup(std::vector<ElementData>& data, netCDF::NcGroup& grp, const NameMap& nameMap)
141+
{
142+
netCDF::NcGroup metaGroup(grp.getGroup(nameMap.at(StringName::METADATA_NODE)));
143+
netCDF::NcGroup dataGroup(grp.getGroup(nameMap.at(StringName::DATA_NODE)));
144+
145+
initMeta(data, metaGroup);
146+
initData(data, dataGroup);
147+
}
148+
149+
void dumpMeta(
150+
const std::vector<ElementData>& data, netCDF::NcGroup& metaGroup, const NameMap& nameMap)
151+
{
152+
metaGroup.putAtt(IStructure::typeNodeName(), nameMap.at(StringName::STRUCTURE));
153+
}
154+
155+
/*
156+
* Uses a pointer-to-member-function to access the data in PrognosticData
157+
* element by element. Please see the references in the comments associated
158+
* with ProgDoubleFn and CALL_MEMBER_FN for more details.
159+
*/
160+
std::vector<double> gather(const std::vector<ElementData>& data, ProgDoubleFn pFunc)
161+
{
162+
std::vector<double> gathered(data.size());
163+
for (int i = 0; i < data.size(); ++i) {
164+
gathered[i] = CALL_MEMBER_FN(data[i], pFunc)();
165+
}
166+
return gathered;
167+
}
168+
169+
void dumpData(
170+
const std::vector<ElementData>& data, netCDF::NcGroup& dataGroup, const NameMap& nameMap)
171+
{
172+
int nx = DevGrid::nx;
173+
// Create the dimension data, since it has to be in the same group as the
174+
// data or the parent group
175+
netCDF::NcDim xDim = dataGroup.addDim(nameMap.at(StringName::X_DIM), nx);
176+
netCDF::NcDim yDim = dataGroup.addDim(nameMap.at(StringName::Y_DIM), nx);
177+
178+
std::vector<netCDF::NcDim> dims2 = { xDim, yDim };
179+
for (auto fnNamePair : variableFunctions) {
180+
const std::string& name = fnNamePair.first;
181+
netCDF::NcVar var(dataGroup.addVar(name, netCDF::ncDouble, dims2));
182+
std::vector<double> gathered = gather(data, variableFunctions.at(name));
183+
var.putVar(gathered.data());
184+
}
185+
186+
int nLayers = data[0].nIceLayers();
187+
netCDF::NcDim zDim = dataGroup.addDim(nameMap.at(StringName::Z_DIM), nLayers);
188+
std::vector<netCDF::NcDim> dims3 = { xDim, yDim, zDim };
189+
netCDF::NcVar iceT(dataGroup.addVar(ticeName, netCDF::ncDouble, dims3));
190+
191+
// Gather the three dimensional data explicitly (until there is more than
192+
// one three dimensional dataset).
193+
std::vector<double> tice(data.size() * nLayers);
194+
for (int i = 0; i < data.size(); ++i) {
195+
int ii = nLayers * i;
196+
for (int l = 0; l < nLayers; ++l) {
197+
tice[ii + l] = data[i].iceTemperature(l);
198+
}
199+
}
200+
iceT.putVar(tice.data());
201+
}
202+
203+
void dumpGroup(
204+
const std::vector<ElementData>& data, netCDF::NcGroup& headGroup, const NameMap& nameMap)
205+
{
206+
netCDF::NcGroup metaGroup = headGroup.addGroup(nameMap.at(StringName::METADATA_NODE));
207+
netCDF::NcGroup dataGroup = headGroup.addGroup(nameMap.at(StringName::DATA_NODE));
208+
dumpMeta(data, metaGroup, nameMap);
209+
dumpData(data, dataGroup, nameMap);
210+
}
211+
212+
} /* namespace Nextsim */

core/src/DevStep.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*!
2+
* @file DevStep.cpp
3+
*
4+
* @date Jan 12, 2022
5+
* @author Tim Spain <timothy.spain@nersc.no>
6+
*/
7+
8+
#include "include/DevStep.hpp"
9+
#include "include/IPrognosticUpdater.hpp"
10+
#include "include/PrognosticData.hpp"
11+
12+
namespace Nextsim {
13+
14+
void DevStep::iterate(const Iterator::Duration& dt)
15+
{
16+
PrognosticData::setTimestep(dt);
17+
for (pStructure->cursor = 0; pStructure->cursor; ++pStructure->cursor) {
18+
auto& data = *pStructure->cursor;
19+
data.updateDerivedData(data, data, data);
20+
data.calculate(data, data, data);
21+
data.updateAndIntegrate(data);
22+
}
23+
}
24+
25+
} /* namespace Nextsim */

0 commit comments

Comments
 (0)