Skip to content

Commit 4156717

Browse files
authored
Merge Pull Request #2348 from E3SM-Project/scream/aarondonahue/force_sfc_export_from_file_v2
Automatically Merged using E3SM Pull Request AutoTester PR Title: Add capability to set surface export values via data from file(s) PR Author: AaronDonahue
2 parents 5dc44fe + 57dfd8d commit 4156717

File tree

8 files changed

+228
-36
lines changed

8 files changed

+228
-36
lines changed

components/eamxx/cime_config/namelist_defaults_scream.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ be lost if SCREAM_HACK_XML is not enabled.
170170
<fields type="array(string)">NONE</fields>
171171
<values type="array(real)">0</values>
172172
</prescribed_constants>
173+
<prescribed_from_file>
174+
<fields type="array(string)">NONE</fields>
175+
<files type="array(string)">NONE</files>
176+
</prescribed_from_file>
173177
</sc_export>
174178

175179
<!-- Homme dynamics -->

components/eamxx/src/control/atmosphere_driver.hpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ class AtmosphereDriver
136136
// NOTE: if already finalized, this is a no-op
137137
void finalize ();
138138

139-
field_mgr_ptr get_ref_grid_field_mgr () const;
140139
field_mgr_ptr get_field_mgr (const std::string& grid_name) const;
141140

142141
// Get atmosphere time stamp

components/eamxx/src/control/atmosphere_surface_coupling_exporter.cpp

Lines changed: 82 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ void SurfaceCouplingExporter::initialize_impl (const RunType /* run_type */)
171171
for (int i=0; i<m_num_scream_exports; ++i) {
172172

173173
std::string fname = m_export_field_names[i];
174+
m_export_field_names_vector.push_back(fname);
174175
EKAT_REQUIRE_MSG(has_helper_field(fname),"Error! Attempting to export "+fname+
175176
" which has not been added as a helper field.\n");
176177
auto& field = m_helper_fields.at(fname);
@@ -209,33 +210,78 @@ void SurfaceCouplingExporter::initialize_impl (const RunType /* run_type */)
209210
m_export_source_h = Kokkos::create_mirror_view(m_export_source);
210211
Kokkos::deep_copy(m_export_source_h,FROM_MODEL); // The default is that all export variables will be derived from the EAMxx state.
211212
m_num_from_model_exports = m_num_scream_exports;
212-
213+
214+
// Parse all fields that will be set by interpolating data from file(s):
215+
if (m_params.isSublist("prescribed_from_file")) {
216+
// Retrieve the parameters for prescribed from file
217+
auto export_from_file_params = m_params.sublist("prescribed_from_file");
218+
EKAT_REQUIRE_MSG(export_from_file_params.isParameter("fields"),"Error! surface_coupling_exporter::init - prescribed_from_file does not have 'fields' parameter.");
219+
auto export_from_file_fields = export_from_file_params.get<vos_type>("fields");
220+
221+
EKAT_REQUIRE_MSG(export_from_file_params.isParameter("files"),"Error! surface_coupling_exporter::init - prescribed_from_file does not have 'files' parameter.");
222+
auto export_from_file_names = export_from_file_params.get<vos_type>("files");
223+
224+
bool are_fields_present = (std::find(export_from_file_fields.begin(),export_from_file_fields.end(),"NONE") == export_from_file_fields.end()) and (export_from_file_fields.size() > 0);
225+
bool are_files_present = (std::find(export_from_file_names.begin(),export_from_file_names.end(),"NONE") == export_from_file_names.end()) and (export_from_file_names.size() > 0);
226+
if (are_fields_present) {
227+
EKAT_REQUIRE_MSG(are_files_present,"ERROR!! surface_coupling_exporter::init - prescribed_from_file has fields but no files.");
228+
}
229+
if (are_files_present) {
230+
EKAT_REQUIRE_MSG(are_fields_present,"ERROR!! surface_coupling_exporter::init - prescribed_from_file has files but no fields.");
231+
}
232+
bool do_export_from_file = are_fields_present and are_files_present;
233+
if (do_export_from_file) {
234+
// Construct a time interpolation object
235+
auto time_interp = util::TimeInterpolation(m_grid,export_from_file_names);
236+
for (auto fname : export_from_file_fields) {
237+
// Find the index for this field in the list of export fields.
238+
auto v_loc = std::find(m_export_field_names_vector.begin(),m_export_field_names_vector.end(),fname);
239+
EKAT_REQUIRE_MSG(v_loc != m_export_field_names_vector.end(), "ERROR!! surface_coupling_exporter::init - prescribed_from_file has field with name " << fname << " which can't be found in set of exported fields\n.");
240+
auto idx = v_loc - m_export_field_names_vector.begin();
241+
EKAT_REQUIRE_MSG(m_export_source_h(idx)==FROM_MODEL,"Error! surface_coupling_exporter::init - attempting to set field " << fname << " export type, which has already been set. Please check namelist options");
242+
m_export_source_h(idx) = FROM_FILE;
243+
++m_num_from_file_exports;
244+
--m_num_from_model_exports;
245+
auto& f_helper = m_helper_fields.at(fname);
246+
// We want to add the field as a deep copy so that the helper_fields are automatically updated.
247+
time_interp.add_field(f_helper, true);
248+
m_export_from_file_field_names.push_back(fname);
249+
}
250+
m_time_interp = time_interp;
251+
m_time_interp.initialize_data_from_files();
252+
}
253+
}
254+
255+
// Parse all fields that will be set to a constant value:
213256
if (m_params.isSublist("prescribed_constants")) {
214257
auto export_constant_params = m_params.sublist("prescribed_constants");
215258
EKAT_REQUIRE_MSG(export_constant_params.isParameter("fields"),"Error! surface_coupling_exporter::init - prescribed_constants does not have 'fields' parameter.");
216259
EKAT_REQUIRE_MSG(export_constant_params.isParameter("values"),"Error! surface_coupling_exporter::init - prescribed_constants does not have 'values' parameter.");
217260
auto export_constant_fields = export_constant_params.get<vos_type>("fields");
218261
auto export_constant_values = export_constant_params.get<vor_type>("values");
219262
EKAT_REQUIRE_MSG(export_constant_fields.size()==export_constant_values.size(),"Error! surface_coupling_exporter::init - prescribed_constants 'fields' and 'values' are not the same size");
220-
if (export_constant_fields.size()>0) {
263+
bool are_fields_present = (std::find(export_constant_fields.begin(),export_constant_fields.end(),"NONE") == export_constant_fields.end()) and (export_constant_fields.size() > 0);
264+
if (are_fields_present) {
221265
// Determine which fields need constants
222-
for (int i=0; i<m_num_scream_exports; ++i) { // TODO: This loop would probably be simpler if we just checked which "i" corresponded to each name in the fields list.
223-
std::string fname = m_export_field_names[i];
224-
auto loc = std::find(export_constant_fields.begin(),export_constant_fields.end(),fname);
225-
if (loc != export_constant_fields.end()) {
226-
const auto pos = loc-export_constant_fields.begin();
227-
m_export_source_h(i) = CONSTANT;
228-
++m_num_const_exports;
229-
--m_num_from_model_exports;
230-
m_export_constants.emplace(fname,export_constant_values[pos]);
231-
}
266+
for (int ii=0; ii<export_constant_fields.size(); ii++) {
267+
auto fname = export_constant_fields[ii];
268+
// Find the index for this field in the list of export fields.
269+
auto v_loc = std::find(m_export_field_names_vector.begin(),m_export_field_names_vector.end(),fname);
270+
EKAT_REQUIRE_MSG(v_loc != m_export_field_names_vector.end(), "ERROR!! surface_coupling_exporter::init - prescribed_constants has field with name " << fname << " which can't be found in set of exported fields\n.");
271+
auto idx = v_loc - m_export_field_names_vector.begin();
272+
// This field should not have been set to anything else yet (recall FROM_MODEL is the default)
273+
EKAT_REQUIRE_MSG(m_export_source_h(idx)==FROM_MODEL,"Error! surface_coupling_exporter::init - attempting to set field " + fname + " export type, which has already been set. Please check namelist options");
274+
m_export_source_h(idx) = CONSTANT;
275+
++m_num_const_exports;
276+
--m_num_from_model_exports;
277+
m_export_constants.emplace(fname,export_constant_values[ii]);
232278
}
233279
}
234280
}
235281
// Copy host view back to device view
236282
Kokkos::deep_copy(m_export_source,m_export_source_h);
237283
// Final sanity check
238-
EKAT_REQUIRE_MSG(m_num_scream_exports = m_num_const_exports+m_num_from_model_exports,"Error! surface_coupling_exporter - Something went wrong set the type of export for all variables.");
284+
EKAT_REQUIRE_MSG(m_num_scream_exports = m_num_from_file_exports+m_num_const_exports+m_num_from_model_exports,"Error! surface_coupling_exporter - Something went wrong set the type of export for all variables.");
239285
EKAT_REQUIRE_MSG(m_num_from_model_exports>=0,"Error! surface_coupling_exporter - The number of exports derived from EAMxx < 0, something must have gone wrong in assigning the types of exports for all variables.");
240286

241287
// Perform initial export (if any are marked for export during initialization)
@@ -250,8 +296,13 @@ void SurfaceCouplingExporter::run_impl (const double dt)
250296
void SurfaceCouplingExporter::do_export(const double dt, const bool called_during_initialization)
251297
{
252298
if (m_num_const_exports>0) {
253-
set_constant_exports(dt,called_during_initialization);
299+
set_constant_exports();
254300
}
301+
302+
if (m_num_from_file_exports>0) {
303+
set_from_file_exports(dt);
304+
}
305+
255306
if (m_num_from_model_exports>0) {
256307
compute_eamxx_exports(dt,called_during_initialization);
257308
}
@@ -260,17 +311,32 @@ void SurfaceCouplingExporter::do_export(const double dt, const bool called_durin
260311
do_export_to_cpl(called_during_initialization);
261312
}
262313
// =========================================================================================
263-
void SurfaceCouplingExporter::set_constant_exports(const double dt, const bool called_during_initialization)
314+
void SurfaceCouplingExporter::set_constant_exports()
264315
{
265316
// Cycle through those fields that will be set to a constant value:
317+
int num_set = 0; // Checker to make sure we got all the fields we wanted.
266318
for (int i=0; i<m_num_scream_exports; ++i) {
267319
if (m_export_source_h(i)==CONSTANT) {
268320
std::string fname = m_export_field_names[i];
269321
const auto field_view = m_helper_fields.at(fname).get_view<Real*>();
270322
Kokkos::deep_copy(field_view,m_export_constants.at(fname));
323+
num_set++;
271324
}
272325
}
326+
// Gotta catch em all
327+
EKAT_REQUIRE_MSG(num_set==m_num_const_exports,"ERROR! SurfaceCouplingExporter::set_constant_exports() - Number of fields set to a constant (" + std::to_string(num_set) +") doesn't match the number recorded at initialization (" + std::to_string(m_num_const_exports) +"). Something went wrong.");
273328

329+
}
330+
// =========================================================================================
331+
void SurfaceCouplingExporter::set_from_file_exports(const int dt)
332+
{
333+
// Perform interpolation on the data with the latest timestamp
334+
auto ts = timestamp();
335+
if (dt > 0) {
336+
ts += dt;
337+
}
338+
m_time_interp.perform_time_interpolation(ts);
339+
274340
}
275341
// =========================================================================================
276342
// This compute_eamxx_exports routine handles all export variables that are derived from the EAMxx state.
@@ -479,7 +545,7 @@ void SurfaceCouplingExporter::do_export_to_cpl(const bool called_during_initiali
479545
// =========================================================================================
480546
void SurfaceCouplingExporter::finalize_impl()
481547
{
482-
548+
// Nothing to do
483549
}
484550
// =========================================================================================
485551
} // namespace scream

components/eamxx/src/control/atmosphere_surface_coupling_exporter.hpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "share/atm_process/atmosphere_process.hpp"
55
#include "ekat/ekat_parameter_list.hpp"
66
#include "share/util/scream_common_physics_functions.hpp"
7+
#include "share/util/eamxx_time_interpolation.hpp"
78
#include "share/atm_process/ATMBufferManager.hpp"
89
#include "share/atm_process/SCDataManager.hpp"
910

@@ -79,7 +80,8 @@ class SurfaceCouplingExporter : public AtmosphereProcess
7980
// which do not have valid entries.
8081
void do_export(const double dt, const bool called_during_initialization=false); // Main export routine
8182
void compute_eamxx_exports(const double dt, const bool called_during_initialization=false); // Export vars are derived from eamxx state
82-
void set_constant_exports(const double dt, const bool called_during_initialization=false); // Export vars are set to a constant
83+
void set_constant_exports(); // Export vars are set to a constant
84+
void set_from_file_exports(const int dt); // Export vars are set by interpolation of data from files
8385
void do_export_to_cpl(const bool called_during_initialization=false); // Finish export by copying data to cpl structures.
8486

8587
// Take and store data from SCDataManager
@@ -123,12 +125,16 @@ class SurfaceCouplingExporter : public AtmosphereProcess
123125
Int m_num_cpl_exports;
124126

125127
// Number of exports from EAMxx and how they will be handled
126-
Int m_num_scream_exports;
128+
int m_num_scream_exports;
127129
view_1d<DefaultDevice,ExportType> m_export_source;
128130
view_1d<HostDevice,ExportType> m_export_source_h;
129131
std::map<std::string,Real> m_export_constants;
130132
int m_num_from_model_exports=0;
131133
int m_num_const_exports=0;
134+
// For exporting from file
135+
int m_num_from_file_exports=0;
136+
util::TimeInterpolation m_time_interp;
137+
std::vector<std::string> m_export_from_file_field_names;
132138

133139
// Views storing a 2d array with dims (num_cols,num_fields) for cpl export data.
134140
// The field idx strides faster, since that's what mct does (so we can "view" the
@@ -137,7 +143,8 @@ class SurfaceCouplingExporter : public AtmosphereProcess
137143
uview_2d<HostDevice, Real> m_cpl_exports_view_h;
138144

139145
// Array storing the field names for exports
140-
name_t* m_export_field_names;
146+
name_t* m_export_field_names;
147+
std::vector<std::string> m_export_field_names_vector;
141148

142149
// Views storing information for each export
143150
uview_1d<HostDevice, int> m_cpl_indices_view;

components/eamxx/src/share/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ set(SHARE_SRC
3434
util/scream_utils.cpp
3535
util/eamxx_time_interpolation.cpp
3636
util/scream_bfbhash.cpp
37+
util/eamxx_time_interpolation.cpp
3738
)
3839

3940
add_library(scream_share ${SHARE_SRC})

components/eamxx/src/share/util/eamxx_time_interpolation.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,6 @@ TimeInterpolation::TimeInterpolation(
2727
m_is_data_from_file = true;
2828
}
2929
/*-----------------------------------------------------------------------------------------------*/
30-
// Destructor
31-
TimeInterpolation::
32-
~TimeInterpolation ()
33-
{
34-
finalize();
35-
}
36-
/*-----------------------------------------------------------------------------------------------*/
3730
void TimeInterpolation::finalize()
3831
{
3932
if (m_is_data_from_file) {
@@ -275,6 +268,10 @@ void TimeInterpolation::set_file_data_triplets(const vos_type& list_of_files) {
275268
ts_snap += (time_snap*time_mult);
276269
}
277270
auto time = ts_snap.seconds_from(ts_ref);
271+
// Sanity check that we don't have multiples of the same timesnap
272+
EKAT_REQUIRE_MSG(map_of_times_to_vector_idx.count(time)==0,"Error! TimeInterpolation::set_file_data_triplets - The same time step has been encountered more than once in the data files, please check\n"
273+
<< " TimeStamp: " << ts_snap.to_string() << "\n"
274+
<< " Filename: " << filename << "\n");
278275
map_of_times_to_vector_idx.emplace(time,running_idx);
279276
filenames_tmp.push_back(filename);
280277
timestamps_tmp.push_back(ts_snap);

components/eamxx/src/share/util/eamxx_time_interpolation.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class TimeInterpolation {
2323
TimeInterpolation() = default;
2424
TimeInterpolation(const grid_ptr_type& grid);
2525
TimeInterpolation(const grid_ptr_type& grid, const vos_type& list_of_files);
26-
~TimeInterpolation ();
26+
~TimeInterpolation () = default;
2727

2828
// Running the interpolation
2929
void initialize_timestamps(const TimeStamp& ts_in);

0 commit comments

Comments
 (0)