From 9b340a2d699ea5122371781d3ec2b32a8c961258 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Wed, 19 Oct 2022 20:33:07 -0700 Subject: [PATCH] defaults (#2448) * Allow specification of default values for inputs in the json and toml configurations * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Minor edits to Config. Options Reference for new `defaults` parameters * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Update docs/references/configuration_options_reference.md Co-authored-by: Ryan Mast <3969255+nightlark@users.noreply.github.com> * Update docs/references/configuration_options_reference.md Co-authored-by: Ryan Mast <3969255+nightlark@users.noreply.github.com> * Update docs/user-guide/fundamental_topics/interface_configuration.md Co-authored-by: Ryan Mast <3969255+nightlark@users.noreply.github.com> * Update docs/user-guide/fundamental_topics/interface_configuration.md Co-authored-by: Ryan Mast <3969255+nightlark@users.noreply.github.com> * Corrected `helicsInputSetDefaultTime()` and `helicsInputSetDefaultNamedPoint()` in Config. Options Reference * Apply suggestions from code review Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Trevor Hardy Co-authored-by: Ryan Mast <3969255+nightlark@users.noreply.github.com> --- .../configuration_options_reference.md | 30 ++++++++++++++++ .../interface_configuration.md | 34 +++++++++++++++++-- src/helics/application_api/ValueFederate.cpp | 19 +++++++++-- .../ValueFederateAdditionalTests.cpp | 13 +++++++ .../test_files/example_value_fed_testb.json | 4 ++- .../test_files/example_value_fed_testb.toml | 4 +-- 6 files changed, 96 insertions(+), 8 deletions(-) diff --git a/docs/references/configuration_options_reference.md b/docs/references/configuration_options_reference.md index 613a3ecc4a..8d2b5eb6d2 100644 --- a/docs/references/configuration_options_reference.md +++ b/docs/references/configuration_options_reference.md @@ -160,6 +160,7 @@ An example of one publication, subscription, named input, endpoint, and filter i "subscriptions": [ { "only_update_on_change": false, + "default": value, } ], "inputs": [ @@ -171,6 +172,7 @@ An example of one publication, subscription, named input, endpoint, and filter i "multiple_connections_allowed": false "multi_input_handling_method": "average", "targets": ["pub1", "pub2"] + "default": 5.5, } ], "endpoints": [ @@ -761,6 +763,34 @@ This option allows the specific numerical definition of "change" when using the --- +### `default` + +_API:_ `helicsInputSetDefaultX` +[C++ input](https://docs.helics.org/en/latest/doxygen/classhelics_1_1Input.html#a55056ac9dd2895270f575827dd9951c7) +| [C input](api-reference/C_API.md#input) +| [Python input](https://python.helics.org/api/capi-py.html#helicsInputSetDefault) +| [Julia input](https://julia.helics.org/latest/api/#HELICS.helicsInputSetDefulat-Tuple{HELICS.Input,XXX}) + +This option allows specifying the default value used when no publication has been received. Each datatype has its own API call such as: + +- `helicsInputSetDefaultBoolean()` +- `helicsInputSetDefaultBytes()` +- `helicsInputSetDefaultChar()` +- `helicsInputSetDefaultComplex()` +- `helicsInputSetDefaultComplexVector()` +- `helicsInputSetDefaulDouble()` +- `helicsInputSetDefaultInteger()` +- `helicsInputSetDefaultRaw()` +- `helicsInputSetDefaultString()` (used for JSONs) +- `helicsInputSetDefaultVector()` + +Though they are not as obviously named, the following two APIs do provide a means of setting the default value as well: + +- `helicsInputSetDefaultTime()` - set the default using a HelicsTime value +- `helicsInputSetDefaultNamedPoint()` -set the default NamedPoint which is a pair of a string and double used for tagged values or set points + +--- + ### `connection_required` | `connectionrequired` | `connectionRequired` [false] _API:_ `helicsFederateInfoSetFlagOption` diff --git a/docs/user-guide/fundamental_topics/interface_configuration.md b/docs/user-guide/fundamental_topics/interface_configuration.md index bd79431bfe..93a87f6903 100644 --- a/docs/user-guide/fundamental_topics/interface_configuration.md +++ b/docs/user-guide/fundamental_topics/interface_configuration.md @@ -66,9 +66,25 @@ Below is a sample JSON configuration file with some of the more common options. "unit":"A", "global": true, "only_update_on_change": true, - "tolerance": 0.2 + "tolerance": 0.2, + "default":0.91 } - ] + ], + "inputs": [ + { + "key": "ipt2", + "type": "double", + "connection_required": true, + "target": "pub1", + "global": true, + "default":"3.67", + "tags": [ + { "name": "period", "value": "0.7" }, + { "name": "description", "value": "a test input" } + ] + } + //specify an input with a target multiple targets could be specified like "targets":["pub1","pub2","pub3"] + ], } ``` @@ -93,15 +109,29 @@ Below is a sample JSON configuration file with some of the more common options. - `type` - Data type, such as integer, double, complex. - `units` - The units can be any sort of unit string, a wide assortment is supported and can be compound units such as m/s^2 and the conversion will convert as long as things are convertible. The unit match is also checked for other types and an error if mismatching units are detected. A warning is also generated if the units are not understood and not matching. The unit checking and conversion is only active if both the publication and subscription specify units. HELICS is able to do some levels of unit conversion, currently only on double type publications but more may be added in the future. - `only_transmit_on_change` and `tolerance` - Publications will only send a new value out to the federation when the value has changed more than the delta specified by `tolerance`. + - `alias` - an alternate name for the publication must be globally unique for publications - `tags` - Arbitrary string value pairs that can be applied to interfaces. Tags are available to others through queries but are not transmitted by default. They can be used to store additional information about an interface that might be useful to applications. At some point in the future automated connection routines will make use of them. "tags" are applicable to any interface and can also be used on federates. - **`subscriptions`** - These are lists of the values being sent to and from the given federate. + - `key` - This string identifies the federation-unique value that this federate wishes to receive. If `global` has been set to `false` in the `publications` JSON configuration file, the name of the value is formatted as `/`. Both of these strings can be found in the publishing federate's JSON configuration file as the `name` and `key` strings, respectively. If `global` is `true` the string is the publishing federate's `key` value. - `required` - The message being subscribed to must be provided by some other publisher in the federation. - `type` - Data type, such as integer, double, complex. - `units` - Same as with `publications`. - `global` - Applies to the `key`, same as with `publications`. + - `default` - set the default value to return if no publications have been received - `only_update_on_change` and `tolerance` - Subscriptions will only consider a new value received when that value has changed more than the delta specified by `tolerance`. +- **`inputs`** - These are lists of the values being sent to and from the given federate. + - `name` - the name of the input. + - `required` - The input must have a valid target + - `type` - Data type, such as integer, double, complex. + - `units` - Same as with `publications`. + - `global` - Applies to the `key`, same as with `publications`. + - `default` - set the default value to return if no publications have been received + - `target` - A key for a publication the input should receive, may be an array such as ["pub1","pub2","pub3"] + - `tags` - name and value pairs defining user tags for the interface + - `only_update_on_change` and `tolerance` - Inputs will only consider a new value received when that value has changed more than the delta specified by `tolerance`. + ## API Configuration Configuring the federate interface with the API is done internal to a user-written simulator. The specific API used will depend on the language the simulator is written in. Native APIs for HELICS are available in [C++](../../doxygen/index.md) and [C](../../references/api-reference/C_API.md). MATLAB, Java, Julia, Nim, and Python all support the C API calls (ex: `helicsFederateEnterExecutionMode()`). Python and Julia also have native APIs (see: [Python (PyHELICS)](https://python.helics.org/api/), [Julia](https://gmlc-tdc.github.io/HELICS.jl/latest/api/)) that wrap the C APIs to better support the conventions of their languages. The [API References](../../references/api-reference/index.md) page contains links to the APIs. diff --git a/src/helics/application_api/ValueFederate.cpp b/src/helics/application_api/ValueFederate.cpp index 1292a069d4..496e3bf3f8 100644 --- a/src/helics/application_api/ValueFederate.cpp +++ b/src/helics/application_api/ValueFederate.cpp @@ -292,6 +292,10 @@ void ValueFederate::registerValueInterfacesJson(const std::string& jsonString) subAct->addTarget(name); } } + auto defStr = fileops::getOrDefault(sub, "default", emptyStr); + if (!defStr.empty()) { + subAct->setDefault(defStr); + } loadOptions(this, sub, *subAct); } } @@ -312,7 +316,10 @@ void ValueFederate::registerValueInterfacesJson(const std::string& jsonString) inp = ®isterInput(name, type, units); } } - + auto defStr = fileops::getOrDefault(ipt, "default", emptyStr); + if (!defStr.empty()) { + inp->setDefault(defStr); + } loadOptions(this, ipt, *inp); } } @@ -386,7 +393,10 @@ void ValueFederate::registerValueInterfacesToml(const std::string& tomlString) id->addTarget(name); } } - + auto defStr = fileops::getOrDefault(sub, "default", emptyStr); + if (!defStr.empty()) { + id->setDefault(defStr); + } loadOptions(this, sub, *id); } } @@ -412,7 +422,10 @@ void ValueFederate::registerValueInterfacesToml(const std::string& tomlString) id = ®isterInput(name, type, units); } } - + auto defStr = fileops::getOrDefault(ipt, "default", emptyStr); + if (!defStr.empty()) { + id->setDefault(defStr); + } loadOptions(this, ipt, *id); } } diff --git a/tests/helics/application_api/ValueFederateAdditionalTests.cpp b/tests/helics/application_api/ValueFederateAdditionalTests.cpp index 2fa225297d..742b5cb9e5 100644 --- a/tests/helics/application_api/ValueFederateAdditionalTests.cpp +++ b/tests/helics/application_api/ValueFederateAdditionalTests.cpp @@ -632,6 +632,14 @@ TEST(valuefed_json_tests, file_loadb) EXPECT_EQ(vFed.getTag("description"), "fedb description"); EXPECT_EQ(vFed.getTag("version"), "27"); + + auto& sub1 = vFed.getInput(0); + vFed.enterInitializingMode(); + + auto dv = sub1.getDouble(); + EXPECT_DOUBLE_EQ(dv, 9.33); + dv = inp2.getDouble(); + EXPECT_DOUBLE_EQ(dv, 3.67); vFed.disconnect(); helics::BrokerFactory::terminateAllBrokers(); helics::CoreFactory::terminateAllCores(); @@ -662,8 +670,13 @@ TEST(valuefederate, toml_file_loadb) EXPECT_EQ(std::stod(dval), 0.7); } + auto& sub1 = vFed.getInput(0); vFed.enterExecutingMode(); + auto dv = sub1.getDouble(); + EXPECT_DOUBLE_EQ(dv, 9.33); + dv = inp2.getDouble(); + EXPECT_DOUBLE_EQ(dv, 3.67); EXPECT_EQ(vFed.getTag("description"), "fedb description"); EXPECT_EQ(vFed.getTag("version"), "27"); diff --git a/tests/helics/test_files/example_value_fed_testb.json b/tests/helics/test_files/example_value_fed_testb.json index bab791326c..3725d8d4b9 100644 --- a/tests/helics/test_files/example_value_fed_testb.json +++ b/tests/helics/test_files/example_value_fed_testb.json @@ -46,7 +46,8 @@ { "key": "pub1", // the key of the publication "connection_required": true, //set to true to make helics issue a warning if the publication is not found - "tolerance": 0.3 + "tolerance": 0.3, + "default": "9.33" }, { "key": "fedName/pub2", // the name of the publication to subscribe to @@ -63,6 +64,7 @@ "connection_required": true, "target": "pub1", "global": true, + "default": 3.67, "tags": [ { "name": "period", "value": "0.7" }, { "name": "description", "value": "a test input" } diff --git a/tests/helics/test_files/example_value_fed_testb.toml b/tests/helics/test_files/example_value_fed_testb.toml index 080ddb6c3f..f6f65218b0 100644 --- a/tests/helics/test_files/example_value_fed_testb.toml +++ b/tests/helics/test_files/example_value_fed_testb.toml @@ -12,13 +12,13 @@ period= 1.0 #the period with which federate may return time #set required to true to make helics issue a warning if the publication is not found #example of inline tables (be careful it falls under the most recent [section] or [[table]] subscriptions=[ -{key="pub1", connection_required=true}, +{key="pub1", connection_required=true, default=9.33}, # shortcut is a naming shortcut for the publication for later retrieval {key="valueFed_toml/pub2", alias="pubshortcut", info="this is an information string for use by the application"} ] inputs=[ -{key="ipt2", type="double",flags="connection_optional", target="pub1", global=true,tags=[{name="period",value=0.7},{name="description",value="a test input"}]} +{key="ipt2", type="double",flags="connection_optional", target="pub1",default="3.67", global=true,tags=[{name="period",value=0.7},{name="description",value="a test input"}]} ] #specify an input with a target #add some descriptive tags to a federate