From e3b2866236998031349544d9fd504b61b3702a58 Mon Sep 17 00:00:00 2001 From: Phil Miller Date: Mon, 25 Aug 2025 11:36:28 -0700 Subject: [PATCH 1/4] Bump version in interface to 3.0 to reflect API breakage and intention for major version --- bmi.sidl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bmi.sidl b/bmi.sidl index 9c3b0fb..30766a8 100644 --- a/bmi.sidl +++ b/bmi.sidl @@ -1,8 +1,8 @@ // // The Basic Model Interface (BMI) // -package csdms version 2.1-dev.0 { - interface bmi { +package csdms version 3.0-alpha1 { + interface bmi3 { // Model and BMI metadata int get_bmi_version(out string version); From f21a27b6f9303b0e01fadb24dd478ec6ecafe5a5 Mon Sep 17 00:00:00 2001 From: Phil Miller Date: Mon, 3 Nov 2025 17:32:34 -0800 Subject: [PATCH 2/4] Replace use of variable names with numeric index values throughout --- bmi.sidl | 23 +++++----- docs/source/bmi.getter_setter.md | 36 +++++++-------- docs/source/bmi.var_funcs.md | 79 +++++++++++++++++++++++--------- 3 files changed, 87 insertions(+), 51 deletions(-) diff --git a/bmi.sidl b/bmi.sidl index 30766a8..d5c3599 100644 --- a/bmi.sidl +++ b/bmi.sidl @@ -21,12 +21,13 @@ package csdms version 3.0-alpha1 { int get_output_var_names(out array names); // Variable information - int get_var_grid(in string name, out int grid); - int get_var_type(in string name, out string type); - int get_var_units(in string name, out string units); - int get_var_itemsize(in string name, out int size); - int get_var_nbytes(in string name, out int nbytes); - int get_var_location(in string name, out string location); + int get_var_index(in string name, out int index); + int get_var_grid(in int index, out int grid); + int get_var_type(in int index, out string type); + int get_var_units(in int index, out string units); + int get_var_itemsize(in int index, out int size); + int get_var_nbytes(in int index, out int nbytes); + int get_var_location(in int index, out string location); // Time information int get_current_time(out double time); @@ -36,14 +37,14 @@ package csdms version 3.0-alpha1 { int get_time_step(out double time_step); // Getters - int get_value(in string name, in array<> dest); - int get_value_ptr(in string name, out array<> dest_ptr); - int get_value_at_indices(in string name, in array<> dest, + int get_value(in int index, in array<> dest); + int get_value_ptr(in int index, out array<> dest_ptr); + int get_value_at_indices(in int index, in array<> dest, in array inds); // Setters - int set_value(in string name, in array<> src); - int set_value_at_indices(in string name, in array inds, + int set_value(in int index, in array<> src); + int set_value_at_indices(in int index, in array inds, in array<> src); // Grid information diff --git a/docs/source/bmi.getter_setter.md b/docs/source/bmi.getter_setter.md index 0b4073d..1eaffb0 100644 --- a/docs/source/bmi.getter_setter.md +++ b/docs/source/bmi.getter_setter.md @@ -24,25 +24,25 @@ state variable can be changed or check the new data for validity. :::{tab-item} SIDL :sync: sidl ```java -int get_value(in string name, in array<> dest); +int get_value(in int index, in array<> dest); ``` ::: :::{tab-item} Python :sync: python ```python -def get_value(self, name: str, dest: NDArray[Any]) -> NDArray[Any]: +def get_value(self, index: int, dest: NDArray[Any]) -> NDArray[Any]: ``` ::: :::{tab-item} c :sync: c ```c -int get_value(void *self, const char *name, void *dest); +int get_value(void *self, int index, void *dest); ``` ::: :::: -The `get_value` function takes a variable name and copies values into a +The `get_value` function takes a variable index and copies values into a provided array parameter. The type and size of the array parameter depend on the variable, and can be determined through @@ -75,25 +75,25 @@ even if the model uses dimensional variables. :::{tab-item} SIDL :sync: sidl ```java -int get_value_ptr(in string name, out array<> dest_ptr); +int get_value_ptr(in int index, out array<> dest_ptr); ``` ::: :::{tab-item} Python :sync: python ```python -def get_value_ptr(self, name: str) -> NDArray[Any]: +def get_value_ptr(self, index: int) -> NDArray[Any]: ``` ::: :::{tab-item} c :sync: c ```c -int get_value_ptr(void *self, const char *name, void **dest_ptr); +int get_value_ptr(void *self, int index, void **dest_ptr); ``` ::: :::: -The `get_value_ptr` function takes a variable name and returns a reference +The `get_value_ptr` function takes a variable index and returns a reference to a variable. Unlike the array parameter returned from {ref}`get-value`, the reference always points to the current values of the variable, @@ -119,7 +119,7 @@ even if the model's state has changed. :::{tab-item} SIDL :sync: sidl ```java -int get_value_at_indices(in string name, in array<> dest, in array inds); +int get_value_at_indices(in int index, in array<> dest, in array inds); ``` ::: @@ -127,7 +127,7 @@ int get_value_at_indices(in string name, in array<> dest, in array inds) :sync: python ```python def get_value_at_indices( - self, name: str, dest: NDArray[Any], inds: NDArray[np.int_] + self, index: int, dest: NDArray[Any], inds: NDArray[np.int_] ) -> NDArray[Any]: ``` ::: @@ -135,7 +135,7 @@ def get_value_at_indices( :sync: c ```c int get_value_at_indices( - void *self, const char *name, void *dest, int *inds, int count + void *self, int index, void *dest, int *inds, int count ); ``` ::: @@ -164,25 +164,25 @@ Additionally, :::{tab-item} SIDL :sync: sidl ```java -int set_value(in string name, in array<> src); +int set_value(in int index, in array<> src); ``` ::: :::{tab-item} Python :sync: python ```python -def set_value(self, name: str, src: NDArray[Any]) -> None: +def set_value(self, index: int, src: NDArray[Any]) -> None: ``` ::: :::{tab-item} c :sync: c ```c -int set_value(void *self, const char *name, void *src); +int set_value(void *self, int index, void *src); ``` ::: :::: -The `set_value` function takes a variable name and an array of values, +The `set_value` function takes a variable index and an array of values, *src*, and copies those values into the model's internal array of values, overwriting the current contents. @@ -214,7 +214,7 @@ even if the model uses dimensional variables. :::{tab-item} SIDL :sync: sidl ```java -int set_value_at_indices(in string name, in array inds, in array<> src); +int set_value_at_indices(in int index, in array inds, in array<> src); ``` ::: @@ -222,7 +222,7 @@ int set_value_at_indices(in string name, in array inds, in array<> src); :sync: python ```python def set_value_at_indices( - self, name: str, inds: NDArray[np.int_], src: NDArray[Any] + self, index: int, inds: NDArray[np.int_], src: NDArray[Any] ) -> None: ``` ::: @@ -230,7 +230,7 @@ def set_value_at_indices( :sync: c ```c int set_value_at_indices( - void *self, const char *name, int *inds, int count, void *src + void *self, int index, int *inds, int count, void *src ); ``` ::: diff --git a/docs/source/bmi.var_funcs.md b/docs/source/bmi.var_funcs.md index b22d754..75bbaf4 100644 --- a/docs/source/bmi.var_funcs.md +++ b/docs/source/bmi.var_funcs.md @@ -6,9 +6,44 @@ These BMI functions provide information about a particular input or output variable. They must accommodate any variable returned from the {ref}`get-input-var-names` or {ref}`get-output-var-names` functions -- -the variable name is used as an argument in each function. -Based on the information returned, -type or unit conversions can be applied when necessary. +the variable index as obtained from {ref}`get-var-index` is used as an argument in each function. +Based on the information returned, type or unit conversions can be applied when necessary. + +(get-var-index)= + +## *get_var_index* + +::::{tab-set} +:sync-group: lang + +:::{tab-item} SIDL +:sync: sidl + +```java +int get_var_index(in string name, out int index); +``` +::: +:::{tab-item} Python +:sync: python +```python +def get_var_index(self, name: str) -> int: +``` +::: +:::{tab-item} c +:sync: c +```c +int get_var_index(void *self, const char *name, int *index); +``` +::: +:::: + +Each input and output variable is associated with a numerical index. +The `get_var_index` function provides the value for this index. +These index values need not be in any particular order or range. +The identifier can be passed to the BMI +{ref}`variable information ` functions +to get the details of a particular variable; +e.g., size, type, units, grid, etc. (get-var-grid)= @@ -21,19 +56,19 @@ type or unit conversions can be applied when necessary. :sync: sidl ```java -int get_var_grid(in string name, out int grid); +int get_var_grid(in int index, out int grid); ``` ::: :::{tab-item} Python :sync: python ```python -def get_var_grid(self, name: str) -> int: +def get_var_grid(self, index: int) -> int: ``` ::: :::{tab-item} c :sync: c ```c -int get_var_grid(void *self, const char *name, int *grid); +int get_var_grid(void *self, int index, int *grid); ``` ::: :::: @@ -65,20 +100,20 @@ A model can have one or more grids. :::{tab-item} SIDL :sync: sidl ```java -int get_var_type(in string name, out string type); +int get_var_type(in int index, out string type); ``` ::: :::{tab-item} Python :sync: python ```python -def get_var_type(self, name: str) -> str: +def get_var_type(self, index: int) -> str: ``` ::: :::{tab-item} c :sync: c ```c -int get_var_type(void *self, const char *name, char *type); +int get_var_type(void *self, int index, char *type); ``` ::: :::: @@ -110,19 +145,19 @@ while in Fortran, use `integer`, `real`, and `double precision`. :sync: sidl ```java -int get_var_units(in string name, out string units); +int get_var_units(in int index, out string units); ``` ::: :::{tab-item} Python :sync: python ```python -def get_var_units(self, name: str) -> str: +def get_var_units(self, index: int) -> str: ``` ::: :::{tab-item} c :sync: c ```c -int get_var_units(void *self, const char *name, char *units); +int get_var_units(void *self, int index, char *units); ``` ::: :::: @@ -159,20 +194,20 @@ full description of valid unit names and a list of supported units. :::{tab-item} SIDL :sync: sidl ```java -int get_var_itemsize(in string name, out int size); +int get_var_itemsize(in int index, out int size); ``` ::: :::{tab-item} Python :sync: python ```python -def get_var_itemsize(self, name: str) -> int: +def get_var_itemsize(self, index: int) -> int: ``` ::: :::{tab-item} c :sync: c ```c -int get_var_itemsize(void *self, const char *name, int *size); +int get_var_itemsize(void *self, int index, int *size); ``` ::: :::: @@ -199,20 +234,20 @@ For example, if data for a variable are stored as 64-bit integers, :::{tab-item} SIDL :sync: sidl ```java -int get_var_nbytes(in string name, out int nbytes); +int get_var_nbytes(in int index, out int nbytes); ``` ::: :::{tab-item} Python :sync: python ```python -def get_var_nbytes(self, name: str) -> int: +def get_var_nbytes(self, index: int) -> int: ``` ::: :::{tab-item} c :sync: c ```c -int get_var_nbytes(void *self, const char *name, int *nbytes); +int get_var_nbytes(void *self, int index, int *nbytes); ``` ::: :::: @@ -237,26 +272,26 @@ a variable; i.e., the number of items multiplied by the size of each item. :::{tab-item} SIDL :sync: sidl ```java -int get_var_location(in string name, out string location); +int get_var_location(in int index, out string location); ``` ::: :::{tab-item} Python :sync: python ```python -def get_var_location(self, name: str) -> str: +def get_var_location(self, index: int) -> str: ``` ::: :::{tab-item} c :sync: c ```c -int get_var_location(void *self, const char *name, char *location); +int get_var_location(void *self, int index, char *location); ``` ::: :::: The `get_var_location` function, -given a variable name, returns a string that indicates on what grid +given a variable index, returns a string that indicates on what grid element the variable is defined. Valid return values are: - `node` From 315be80a89bd2c752c56dafbf4f7adcf93dc37e9 Mon Sep 17 00:00:00 2001 From: Phil Miller Date: Mon, 25 Aug 2025 11:36:34 -0700 Subject: [PATCH 3/4] Preliminary wording for defining sets of variables exported by a model --- bmi.sidl | 8 +- docs/source/bmi.info_funcs.md | 136 +++++++--------------------------- docs/source/bmi.spec.md | 6 +- 3 files changed, 31 insertions(+), 119 deletions(-) diff --git a/bmi.sidl b/bmi.sidl index d5c3599..3a19b35 100644 --- a/bmi.sidl +++ b/bmi.sidl @@ -15,10 +15,10 @@ package csdms version 3.0-alpha1 { // Model information int get_component_name(out string name); - int get_input_item_count(out int count); - int get_output_item_count(out int count); - int get_input_var_names(out array names); - int get_output_var_names(out array names); + + // Variable set information + int get_varset_member_count(in string set_name, out int count); + int get_varset_members(in string set_name, out array names); // Variable information int get_var_index(in string name, out int index); diff --git a/docs/source/bmi.info_funcs.md b/docs/source/bmi.info_funcs.md index 31efc1a..19e23c3 100644 --- a/docs/source/bmi.info_funcs.md +++ b/docs/source/bmi.info_funcs.md @@ -46,121 +46,83 @@ but it should be unique to prevent conflicts with other components. - In C++, Java, and Python, this argument is omitted, and a string -- a basic type in these languages -- is returned from the function. -(get-input-item-count)= +(get-varset-member-count)= -## *get_input_item_count* +## *get_varset_member_count* ::::{tab-set} :sync-group: lang :::{tab-item} SIDL :sync: sidl -```java -int get_input_item_count(out int count); -``` -::: -:::{tab-item} Python -:sync: python -```python -def get_input_item_count(self) -> int: -``` -::: -:::{tab-item} c -:sync: c -```c -int get_input_item_count(void *self, int *count); -``` -::: -:::: - -The number of variables the model can use from other models -implementing a BMI. -Also the number of variables that can be set with {ref}`set-value`. - -**Implementation notes** - -- In C++, Java, and Python, the argument is omitted and the count is returned - from the function. -- In C and Fortran, an integer status code indicating success (zero) or failure - (nonzero) is returned. - -(get-output-item-count)= - -## *get_output_item_count* - -::::{tab-set} -:sync-group: lang - -:::{tab-item} SIDL -:sync: sidl ```java -int get_output_item_count(out int count); +int get_varset_member_count(in string set_name, out int count); ``` ::: - :::{tab-item} Python :sync: python ```python -def get_output_item_count(self) -> int: +def get_varset_member_count(self, set_name: str) -> int: ``` ::: :::{tab-item} c :sync: c ```c -int get_output_item_count(void *self, int *count); +int get_varset_member_count(void *self, const char *name, int *count); ``` ::: :::: -The number of variables the model can provide other models -implementing a BMI. -Also the number of variables that can be retrieved with {ref}`get-value`. +Gets the number of exchange items in a particular set exposed by the model. **Implementation notes** -- In C++, Java, and Python, the argument is omitted and the count is - returned from the function. -- In C and Fortran, an integer status code indicating success (zero) or failure - (nonzero) is returned. +- In C++, Java, and Python, the *count* argument is omitted and the count + is returned from the function. +- In C and Fortran, an integer status code indicating success (BMI_SUCCESS) or + failure (BMI_FAILURE) is returned. -(get-input-var-names)= +(get-varset-members)= -## *get_input_var_names* +## *get_varset_members* ::::{tab-set} :sync-group: lang :::{tab-item} SIDL :sync: sidl + ```java -int get_input_var_names(out array names); +int get_varset_members(in string set_name, out array names); ``` ::: :::{tab-item} Python :sync: python ```python -def get_input_var_names(self) -> tuple[str, ...]: +def get_varset_members(self, set_name: str) -> tuple[str, ...]: ``` ::: :::{tab-item} c :sync: c ```c -int get_input_var_names(void *self, char **names); +int get_varset_members(void *self, const char *name, char const* const* members); ``` ::: :::: -Gets an array of names for the variables the model can use from other -models implementing a BMI. -The length of the array is given by {ref}`get-input-item-count`. +Gets an array of names for the variables the model publishes in the requested set. +The length of the array is given by {ref}`get-varset-member-count`. The names are preferably in the form of CSDMS {term}`Standard Names`. -Standard Names enable a modeling framework to determine whether an -input variable in one model is equivalent to, or compatible with, -an output variable in another model. +Standard Names enable a modeling framework to determine whether a +variable in one model is equivalent to, or compatible with, +a corresponding variable in another model. This allows the framework to automatically connect components. Standard Names do not have to be used within the model. +Available variable sets are defined by this specification, extensions, +or private conventions between the caller and model. + **Implementation notes** - In C and Fortran, the names are passed back as an array of character @@ -174,53 +136,5 @@ Standard Names do not have to be used within the model. function in a tuple, a standard container in the language. - A model might have no input variables. -(get-output-var-names)= - -## *get_output_var_names* - -::::{tab-set} -:sync-group: lang - -:::{tab-item} SIDL -:sync: sidl -```java -int get_output_var_names(out array names); -``` +:::{include} links.md ::: - -:::{tab-item} Python -:sync: python -```python -def get_output_var_names(self) -> tuple[str, ...]: -``` -::: -:::{tab-item} c -:sync: c -```c -int get_output_var_names(void *self, char **names); -``` -::: -:::: - -Gets an array of names for the variables the model can provide to other -models implementing a BMI. -The length of the array is given by {ref}`get-output-item-count`. -The names are preferably in the form of CSDMS {term}`Standard Names`. -Standard Names enable a modeling framework to determine whether an -input variable in one model is equivalent to, or compatible with, -an output variable in another model. -This allows the framework to automatically connect components. -Standard Names do not have to be used within the model. - -**Implementation notes** - -- In C and Fortran, the names are passed back as an array of character - pointers (because the variable names could have differing lengths), and an - integer status code indicating success (zero) or failure (nonzero) is returned. -- In C++, the argument is omitted and the names are returned from the - function in a vector, a standard container in the language. -- In Java, the argument is omitted and the names are returned from the - function in a string array, a standard container in the language. -- In Python, the argument is omitted and the names are returned from the - function in a tuple, a standard container in the language. -- A model may have no output variables. diff --git a/docs/source/bmi.spec.md b/docs/source/bmi.spec.md index c94eace..8f01edc 100644 --- a/docs/source/bmi.spec.md +++ b/docs/source/bmi.spec.md @@ -35,10 +35,8 @@ grouped by functional category. | {ref}`update-until` | Advance model state until the given time. | | {ref}`finalize` | Perform tear-down tasks for the model. | | {ref}`get-component-name` | Name of the model. | -| {ref}`get-input-item-count` | Count of a model's input variables. | -| {ref}`get-output-item-count` | Count of a model's output variables. | -| {ref}`get-input-var-names` | List of a model's input variables. | -| {ref}`get-output-var-names` | List of a model's output variables. | +| {ref}`get-varset-item-count` | Count of a model's variables in a set. | +| {ref}`get-varset-members` | List of a model's variables in a set. | | {ref}`get-var-grid` | Get the grid identifier for a variable. | | {ref}`get-var-type` | Get the data type of a variable. | | {ref}`get-var-units` | Get the units of a variable. | From 96727bea3b0623d5ca0150bda3b823c581f2386c Mon Sep 17 00:00:00 2001 From: Phil Miller Date: Mon, 3 Nov 2025 17:47:42 -0800 Subject: [PATCH 4/4] Make get_varset_members return both names and indexes as a convenience, since every downstream function now takes the index --- bmi.sidl | 2 +- docs/source/bmi.info_funcs.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bmi.sidl b/bmi.sidl index 3a19b35..e89869e 100644 --- a/bmi.sidl +++ b/bmi.sidl @@ -18,7 +18,7 @@ package csdms version 3.0-alpha1 { // Variable set information int get_varset_member_count(in string set_name, out int count); - int get_varset_members(in string set_name, out array names); + int get_varset_members(in string set_name, out array names, out array indexes); // Variable information int get_var_index(in string name, out int index); diff --git a/docs/source/bmi.info_funcs.md b/docs/source/bmi.info_funcs.md index 19e23c3..0732daa 100644 --- a/docs/source/bmi.info_funcs.md +++ b/docs/source/bmi.info_funcs.md @@ -94,25 +94,25 @@ Gets the number of exchange items in a particular set exposed by the model. :sync: sidl ```java -int get_varset_members(in string set_name, out array names); +int get_varset_members(in string set_name, out array names, out array indexes); ``` ::: :::{tab-item} Python :sync: python ```python -def get_varset_members(self, set_name: str) -> tuple[str, ...]: +def get_varset_members(self, set_name: str) -> Mapping[str, int]: ``` ::: :::{tab-item} c :sync: c ```c -int get_varset_members(void *self, const char *name, char const* const* members); +int get_varset_members(void *self, const char *name, char const* const* members, int *indexes); ``` ::: :::: -Gets an array of names for the variables the model publishes in the requested set. -The length of the array is given by {ref}`get-varset-member-count`. +Gets the names and indexes for the variables the model publishes in the requested set. +The length of each array is given by {ref}`get-varset-member-count`. The names are preferably in the form of CSDMS {term}`Standard Names`. Standard Names enable a modeling framework to determine whether a variable in one model is equivalent to, or compatible with,