C API

ASYNCH comes with a collection of routines to access specific details of the underlying solver structure. This allows a user to construct his or her own programs, while making calls to the solver in particular ways. This is useful for modifying how the solvers behave, and for producing more specialized outputs. A user can also specify his or her own models in a separate module. Currently, interface routines exist for the C/C++ and Python programming languages.

Typical Interface Usage

In this section, we provide an overview of how to use the API routines for running simulations. Regardless of the language, the general order of calling API routines is the same. Further routines may be added to increase flexibility.

A basic program that uses the ASYNCH solvers to perform calculations and takes advantage of all the features of a global file is the following (written in C):

//Make sure we finalize MPI
void asynch_onexit(void)
{
    int flag;
    MPI_Finalized(&flag);
    if (!flag)
        MPI_Finalize();
}

int main(int argc,char* argv[])
{
  int res;
  char *global_filename = argv[1];

  //Initialize MPI stuff
  res = MPI_Init(&argc, &argv);
  if (res == MPI_SUCCESS)
      atexit(asynch_onexit);
  else
  {
      print_err("Failed to initialize MPI");
      exit(EXIT_FAILURE);
  }

  //Init asynch object and the river network
  AsynchSolver asynch;
  Asynch_Init(&asynch, MPI_COMM_WORLD);
  Asynch_Parse_GBL(&asynch, global_filename);
  Asynch_Load_Network(&asynch);
  Asynch_Partition_Network(&asynch);
  Asynch_Load_Network_Parameters(&asynch, 0);
  Asynch_Load_Dams(&asynch);
  Asynch_Load_Numerical_Error_Data(&asynch);
  Asynch_Initialize_Model(&asynch);
  Asynch_Load_Initial_Conditions(&asynch);
  Asynch_Load_Forcings(&asynch);
  Asynch_Load_Save_Lists(&asynch);
  Asynch_Finalize_Network(&asynch);
  Asynch_Calculate_Step_Sizes(&asynch);

  //Prepare output files
  Asynch_Prepare_Temp_Files(&asynch);
  Asynch_Write_Current_Step(&asynch);
  Asynch_Prepare_Peakflow_Output(&asynch);
  Asynch_Prepare_Output(&asynch);

  //Perform the calculations
  Asynch_Advance(&asynch, 1);

  //Create output files
  Asynch_Take_System_Snapshot(&asynch, NULL);
  Asynch_Create_Output(&asynch, NULL);
  Asynch_Create_Peakflows_Output(&asynch);

  //Clean up
  Asynch_Delete_Temporary_Files(&asynch);
  Asynch_Free(&asynch);

  return EXIT_SUCCESS;
}

Details of each function call can be found in Section [sec: user interface routines].

The program begins by initializing the asynchsolver object. The MPI communicator consisting of all processes (MPI_COMM_WORLD) is used for the calculations. Next, the global file specified as a command line argument to the program is parsed. Based upon the information specified by the global file, the different components of the network are constructed.

Next, the outputs for the program are initialized. The files for holding calculation results while the program runs is initialized (i.e. the temporary files). The initial values of the states are written to disk. Any initializations needed for the output peakflow and output time series sources are done.

With a call to Asynch_Advance, the calculations are performed. Any time series results are temporarily stored in the temporary files.

Once the calculations are complete, any necessary outputs are created (snapshot, output time series, output peakflow data). This could include writing to files or database tables, depending upon the options selected in the global file.

Lastly, clean up routines are called. The temporary files are deleted. The asynchsolver object is also deleted from memory with a call to . Note that this routine does not need to be called if using the interface functions from a language that supports automatic garbage collection.

Of course, outputting more information might be useful (timing results, command line parameter checking, results printed to screen, etc), and additional features may be needed (outputting data to multiple sources, creating peakflow data over intervals of time, etc). However, this is the basic structure needed to perform simulations. The source files asynchdist.c and asynchdist.py are essentially duplicates of the above program, but with information printed to screen.

User Interface Routines

In this section, routines for operating the solver are described. These routines can be used to create an instance of an ASYNCH solver, and manipulate properties such as total simulation time, when data output occurs, etc… Creation of custom outputs is discussed in Section [sec: custom outputs] and creation of custom models is discussed in Section [sec: custom-models].

Solver Constructor / Destructor

AsynchSolver *Asynch_Init(MPI_Comm comm, bool verbose)

This routine initializes an instance of an AsynchSolver.

Multiple solvers could be created if multiple problems are to be solved. An instance of an AsynchSolver contains all the relevant data structures and information to solve the equations for an underlying model. An AsynchSolver object should be destroyed with a call to Asynch_Free.

Pre
MPI should be properly initialized with MPI_Init before calling Asynch_Init.
Return
A pointer to an AsynchSolver object.
See
Asynch_Free
Parameters
  • comm: The MPI communicator to use with this solver object.

void Asynch_Free(AsynchSolver *asynch)

This routine deallocates the memory occupied by an AsynchSolver object created with a call to Asynch_Init.

See
Asynch_Init
Parameters
  • asynch: A pointer to a AsynchSolver object to free.

Solver Initialization

void Asynch_Parse_GBL(AsynchSolver *asynch, char *filename)

This routine opens and processes a global file.

It reads all specified database connection files, but does not process any other input file. An error in this routine is considered fatal, and results in a call to the routine MPI_Abort on the communicator used to create asynch.

Pre
asynch should be initialized with Asynch_Init before calling Asynch_Parse_GBL.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • filename: Path of a global file.

void Asynch_Load_Network(AsynchSolver *asynch)

This routine processes topology inputs for the AsynchSolver object as set in the global file read by Asynch_Parse_GBL.

This initializes each Link object and sets their parent and child information. Generally, this is the first initialization routine to call after parsing a global.

Pre
Asynch_Parse_GBL should be called before Asynch_Load_Network.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Partition_Network(AsynchSolver *asynch)

This routine assigns the Links of the asynchsolver object to the MPI processes.

Pre
This routine must be called after Asynch_Load_Network.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Load_Network_Parameters(AsynchSolver *asynch)

This routine processes parameter inputs for the AsynchSolver object as set in the global file read by Asynch_Parse_GBL.

Setting load_all to true causes every MPI process to store the parameters at every Link.

Pre
This routine can be called before Asynch_Partition_Network only if load_all is set to true.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Load_Dams(AsynchSolver *asynch)

This routine processes the is_dam inputs for the AsynchSolver object as set in the global file read by.

Pre
This routine should be called after Asynch_Partition_Network and Asynch_Load_Network_Parameters have been called.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Load_Numerical_Error_Data(AsynchSolver *asynch)

This routine processes numerical solver inputs for the AsynchSolver object as set in the global file read by Asynch_Parse_GBL.

Pre
This routine should be called after Asynch_Partition_Network has been called.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Initialize_Model(AsynchSolver *asynch)

This routine sets the model specific routines for each link for the AsynchSolver object as set in the global file read by Asynch_Parse_GBL.

Pre
This routine should be called after Asynch_Partition_Network and Asynch_Load_Network_Parameters have been called.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Load_Initial_Conditions(AsynchSolver *asynch)

This routine processes the initial condition inputs for the AsynchSolver object as set in the global file read by Asynch_Parse_GBL.

Pre
This routine should be called after Asynch_Partition_Network and Asynch_Initialize_Model have been called.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Load_Forcings(AsynchSolver *asynch)

This routine processes the forcing inputs for the AsynchSolver object as set in the global file read by Asynch_Parse_GBL.

Pre
This routine should be called after Asynch_Partition_Parameters has been called.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Load_Save_Lists(AsynchSolver *asynch)

This routine processes save list inputs for the AsynchSolver object as set in the global file read by Asynch_Parse_GBL.

Pre
This routine should be called after Asynch_Partition_Network has been called.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Finalize_Network(AsynchSolver *asynch)

This routine checks that all inputs are loaded for the AsynchSolver object.

Some small final initializations are also performed.

Pre
This routine should be called as the last initialization routine.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

Integration

void Asynch_Calculate_Step_Sizes(AsynchSolver *asynch)

This routine processes calculates appropriate step sizes for the integrators at each link in the AsynchSolver object.

Pre
This routine must be called before a call to Asynch_Advance, and after all initializations are performed.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Advance(AsynchSolver *asynch, int print_level)

This routine advances the numerical solver up to the time set in maxtime.

See Section [sec: model type and maxtime]. Calculations to solve the model differential and algebraic equations are performed, using forcing data as needed.

Pre
This routine should be called after Asynch_Partition_Network has been called.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • print_level: If 0, no time series information is produced. Otherwise, time series information is produced.

Timeseries Output

void Asynch_Prepare_Output(AsynchSolver *asynch)

This routine prepares the output sources for time series data.

Preparation includes creating files or database tables.

Pre
This routine must be called before any time series data can be produced.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

int Asynch_Create_Output(AsynchSolver *asynch, char *file_suffix)

This routine takes all data written to temporary files and moves them to a final output destination for time series data.

If the output format is data file or CSV file, then the string additional_out is appended to the filename. If additional_out is NULL, then no appending to the filename occurs.

Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • file_suffix: String appended to the end of any output filename. \ return Returns 0 if output is written, -1 means there is no data to output.

void Asynch_Prepare_Peakflow_Output(AsynchSolver *asynch)

This routine prepares the output sources for the peakflow data.

Preparation includes creating files or database tables.

Pre
This routine must be called before any peakflow data can be produced.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

int Asynch_Create_Peakflows_Output(AsynchSolver *asynch)

This routine takes all calculated peakflow data and writes them to a final output destination.

Parameters
  • asynch: A pointer to a AsynchSolver object to use. \ return Returns 0 if output is written, -1 means there is no data to output.

int Asynch_Write_Current_Step(AsynchSolver *asynch)

This routine writes the current state of each link to temporary files for every link where a time series output has been specified.

Normally, calling Asynch_Advance with the print_flag set is enough to write output time series. However, advancing an AsynchSolver object without the print_flag set or calls that modify how data is outputted to the temporary files will cause data to not be written for some times. This routine can be called to commit missing data.

Return
Returns 0 if the step is written, 1 if no temporary file is available.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

Temporary files

void Asynch_Prepare_Temp_Files(AsynchSolver *asynch)

This routine prepares the temporary files for time series data.

Preparation includes creating files or database tables.

Pre
This routine must be called before any time series data can be calculated. A call to Asynch_Advance with the print_flag set before preparing temporary files will create an error.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

int Asynch_Delete_Temporary_Files(AsynchSolver *asynch)

This routine deletes the tempfiles for asynch.

This is useful for cleaning up temporary files at the end of a simulation, or for deleting the files if they must be reconstructed.

Return
Returns 0 if the tempfiles were deleted, 1 if no tempfiles exist, and 2 if an error occurred.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

int Asynch_Set_Temp_Files(AsynchSolver *asynch, double set_time, void *set_value, unsigned int output_idx)

This routine moves the temporary file pointer to a previous value.

All future values are deleted. The point where the pointer is moved is determined by set_value, which is in the output series determined by output_idx. The local time where the next data will be written for each link is set_time.

Pre
A warning occurs if set_value is not found for a link, and that link’s tempfile pointer is not changed.
Return
Returns 0 if the temporary files are set, 1 if a warning occurred, 2 if there was an error setting the files.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • set_time: The local time corresponding the step where the temp files will be set.
  • set_value: The value to which the tempfiles will be set.
  • output_idx: The index of the series output of which set_value corresponds.

Snapshots

int Asynch_Take_System_Snapshot(AsynchSolver *asynch, char *prefix)

This routine processes calculates appropriate step sizes for the integrators at each link in the AsynchSolver object.

This routine creates snapshot output data to either a recovery file or a database table.

The current value of every state at every link is outputted. If a recovery file was the format specified in the global file, then the string

name is appended to the end of the recovery filename. This appending does not occur if name is NULL or if a database table is the selected format.
Pre
This routine must be called before a call to Asynch_Advance, and after all initializations are performed.
Return
An error code. Returns 0 if a snapshot was made, 1 if an error was encountered, -1 if no snapshot is made.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • prefix: String to prepend to the snapshot output filename.

Return
Returns 0 if a snapshot was made, 1 if an error was encountered, -1 if no snapshot is made.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • prefix: String to prepend to the snapshot output filename.

int Asynch_Get_Snapshot_Output_Name(AsynchSolver *asynch, char *filename)

This routine gets the filename of the output snapshot file.

If a database connection is used, then the contents of snapshotname is not modified. The Python interface routine returns the string with the filename instead of taking it as an argument.

Return
0 if the filename was set successfully. 1 otherwise.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • filename: Name of the snapshot output filename returned.

int Asynch_Set_Snapshot_Output_Name(AsynchSolver *asynch, char *filename)

This routine sets the filename of the output snapshot file.

If a database connection is used, then no changes are made.

Return
0 if the filename was set successfully. 1 otherwise.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • filename: Name to set the snapshot output filename.

Getters and Setters

unsigned short Asynch_Get_Model_Type(AsynchSolver *asynch)

This routine sets the model type.

Return
The model type
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Set_Model_Type(AsynchSolver *asynch, unsigned short type)

This routine returns the model type.

Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • type: The model type.

double Asynch_Get_Total_Simulation_Duration(AsynchSolver *asynch)

This routine returns the value of duration, as defined in Section[sec:simulation period].

Return
The current duration of the simulation time of the AsynchSolver object (unit is model dependant, but usually minutes is used).
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

void Asynch_Set_Total_Simulation_Duration(AsynchSolver *asynch, double duration)

This routine returns the value of duration, as defined in Section[sec:model type and duration].

Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • duration: The value to set the maximum simulation time.

unsigned short Asynch_Get_Num_Links(AsynchSolver *asynch)

This routine returns the total number of links in the network of asynch.

Return
Number of links in the network
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

Link *Asynch_Get_Links(AsynchSolver *asynch)

This routine returns the total number of links assigned to the current MPI process in the network of asynch.

This number represents the total number of links whose differential and algebraic equations are solved by the current process.

Return
Number of links assigned to the current MPI process
Parameters
  • asynch: A pointer to a AsynchSolver object to use.

Database

void Asynch_Set_Database_Connection(AsynchSolver *asynch, const char *conn_string, unsigned int conn_idx)

This routine sets a new database for an input or output.

If information for a database has already been set, it is released, and the new connection information is set. Database information includes hostname, username, password, etc. This is the same information that is available in the header of database connection files (see Section [sec: database connection files]). Several database connections exist for every AsynchSolver object. conn_idx can take the values:

  • ASYNCH_DB_LOC_TOPO
  • ASYNCH_DB_LOC_PARAMS
  • ASYNCH_DB_LOC_INIT
  • ASYNCH_DB_LOC_RSV
  • ASYNCH_DB_LOC_HYDROSAVE
  • ASYNCH_DB_LOC_PEAKSAVE
  • ASYNCH_DB_LOC_HYDRO_OUTPUT
  • ASYNCH_DB_LOC_PEAK_OUTPUT
  • ASYNCH_DB_LOC_SNAPSHOT_OUTPUT
  • ASYNCH_DB_LOC_FORCING_START

The last value for conn_idx is the database connection for the first forcing specified in the global file. Database connections for other forcings can be access sequentially. For example, to access the forcing with index 2 (the third forcing in a global file), set conn_idx as ASYNCH_DB_LOC_FORCING_START + 2

Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • conn_string: A connection string
  • conn_idx: Connection index

Forcing

int Asynch_Activate_Forcing(AsynchSolver *asynch, unsigned int idx)

This routine activates a forcing for use.This means when a call to the routine Asynch_Advance is made, the forcing with index idx will be applied for calculations.By default, all forcings set in a global file are initially active.This routine has the opposite effect of Asynch_Deactivate_Forcing.

Return
Returns 0 if the forcing was activated, 1 if an error occurred
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • idx: The index of the forcing to activate.

int Asynch_Deactivate_Forcing(AsynchSolver *asynch, unsigned int idx)

This routine deactivates a forcing for use.

This means when a call to the routine Asynch_Advance is made, all values for the forcing with index idx will be taken as 0. By default, all forcings set in a global file are initially active. This routine has the opposite effect of Asynch_Activate_Forcing.

Return
Returns 0 if the forcing was activated, 1 if an error occurred
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • idx: The index of the forcing to activate.

unsigned int Asynch_Get_First_Forcing_Timestamp(AsynchSolver *asynch, unsigned int forcing_idx)

This routine returns the first timestamp for a forcing.

Pre
This can only be used if the forcing with index forcing_idx is using a format of binary files, gz binary files, or database table. See Section [sec: forcing inputs] for adescription of these formats.
Return
The timestamp of the last timestamp for the forcing with index forcing_idx.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • forcing_idx: An index of a forcing.

void Asynch_Set_First_Forcing_Timestamp(AsynchSolver *asynch, unsigned int unix_time, unsigned int forcing_idx)

This routine sets the first timestamp for a forcing.

Pre
This can only be used if the forcing with index forcing_idx is using a format of binary files, gz binary files, or database table. See Section [sec: forcing inputs] for adescription of these formats.
Return
The timestamp of the last timestamp for the forcing with index forcing_idx.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • unix_time: The value to set the first forcing timestamp.
  • forcing_idx: An index of a forcing.

unsigned int Asynch_Get_Last_Forcing_Timestamp(AsynchSolver *asynch, unsigned int forcing_idx)

This routine returns the last timestamp for a forcing.

Pre
This can only be used if the forcing with index forcing_idx is using a format of binary files, gz binary files, or database table. See Section [sec: forcing inputs] for adescription of these formats.
Return
The timestamp of the last timestamp for the forcing with index forcing_idx.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • forcing_idx: An index of a forcing.

void Asynch_Set_Last_Forcing_Timestamp(AsynchSolver *asynch, unsigned int unix_time, unsigned int forcing_idx)

This routine sets the last timestamp for a forcing.

Pre
This can only be used if the forcing with index forcing_idx is using a format of binary files, gz binary files, or database table. See Section [sec: forcing inputs] for adescription of these formats.
Return
The timestamp of the last timestamp for the forcing with index forcing_idx.
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • unix_time: The value to set the last forcing timestamp.
  • forcing_idx: An index of a forcing.

void Asynch_Set_Forcing_DB_Starttime(AsynchSolver *asynch, unsigned int unix_time, unsigned int forcing_idx)

This routine sets the start time used for a forcing.

This value is used for converting between timestamps in a database table and the local time of the solvers. This can only be used if the forcing with index forcing_idx is using a format of database table. See Section [sec: forcing inputs] for a description of this format.

Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • unix_time: The value to set the start timestamp.
  • forcing_idx: An index of a forcing.

State Variables Getters and Setters

void Asynch_Set_Init_File(AsynchSolver *asynch, char *filename)

This routine sets a file for reading initial value data.

The init_flag is set based upon the extension of filename. The initial data is NOT read while executing this routine. A call to Asynch_Load_System is needed to set the filename. This routine cannot be used to set the format to a database connection.

Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • filename: Filename to use for initial value data.

void Asynch_Set_System_State(AsynchSolver *asynch, double unix_time, double *states)

This routine sets the current time of each link to t_0 and the current state to the vector in the array values.

The vectors are assumed to be in the same order as the links provided by the topology source specified in the global file (see Section [sec: topology]).

Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • unix_time: The timestamp to set at each link.
  • states: The vector of the current state of each link.

State Variables Getters and Setters

Custom Outputs

Time series outputs can be customized so as to produce results specific to a particular model. For instance, fluxes that are used internally to the model, or values that are not needed at all for computing state solutions, may be outputted.

To create a custom output, specify the name of your new output in the global file (see Section [sec: time series output]). Next, in your program after reading the global file but before performing simulations, call the routine Asynch_Set_Output to set your output. Then perform any calculations or further modifications as usual.

A custom routine must be provided by the user for determining how the output is calculated. The specifications for this function are provided below.

Similarly, custom peakflow outputs can be created. These are set with a call to the routine Asynch_Set_Peakflow_Output.

The routines for setting custom outputs are described below.

int Asynch_Set_Output_Int(AsynchSolver *asynch, char *name, OutputIntCallback *callback, unsigned int *used_states, unsigned int num_states)

This routine sets a custom output time series.

A function is required that will be called every time output data is to be written for a link. The function set in this routine should have the specification Asynch_Set_Output_Int must also be given an array used_states. This array contains the indices of the states in the state vectors which are needed by the user specified routine callback. All states listed in this array are guaranteed to be available for the routine callback.

See
Asynch_Set_Output_Double
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • name: Name of the custom time series.
  • callback: Routine to call when writing data for the custom output.
  • used_states: Array of the all indices in the state vector used by callback.
  • num_states: Numver of indiciced in used_states.

int Asynch_Set_Output_Double(AsynchSolver *asynch, char *name, OutputDoubleCallback *callback, unsigned int *used_states, unsigned int num_states)

This routine sets a custom output time series.

A function is required that will be called every time output data is to be written for a link. The function set in this routine should have the specification Asynch_Set_Output_Double must also be given an array used_states. This array contains the indices of the states in the state vectors which are needed by the user specified routine callback. All states listed in this array are guaranteed to be available for the routine callback.

See
Asynch_Set_Output_Int
Parameters
  • asynch: A pointer to a AsynchSolver object to use.
  • name: Name of the custom time series.
  • callback: Routine to call when writing data for the custom output.
  • used_states: Array of the all indices in the state vector used by callback.
  • num_states: Numver of indiciced in used_states.