Help:IRF Interface: Difference between revisions

From CSDMS
m (Update getter and setter sections)
m (Fix headings)
Line 28: Line 28:
In this case the initialization function takes an array of strings as input.  The strings might be names of input files to read from, or could be key/value pairs that set particular model variables.  These are just suggestions.  It may make sense for you model to initialize itself in a somewhat different way.  The main point is that you provide an entry point to your initialization step and document your particular interface.
In this case the initialization function takes an array of strings as input.  The strings might be names of input files to read from, or could be key/value pairs that set particular model variables.  These are just suggestions.  It may make sense for you model to initialize itself in a somewhat different way.  The main point is that you provide an entry point to your initialization step and document your particular interface.


=== Model Execution (the run step) ===
=== Run (Model Execution) ===


Your model's execute step should run your model for a particular amount of time (simulation time, that is).  Generally speaking, this will be the lines of code that are within you time loop.  If your model is time-independent, it should run just once though.  Ideally, it should save this state so that if it were to be called again it would not have to run through its calculations again; rather it would just maintain its current state, saving computation time.
Your model's execute step should run your model for a particular amount of time (simulation time, that is).  Generally speaking, this will be the lines of code that are within you time loop.  If your model is time-independent, it should run just once though.  Ideally, it should save this state so that if it were to be called again it would not have to run through its calculations again; rather it would just maintain its current state, saving computation time.
Line 45: Line 45:
</syntaxhighlight>
</syntaxhighlight>


=== Model Termination (the finalize step) ===
=== Finalize (Model Termination) ===


The finalize step cleans up after your model.  The main purpose of this step to make sure that all resources that your model acquired through its life have been freed.  Most often this will be freeing allocated memory, but could also be freeing file or network handles.  As we have said before, user interfaces should be left out of this step.  Following this step, the model should be left in an invalid state such that its run step can no longer be called.
The finalize step cleans up after your model.  The main purpose of this step to make sure that all resources that your model acquired through its life have been freed.  Most often this will be freeing allocated memory, but could also be freeing file or network handles.  As we have said before, user interfaces should be left out of this step.  Following this step, the model should be left in an invalid state such that its run step can no longer be called.
Line 95: Line 95:
Notice now that your application requires your model to provide an interface that exchanges data between it and the application.  From this example (highlighted), the application assumes that your model provides and interface to get data from it.  Such methods are sometimes referred to as getters or accessors.  Likewise, if you want an application to be able to change data within your model, you must provided an implementation for a setter (or mutator) interface.
Notice now that your application requires your model to provide an interface that exchanges data between it and the application.  From this example (highlighted), the application assumes that your model provides and interface to get data from it.  Such methods are sometimes referred to as getters or accessors.  Likewise, if you want an application to be able to change data within your model, you must provided an implementation for a setter (or mutator) interface.


== Model Accessors and Mutators ==
=== Model Accessors and Mutators ===


The IRF interface described above allows a calling application to control the execution of your model.  The application may be the one that you have already written.  In which case, the new interface has really just acted to clean up you code and hopefully made it easier to maintain.  However, the new interface has also made it easier for someone else to take you model and wrap it inside another application.  Because the IRF interface provides a way to control the model's execution, ultimately the new application will be similar to yours.  What could do though is put a completely new user interface on your model.  For instance, someone could wrap your model in an application that reads input from a new file format, or maybe from a graphical user interface.
The IRF interface described above allows a calling application to control the execution of your model.  The application may be the one that you have already written.  In which case, the new interface has really just acted to clean up you code and hopefully made it easier to maintain.  However, the new interface has also made it easier for someone else to take you model and wrap it inside another application.  Because the IRF interface provides a way to control the model's execution, ultimately the new application will be similar to yours.  What could do though is put a completely new user interface on your model.  For instance, someone could wrap your model in an application that reads input from a new file format, or maybe from a graphical user interface.
Line 101: Line 101:
You may have noticed though that there are still a couple of things missing from this interface that would be useful.  For your model to be able to meaningfully communicate with other models, you should be able to exchange values that your model calculates.  Furthermore, your model should provide a means for another model to set particular values of itself.  One way of doing this is through a getter and setter interface.  As we have seen, a barebones IRF interface is certainly valuable but the more getter and setter methods your model has, the more useful it will be in linking with other models.
You may have noticed though that there are still a couple of things missing from this interface that would be useful.  For your model to be able to meaningfully communicate with other models, you should be able to exchange values that your model calculates.  Furthermore, your model should provide a means for another model to set particular values of itself.  One way of doing this is through a getter and setter interface.  As we have seen, a barebones IRF interface is certainly valuable but the more getter and setter methods your model has, the more useful it will be in linking with other models.


== Value Getters ==
=== Value Getters ===


If an application wishes to access values that your model calculates, your model should implement some kind of getter method (or methods).  This allows you to control what data your model shares with another program and how it shares it.  The main purpose of a getter method is to hide implementation details of your model from another programmer  
If an application wishes to access values that your model calculates, your model should implement some kind of getter method (or methods).  This allows you to control what data your model shares with another program and how it shares it.  The main purpose of a getter method is to hide implementation details of your model from another programmer  
Line 113: Line 113:
</syntaxhighlight>
</syntaxhighlight>


== Value Setters ==
=== Value Setters ===


Sample interface:
Sample interface:

Revision as of 10:27, 22 July 2009

CSDMS Model Interface Standards

For you model application to become a component that can be linked in meaningful ways to other model components, it must have a application programming interface (API). CSDMS asks model contributors to provide a minimal set of functions that allow a calling program to control the component's execution. The minimal set of interface functions would be those that initialize, run, and finalize a component model - the IRF interface. For more complete linkages, your API should also contain value accessors and mutators so that an application can query and change state variables of your model.

The IRF Interface

Numerical models can generally be subdivided into three phases: set up, execution, and teardown. The set up phase occurs before time stepping begins and initializes the model. The execution phase is the guts of your model and will be most everything within the main time loop of the model. The teardown phase occurs after time stepping and acts to clean up the model simulation.

There are many models that are time-independent and so do not have a time loop but that is not to say that they don't have an execution step. In this case, the model calculations can be thought of as a time-stepping model with just one time step. I hope that the following sections will have some of this more clear.

Initialize (Model Set Up)

Before a model enters into its time-stepping loop, it will usually execute a set of commands necessary to set up the subsequent model simulation. This can be thought of as the initialization step - the lines of code before the time loop. The initialize step will put your model into a valid state that is ready to be executed. Mostly this will be initializing variables or grids that will subsequently be used within the execution step. Temporary files that the execution step will read from or write to should also be opened here. Note however that any files that are intended as an interface to a user, should not be used here. User interfaces belong outside of the IRF modeling interface.

Things to include in your model's initialization function:

  • Initialize variables.
  • Allocate memory.
  • Open temporary files
  • Stuff that is done once, and is before the time loop.

Things not to include in your model's initialization function:

  • User interfaces. Your initialization function should not include a user interface (graphical user interface, or a command line interface, for example). This should be taken care of by the calling application.

A typical interface for model initialization:

int init_my_model ( char **strs );

In this case the initialization function takes an array of strings as input. The strings might be names of input files to read from, or could be key/value pairs that set particular model variables. These are just suggestions. It may make sense for you model to initialize itself in a somewhat different way. The main point is that you provide an entry point to your initialization step and document your particular interface.

Run (Model Execution)

Your model's execute step should run your model for a particular amount of time (simulation time, that is). Generally speaking, this will be the lines of code that are within you time loop. If your model is time-independent, it should run just once though. Ideally, it should save this state so that if it were to be called again it would not have to run through its calculations again; rather it would just maintain its current state, saving computation time.

Things to include:

  • Code that updates the state of you model.


Things not to include:

  • User interfaces. This could include, for instance, plotting of the model's state as it's running. These things should be taken care of by the application that runs your component.
  • Writing data to output files. This is just another interface and the calling application should do this.

Sample interface:

int run_my_model (double time);

Finalize (Model Termination)

The finalize step cleans up after your model. The main purpose of this step to make sure that all resources that your model acquired through its life have been freed. Most often this will be freeing allocated memory, but could also be freeing file or network handles. As we have said before, user interfaces should be left out of this step. Following this step, the model should be left in an invalid state such that its run step can no longer be called.

Things to include:

  • Freeing memory.
  • Closing files.

Things not to include:

  • User interfaces such as writing to an output file intended to be read by a user.

Sample interface:

int finalize_my_model (void);

Your Model Application

Notice that the above interfaces have excluded any user interfaces. As we've stated above, the application should take care of user interfaces. With the above interfaces, your model application will consist of a call to your initialize function, followed by your run function (possibly wrapped in a for loop, say), followed by a call to your finalize function. Between these calls, will be your user interface. The particular user interface that you decide to use is up to you.

Without any user interface, your application might look someting like the following pseudocode,

CALL model init function

REPEAT
  CALL model run function for some duration
  INCREMENT time
UNTIL time < end time

CALL model finalize function

Since an application is not of much use if it doesn't interface in some way with a user, you need to add a user interface. The pseudocode for this might look like,

DISPLAY GUI to collect initialization data
CALL model init function

REPEAT
  CALL model run function for some duration
  GET model data
  PRINT data to an output file
  DISPLAY data to screen
UNTIL time < end time

PRINT final data to file
CALL model finalize function

Notice now that your application requires your model to provide an interface that exchanges data between it and the application. From this example (highlighted), the application assumes that your model provides and interface to get data from it. Such methods are sometimes referred to as getters or accessors. Likewise, if you want an application to be able to change data within your model, you must provided an implementation for a setter (or mutator) interface.

Model Accessors and Mutators

The IRF interface described above allows a calling application to control the execution of your model. The application may be the one that you have already written. In which case, the new interface has really just acted to clean up you code and hopefully made it easier to maintain. However, the new interface has also made it easier for someone else to take you model and wrap it inside another application. Because the IRF interface provides a way to control the model's execution, ultimately the new application will be similar to yours. What could do though is put a completely new user interface on your model. For instance, someone could wrap your model in an application that reads input from a new file format, or maybe from a graphical user interface.

You may have noticed though that there are still a couple of things missing from this interface that would be useful. For your model to be able to meaningfully communicate with other models, you should be able to exchange values that your model calculates. Furthermore, your model should provide a means for another model to set particular values of itself. One way of doing this is through a getter and setter interface. As we have seen, a barebones IRF interface is certainly valuable but the more getter and setter methods your model has, the more useful it will be in linking with other models.

Value Getters

If an application wishes to access values that your model calculates, your model should implement some kind of getter method (or methods). This allows you to control what data your model shares with another program and how it shares it. The main purpose of a getter method is to hide implementation details of your model from another programmer

  • Return copy or actual data?
  • Validity check

Sample interface:

int my_model_get_value (char* value_str, double** value_grid);

Value Setters

Sample interface:

int my_model_set_value (char* value_str, double** new_value);