Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Interface allowing ELM to drive ATS #157

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
20dae3c
added basic ELM-ATS interface
jbeisman Sep 14, 2022
eada89b
replace Coordinator's constructor with default constructor and move i…
jbeisman Sep 15, 2022
312aa7b
ELM->ATS driver
jbeisman Sep 15, 2022
bba9dee
added CMakeLists.txt and updated a few things; interface is compiling…
jbeisman Sep 16, 2022
2704dd9
add C++ and Fortran tests - both currently passing column tests
jbeisman Sep 16, 2022
704c25c
organized api directory structure and build system
jbeisman Sep 17, 2022
5e59a11
update to be inline with recent Amanzi and ATS changes
jbeisman Sep 20, 2022
a68f7b7
Merge branch 'master' into jb/elm_api
jbeisman Sep 20, 2022
b68126c
a few changes to the ELM API. Work in progress with ELM
ecoon Sep 27, 2022
fdffc7b
removes indexer for now -- will revisit
ecoon Sep 28, 2022
c94ba70
Merge branch 'jb/elm_api' of https://github.com/amanzi/ats into jb/el…
ecoon Nov 2, 2022
b5b3325
merge from master
ecoon Nov 16, 2022
9ffa11e
updates ELM API, updates implementation of the API
ecoon Nov 18, 2022
f186146
updates to ELM api
ecoon Nov 22, 2022
fe63ea8
debugging ELM-ATS api
ecoon Nov 22, 2022
f2a69e5
Merge branch 'master' of github.com:amanzi/ats into jb/elm_api
jbeisman Mar 14, 2023
a48e52e
Fix from merge - replace registration includes with ats_registrations…
jbeisman Mar 15, 2023
bb24059
Fixed naming confusion and changed some function signatures in API
jbeisman Mar 16, 2023
5f87eff
Got cc driver test working
jbeisman Mar 16, 2023
f105cbc
Got Fortran driver test working
jbeisman Mar 16, 2023
7f5683f
ELM->ATS coupling progress
jbeisman Apr 25, 2023
90c62dc
updates to ELM->ATS driver
jbeisman May 16, 2023
e575f10
Working changes to ELM-ATS driver - fluxes and state variables are pa…
jbeisman Jun 27, 2023
f6252d3
Merge remote-tracking branch 'origin/master' into jb/elm_api
jbeisman Jun 27, 2023
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
9 changes: 8 additions & 1 deletion src/executables/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ include_directories(${ATS_SOURCE_DIR}/src/pks)
include_directories(${ATS_SOURCE_DIR}/src/pks/mpc)
include_directories(${ATS_SOURCE_DIR}/src/pks/energy)
include_directories(${ATS_SOURCE_DIR}/src/pks/flow)
include_directories(${ATS_SOURCE_DIR}/src/pks/deformation)
include_directories(${ATS_SOURCE_DIR}/src/pks/deform)
include_directories(${ATS_SOURCE_DIR}/src/pks/transport)
include_directories(${ATS_SOURCE_DIR}/src/operators/upwinding)
include_directories(${ATS_SOURCE_DIR}/src/operators/advection)
Expand Down Expand Up @@ -177,3 +177,10 @@ add_amanzi_executable(ats
OUTPUT_NAME ats
OUTPUT_DIRECTORY ${ATS_BINARY_DIR})


# set this here for now
# add option to bootstrap before completion
set (BUILD_ELM_ATS_API true)
if (BUILD_ELM_ATS_API)
add_subdirectory(elm_ats_api)
endif()
4 changes: 1 addition & 3 deletions src/executables/ats_driver.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ namespace ATS {

ATSDriver::ATSDriver(Teuchos::ParameterList& parameter_list,
Amanzi::Comm_ptr_type comm)
: Coordinator(parameter_list, comm) {}


: Coordinator() { Coordinator::coordinator_init(parameter_list, comm); }

// -----------------------------------------------------------------------------
// setup and initialize, then run until time >= duration_
Expand Down
26 changes: 12 additions & 14 deletions src/executables/coordinator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,18 @@ actual work.

#include "coordinator.hh"

#define DEBUG_MODE 0

namespace ATS {

Coordinator::Coordinator(Teuchos::ParameterList& parameter_list,
Amanzi::Comm_ptr_type comm ) :
parameter_list_(Teuchos::rcp(new Teuchos::ParameterList(parameter_list))),
comm_(comm),
restart_(false)
// this MUST be be called before using Coordinator
void
Coordinator::coordinator_init(Teuchos::ParameterList& parameter_list,
Amanzi::Comm_ptr_type comm)
{
// initialize plist and comm member variables from input args
parameter_list_ = Teuchos::rcp(new Teuchos::ParameterList(parameter_list));
ecoon marked this conversation as resolved.
Show resolved Hide resolved
comm_ = comm;
restart_ = false;

// create and start the global timer
timer_ = Teuchos::rcp(new Teuchos::Time("wallclock_monitor",true));
setup_timer_ = Teuchos::TimeMonitor::getNewCounter("setup");
Expand All @@ -65,13 +67,6 @@ Coordinator::Coordinator(Teuchos::ParameterList& parameter_list,
// create state.
S_ = Teuchos::rcp(new Amanzi::State(parameter_list_->sublist("state")));

coordinator_init();

vo_ = Teuchos::rcp(new Amanzi::VerboseObject(comm, "Coordinator", *coordinator_list_));
};

void Coordinator::coordinator_init()
{
// create the geometric model and regions
Teuchos::ParameterList reg_list = parameter_list_->sublist("regions");
Teuchos::RCP<Amanzi::AmanziGeometry::GeometricModel> gm =
Expand Down Expand Up @@ -136,6 +131,9 @@ void Coordinator::coordinator_init()
}
}

// create verbose object
vo_ = Teuchos::rcp(new Amanzi::VerboseObject(comm_, "Coordinator", *coordinator_list_));

// create the time step manager
tsm_ = Teuchos::rcp(new Amanzi::TimeStepManager());
}
Expand Down
9 changes: 5 additions & 4 deletions src/executables/coordinator.hh
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ namespace ATS {
class Coordinator {

public:
Coordinator(Teuchos::ParameterList& parameter_list,
Amanzi::Comm_ptr_type comm);

Coordinator() {};

// PK methods
virtual void setup();
void setup();
virtual void initialize();
virtual void finalize();
void report_memory();
Expand All @@ -53,7 +53,8 @@ public:
double get_dt(bool after_fail=false);

protected:
void coordinator_init();
void coordinator_init(Teuchos::ParameterList& parameter_list,
Amanzi::Comm_ptr_type comm);
void read_parameter_list();

// PK container and factory
Expand Down
46 changes: 46 additions & 0 deletions src/executables/elm_ats_api/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- mode: cmake -*-
#
# ELM_ATS_API
# library
#
# builds both dynamic and static libs for now
# need to add build logic to make configurable

# verify the compatibility of the C/Fortran and C++/Fortran compilers
# Amanzi probably does this somewhere upstream, should check
include(FortranCInterface)
FortranCInterface_VERIFY(CXX)

include_directories(${ATS_SOURCE_DIR}/src/executables)

set(elm_ats_src_files
${ATS_SOURCE_DIR}/src/executables/coordinator.cc
${ATS_SOURCE_DIR}/src/executables/ats_mesh_factory.cc
ecoon marked this conversation as resolved.
Show resolved Hide resolved
elm_ats_driver.cc
elm_ats_api.cc
)

set(elm_ats_inc_files
${ATS_SOURCE_DIR}/src/executables/coordinator.hh
${ATS_SOURCE_DIR}/src/executables/ats_mesh_factory.hh
elm_ats_driver.hh
elm_ats_api.h
)

## build shared lib
add_amanzi_library(elm_ats
SOURCE ${elm_ats_src_files}
HEADERS ${elm_ats_inc_files}
LINK_LIBS ${fates_link_libs} ${tpl_link_libs} ${ats_link_libs} ${amanzi_link_libs})
if (APPLE AND BUILD_SHARED_LIBS)
set_target_properties(elm_ats PROPERTIES LINK_FLAGS "-Wl,-undefined,dynamic_lookup")
endif()

## build static lib
add_amanzi_library(elm_ats_static
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does it have to be static?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I mean, I assume so, or you wouldn't have added this, just yuck.

STATIC
SOURCE ${elm_ats_src_files}
HEADERS ${elm_ats_inc_files}
LINK_LIBS ${fates_link_libs} ${tpl_link_libs} ${ats_link_libs} ${amanzi_link_libs})

add_subdirectory(test)
55 changes: 55 additions & 0 deletions src/executables/elm_ats_api/elm_ats_api.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@

#include "elm_ats_driver.hh"
#include "elm_ats_api.h"

#ifdef __cplusplus
extern "C"{
#endif

// allocate, call constructor and cast ptr to opaque ELM_ATS_DRIVER
ELM_ATS_DRIVER ats_create() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

is this void*?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, namespaces are such a good idea. Too bad C didn't think of them.

Copy link
Contributor Author

@jbeisman jbeisman Sep 22, 2022

Choose a reason for hiding this comment

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

is this void*?

Kind of. I used an opaque pointer method that's pretty common when creating portable C++ libraries. It's defined in the accompanying header file:

#ifdef __cplusplus
extern "C" {
// opaque pointer
// external caller only sees *ELM_ATS_DRIVER - similar to void*, but better type safety
// ATS resolves ELM_ATS_DRIVER as real ELM_ATSDriver during linking
class ELM_ATSDriver;
typedef ELM_ATSDriver *ELM_ATS_DRIVER;
#else
// calling code should not dereference the pointer to the ATS object
// pointer hidden behind typedef to discourage
typedef struct ELM_ATS_DRIVER *ELM_ATS_DRIVER;
#endif

To the C compiler and whatever linker the external program invokes, this is a typedef to a pointer to a forward declared dummy struct. It's like a void* with a bit of type safety. To the C++ compiler/linker, it's resolved as a ELM_ATSDriver*.

I made the decision to hide the pointer behind the typedef because calling code should never dereference the ATS object. I think some people hate this, but it seems like the right call here.

return reinterpret_cast<ELM_ATS_DRIVER>(new ATS::ELM_ATSDriver());
}
// reinterpret as elm_ats_driver and delete (calls destructor)
void ats_delete(ELM_ATS_DRIVER ats) {
auto ats_ptr = reinterpret_cast<ATS::ELM_ATSDriver*>(ats);
ats_ptr->finalize();
delete ats_ptr;
}
// call driver setup()
void ats_setup(ELM_ATS_DRIVER ats, MPI_Fint *f_comm, const char *input_filename) {
return reinterpret_cast<ATS::ELM_ATSDriver*>(ats)->setup(f_comm, input_filename);
}
// call driver initialize()
void ats_initialize(ELM_ATS_DRIVER ats){
return reinterpret_cast<ATS::ELM_ATSDriver*>(ats)->initialize();
}
// call driver advance()
void ats_advance(ELM_ATS_DRIVER ats, double *dt) {
return reinterpret_cast<ATS::ELM_ATSDriver*>(ats)->advance(dt);
}
// call driver advance_test()
void ats_advance_test(ELM_ATS_DRIVER ats) {
return reinterpret_cast<ATS::ELM_ATSDriver*>(ats)->advance_test();
}
// call driver set_sources()
void ats_set_sources(ELM_ATS_DRIVER ats, double *soil_infiltration, double *soil_evaporation,
double *root_transpiration, int *ncols, int *ncells) {
return reinterpret_cast<ATS::ELM_ATSDriver*>(ats)
->set_sources(soil_infiltration, soil_evaporation, root_transpiration, ncols, ncells);
}
// call driver get_waterstate()
void ats_get_waterstate(ELM_ATS_DRIVER ats, double *surface_pressure, double *soil_pressure,
double *saturation, int *ncols, int *ncells) {
return reinterpret_cast<ATS::ELM_ATSDriver*>(ats)
->get_waterstate(surface_pressure, soil_pressure, saturation, ncols, ncells);
}
// call driver get_mesh_info()
void ats_get_mesh_info(ELM_ATS_DRIVER ats, int *ncols_local, int *ncols_global, int *ncells_per_col,
double *dz, double *depth, double *elev, double *surf_area_m2, double *lat, double *lon) {
return reinterpret_cast<ATS::ELM_ATSDriver*>(ats)
->get_mesh_info(ncols_local, ncols_global,ncells_per_col, dz, depth, elev, surf_area_m2, lat, lon);
}
#ifdef __cplusplus
}
#endif
51 changes: 51 additions & 0 deletions src/executables/elm_ats_api/elm_ats_api.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

#ifndef ELM_ATS_API_HH_
#define ELM_ATS_API_HH_

#ifdef __cplusplus
extern "C" {
// opaque pointer
// external caller only sees *ELM_ATS_DRIVER - similar to void*, but better type safety
// ATS resolves ELM_ATS_DRIVER as real ELM_ATSDriver during linking
class ELM_ATSDriver;
typedef ELM_ATSDriver *ELM_ATS_DRIVER;
#else
// calling code should not dereference the pointer to the ATS object
// pointer hidden behind typedef to discourage
typedef struct ELM_ATS_DRIVER *ELM_ATS_DRIVER;
#endif

// allocate, call constructor and cast ptr to opaque ELM_ATS_DRIVER
ELM_ATS_DRIVER ats_create();
// reinterpret as elm_ats_driver and delete (calls destructor)
void ats_delete(ELM_ATS_DRIVER ats);
// call driver setup()
void ats_setup(ELM_ATS_DRIVER ats, MPI_Fint *f_comm, const char *input_filename);
// call driver initialize()
void ats_initialize(ELM_ATS_DRIVER ats);
// call driver advance(dt)
void ats_advance(ELM_ATS_DRIVER ats, double *dt);
// call driver advance_test()
void ats_advance_test(ELM_ATS_DRIVER ats);
// call driver set_sources()
// soil_infiltration & soil_evaporation are 1D arrays of length ncols
// root_transpiration is a 1D array array of length (ncells)
void ats_set_sources(ELM_ATS_DRIVER ats, double *soil_infiltration, double *soil_evaporation,
double *root_transpiration, int *ncols, int *ncells);
// call driver get_waterstate()
// surface_pressure is a 1D array of length ncols
// soil_pressure & saturation are 1D arrays array of length (ncells)
void ats_get_waterstate(ELM_ATS_DRIVER ats, double *surface_pressure, double *soil_pressure,
double *saturation, int *ncols, int *ncells);
// call driver get_mesh_info()
// ncols_local, ncols_global, and ncells_per_col are scalars
// dz & depth are 1D arrays array of length (ncells) - these could likely only be ncells_per_col long
// elev, surf_area_m2, lat, lon are 1D arrays of length ncols - lat lon necessary for every cell?
void ats_get_mesh_info(ELM_ATS_DRIVER ats, int *ncols_local, int *ncols_global, int *ncells_per_col,
double *dz, double *depth, double *elev, double *surf_area_m2, double *lat, double *lon);
#ifdef __cplusplus
}
#endif

// include guard
#endif
Loading