helics  3.5.2
Inputs.hpp
1 /*
2 Copyright (c) 2017-2024,
3 Battelle Memorial Institute; Lawrence Livermore National Security, LLC; Alliance for Sustainable
4 Energy, LLC. See the top-level NOTICE for additional details. All rights reserved.
5 SPDX-License-Identifier: BSD-3-Clause
6 */
7 #pragma once
8 
9 #include "Federate.hpp"
10 #include "HelicsPrimaryTypes.hpp"
11 #include "helicsTypes.hpp"
12 
13 #include <memory>
14 #include <string>
15 #include <utility>
16 #include <vector>
17 
18 namespace units {
19 class precise_unit;
20 } // namespace units
21 
22 namespace helics {
23 
24 class ValueFederate;
25 enum MultiInputHandlingMethod : uint16_t {
27  VECTORIZE_OPERATION = HELICS_MULTI_INPUT_VECTORIZE_OPERATION,
28  AND_OPERATION = HELICS_MULTI_INPUT_AND_OPERATION,
29  OR_OPERATION = HELICS_MULTI_INPUT_OR_OPERATION,
30  SUM_OPERATION = HELICS_MULTI_INPUT_SUM_OPERATION,
31  DIFF_OPERATION = HELICS_MULTI_INPUT_DIFF_OPERATION,
32  MAX_OPERATION = HELICS_MULTI_INPUT_MAX_OPERATION,
33  MIN_OPERATION = HELICS_MULTI_INPUT_MIN_OPERATION,
34  AVERAGE_OPERATION = HELICS_MULTI_INPUT_AVERAGE_OPERATION
35 };
36 
38 class HELICS_CXX_EXPORT Input: public Interface {
39  protected:
40  ValueFederate* fed = nullptr;
41  private:
42  int referenceIndex{-1};
43  void* dataReference{nullptr};
44 
45  DataType targetType{DataType::HELICS_UNKNOWN};
46  DataType injectionType{
47  DataType::HELICS_UNKNOWN};
48  bool changeDetectionEnabled{false};
49  bool hasUpdate{false};
50  bool disableAssign{false};
51  bool useThreshold{false};
52  bool multiUnits{false};
53  MultiInputHandlingMethod inputVectorOp{
54  MultiInputHandlingMethod::NO_OP};
55  int32_t prevInputCount{0};
56  size_t customTypeHash{0U};
57  defV lastValue{invalidDouble};
58  std::shared_ptr<units::precise_unit> outputUnits;
59  std::shared_ptr<units::precise_unit> inputUnits;
60  std::vector<std::pair<DataType, std::shared_ptr<units::precise_unit>>>
61  sourceTypes;
62  std::string givenTarget;
63  double delta{-1.0};
64  double threshold{0.0};
65  // this needs to match the defV type
66  std::variant<std::function<void(const double&, Time)>,
67  std::function<void(const int64_t&, Time)>,
68  std::function<void(const std::string&, Time)>,
69  std::function<void(const std::complex<double>&, Time)>,
70  std::function<void(const std::vector<double>&, Time)>,
71  std::function<void(const std::vector<std::complex<double>>&, Time)>,
72  std::function<void(const NamedPoint&, Time)>,
73  std::function<void(const bool&, Time)>,
74  std::function<void(const Time&, Time)>>
75  value_callback;
76  public:
78  Input() = default;
80  Input(ValueFederate* valueFed,
81  InterfaceHandle id,
82  std::string_view actName,
83  std::string_view unitsOut = {});
84 
85  Input(ValueFederate* valueFed,
86  std::string_view key,
87  std::string_view defaultType = "def",
88  std::string_view units = {});
89 
90  template<class FedPtr>
91  Input(FedPtr& valueFed,
92  std::string_view key,
93  std::string_view defaultType = "def",
94  std::string_view units = {}): Input(std::addressof(*valueFed), key, defaultType, units)
95  {
96  static_assert(
97  std::is_base_of<ValueFederate, std::remove_reference_t<decltype(*valueFed)>>::value,
98  "first argument must be a pointer to a ValueFederate");
99  }
100 
101  Input(InterfaceVisibility locality,
102  ValueFederate* valueFed,
103  std::string_view key,
104  std::string_view defaultType = "def",
105  std::string_view units = {});
106 
107  template<class FedPtr>
108  Input(InterfaceVisibility locality,
109  FedPtr& valueFed,
110  std::string_view key,
111  std::string_view defaultType = "def",
112  std::string_view units = {}):
113  Input(locality, std::addressof(*valueFed), key, defaultType, units)
114  {
115  static_assert(
116  std::is_base_of<ValueFederate, std::remove_reference_t<decltype(*valueFed)>>::value,
117  "first argument must be a pointer to a ValueFederate");
118  }
119 
120  Input(ValueFederate* valueFed,
121  std::string_view key,
122  DataType defType,
123  std::string_view units = {}): Input(valueFed, key, typeNameStringRef(defType), units)
124  {
125  }
126 
127  template<class FedPtr>
128  Input(FedPtr& valueFed, std::string_view key, DataType defType, std::string_view units = {}):
129  Input(valueFed, key, typeNameStringRef(defType), units)
130  {
131  }
132 
133  Input(InterfaceVisibility locality,
134  ValueFederate* valueFed,
135  std::string_view key,
136  std::string_view units = {}): Input(locality, valueFed, key, "def", units)
137  {
138  }
139 
140  template<class FedPtr>
141  Input(InterfaceVisibility locality,
142  FedPtr& valueFed,
143  std::string_view key,
144  std::string_view units = {}): Input(locality, valueFed, key, "def", units)
145  {
146  }
147 
148  Input(InterfaceVisibility locality,
149  ValueFederate* valueFed,
150  std::string_view key,
151  DataType defType,
152  std::string_view units = {}):
153  Input(locality, valueFed, key, typeNameStringRef(defType), units)
154  {
155  }
156 
157  template<class FedPtr>
158  Input(InterfaceVisibility locality,
159  FedPtr& valueFed,
160  std::string_view key,
161  DataType defType,
162  std::string_view units = {}):
163  Input(locality, valueFed, key, typeNameStringRef(defType), units)
164  {
165  }
166 
170  Time getLastUpdate() const;
171 
177  void registerNotificationCallback(std::function<void(Time)> callback);
178 
180  const std::string& getPublicationType() const
181  {
182  return ((injectionType == DataType::HELICS_UNKNOWN) ||
183  (injectionType == DataType::HELICS_CUSTOM)) ?
184  getInjectionType() :
185  typeNameStringRef(injectionType);
186  }
188  const std::string& getType() const { return getExtractionType(); }
190  const std::string& getUnits() const { return getExtractionUnits(); }
192  void addPublication(std::string_view target);
194  void addTarget(std::string_view target) { addPublication(target); }
200  bool checkUpdate(bool assumeUpdate = false);
201 
203  void clearUpdate();
206  bool isUpdated();
214  bool isUpdated() const;
215 
216  virtual void setOption(int32_t option, int32_t value = 1) override;
217  virtual int32_t getOption(int32_t option) const override;
223  template<class X>
224  void setInputNotificationCallback(std::function<void(const X&, Time)> callback)
225  {
226  static_assert(
227  helicsType<X>() != DataType::HELICS_CUSTOM,
228  "callback type must be a primary helics type one of \"double, int64_t, named_point, bool, Time "
229  "std::vector<double>, std::vector<std::complex<double>>, std::complex<double>\"");
230  value_callback = std::move(callback);
231  registerCallback();
232  }
233 
234  private:
235  template<class X>
236  void setDefault_impl(std::integral_constant<int, 0> /*V*/, X&& val)
237  {
239  lastValue = make_valid(std::forward<X>(val));
240  }
241 
242  template<class X>
243  void setDefault_impl(std::integral_constant<int, 1> /*V*/, X&& val)
244  {
245  lastValue = make_valid(std::forward<X>(val));
246  }
247 
248  template<class X>
249  void setDefault_impl(std::integral_constant<int, 2> /*V*/, X&& val)
250  {
251  auto res = ValueConverter<remove_cv_ref<X>>::convert(std::forward<X>(val));
252  lastValue = std::string(res.to_string());
253  setDefaultBytes(res);
254  }
255 
257  void registerCallback();
258 
259  public:
262  template<class X>
263  void setDefault(X&& val)
264  {
265  setDefault_impl<X>(typeCategory<X>(), std::forward<X>(val));
266  }
267 
268  void setDefaultBytes(data_view val);
272  void setMinimumChange(double deltaV) noexcept
273  {
274  // this first check enables change detection if it was disabled via negative delta
275  if (delta < 0.0) {
276  changeDetectionEnabled = true;
277  }
278  delta = deltaV;
279  // the second checks if we should disable from negative delta
280  if (delta < 0.0) {
281  changeDetectionEnabled = false;
282  }
283  }
287  void enableChangeDetection(bool enabled = true) noexcept { changeDetectionEnabled = enabled; }
288 
289  private:
291  void handleCallback(Time time);
292  template<class X>
293  void getValue_impl(std::integral_constant<int, primaryType> /*V*/, X& out);
294 
296  void getValue_impl(std::integral_constant<int, primaryType> /*V*/, char& out)
297  {
298  out = getValueChar();
299  }
300 
302  void getValue_impl(std::integral_constant<int, convertibleType> /*V*/, char& out)
303  {
304  out = getValueChar();
305  }
306 
307  template<class X>
308  void getValue_impl(std::integral_constant<int, convertibleType> /*V*/, X& out)
309  {
310  std::conditional_t<std::is_integral<X>::value,
311  std::conditional_t<std::is_same<X, char>::value, char, int64_t>,
312  double>
313  gval;
314  getValue_impl(std::integral_constant<int, primaryType>(), gval);
315  out = static_cast<X>(gval);
316  }
317 
318  template<class X>
319  void getValue_impl(std::integral_constant<int, nonConvertibleType> /*V*/, X& out)
320  {
321  ValueConverter<X>::interpret(getBytes(), out);
322  }
323 
324  template<class X>
325  X getValue_impl(std::integral_constant<int, primaryType> /*V*/)
326  {
327  X val; // NOLINT
328  getValue_impl(std::integral_constant<int, primaryType>(), val);
329  return val;
330  }
331 
332  template<class X>
333  X getValue_impl(std::integral_constant<int, convertibleType> /*V*/)
334  {
335  std::conditional_t<std::is_integral<X>::value,
336  std::conditional_t<std::is_same<X, char>::value, char, int64_t>,
337  double>
338  gval;
339  getValue_impl(std::integral_constant<int, primaryType>(), gval);
340  return static_cast<X>(gval);
341  }
342 
343  template<class X>
344  X getValue_impl(std::integral_constant<int, nonConvertibleType> /*V*/)
345  {
346  return ValueConverter<X>::interpret(getBytes());
347  }
348 
349  public:
351  int getValue(double* data, int maxsize);
353  int getComplexValue(double* data, int maxsize);
355  int getValue(char* str, int maxsize);
359  template<class X>
360  void getValue(X& out)
361  {
362  getValue_impl<X>(typeCategory<X>(), out);
363  }
366  template<class X>
367  auto getValue()
368  {
369  return getValue_impl<remove_cv_ref<X>>(typeCategory<X>());
370  }
371 
372  template<class X>
373  const X& getValueRef();
375  double getDouble() { return getValue_impl<double>(std::integral_constant<int, primaryType>()); }
377  const std::string& getString() { return getValueRef<std::string>(); }
378 
380  data_view getBytes();
382  size_t getByteCount();
384  size_t getStringSize();
386  size_t getVectorSize();
387 
389  DataType getHelicsType() const { return targetType; }
390 
392  DataType getHelicsInjectionType() const { return injectionType; }
393 
394  MultiInputHandlingMethod getMultiInputMode() const { return inputVectorOp; }
395 
396  bool vectorDataProcess(const std::vector<std::shared_ptr<const SmallBuffer>>& dataV);
397 
398  const std::string& getTarget() const
399  {
400  return (!givenTarget.empty()) ? givenTarget : getSourceTargets();
401  }
402 
403  virtual const std::string& getDisplayName() const override
404  {
405  return (mName.empty()) ? getTarget() : getName();
406  }
407 
408  private:
410  void loadSourceInformation();
412  char getValueChar();
414  bool allowDirectFederateUpdate() const
415  {
416  return hasUpdate && !changeDetectionEnabled &&
417  inputVectorOp == MultiInputHandlingMethod::NO_OP;
418  }
419  data_view checkAndGetFedUpdate();
420  void forceCoreDataUpdate();
421  friend class ValueFederateManager;
422 };
423 
425 HELICS_CXX_EXPORT double
426  doubleExtractAndConvert(const data_view& dv,
427  const std::shared_ptr<units::precise_unit>& inputUnits,
428  const std::shared_ptr<units::precise_unit>& outputUnits);
429 
430 HELICS_CXX_EXPORT void
431  integerExtractAndConvert(defV& store,
432  const data_view& dv,
433  const std::shared_ptr<units::precise_unit>& inputUnits,
434  const std::shared_ptr<units::precise_unit>& outputUnits);
435 
436 template<class X>
437 void Input::getValue_impl(std::integral_constant<int, primaryType> /*V*/, X& out)
438 {
439  auto dv = checkAndGetFedUpdate();
440  if (!dv.empty()) {
441  if (injectionType == DataType::HELICS_UNKNOWN) {
442  loadSourceInformation();
443  }
444 
445  if (injectionType == helics::DataType::HELICS_DOUBLE) {
446  defV val = doubleExtractAndConvert(dv, inputUnits, outputUnits);
447  valueExtract(val, out);
448  } else if (injectionType == helics::DataType::HELICS_INT) {
449  defV val;
450  integerExtractAndConvert(val, dv, inputUnits, outputUnits);
451  valueExtract(val, out);
452  } else {
453  valueExtract(dv, injectionType, out);
454  }
455  if (changeDetectionEnabled) {
456  if (changeDetected(lastValue, out, delta)) {
457  lastValue = make_valid(out);
458  } else {
459  valueExtract(lastValue, out);
460  }
461  } else {
462  lastValue = make_valid(out);
463  }
464  } else {
465  valueExtract(lastValue, out);
466  }
467  hasUpdate = false;
468 }
469 
470 template<class X>
471 inline const X& getValueRefImpl(defV& val)
472 {
473  valueConvert(val, helicsType<X>());
474  return std::get<X>(val);
475 }
476 
477 template<>
478 inline const std::string& getValueRefImpl(defV& val)
479 {
480  // don't convert a named point to a string
481  if ((val.index() == named_point_loc)) {
482  return std::get<NamedPoint>(val).name;
483  }
484  valueConvert(val, DataType::HELICS_STRING);
485  return std::get<std::string>(val);
486 }
487 
488 HELICS_CXX_EXPORT bool checkForNeededCoreRetrieval(std::size_t currentIndex,
489  DataType injectionType,
490  DataType conversion);
491 
492 template<class X>
493 const X& Input::getValueRef()
494 {
495  static_assert(std::is_same<typeCategory<X>, std::integral_constant<int, primaryType>>::value,
496  "calling getValue By ref must be with a primary type");
497  auto dv = checkAndGetFedUpdate();
498  if (!dv.empty()) {
499  if (injectionType == DataType::HELICS_UNKNOWN) {
500  loadSourceInformation();
501  }
502 
503  if (changeDetectionEnabled) {
504  X out;
505  if (injectionType == helics::DataType::HELICS_DOUBLE) {
506  defV val = doubleExtractAndConvert(dv, inputUnits, outputUnits);
507  valueExtract(val, out);
508  } else if (injectionType == helics::DataType::HELICS_INT) {
509  defV val;
510  integerExtractAndConvert(val, dv, inputUnits, outputUnits);
511  valueExtract(val, out);
512  } else {
513  valueExtract(dv, injectionType, out);
514  }
515  if (changeDetected(lastValue, out, delta)) {
516  lastValue = make_valid(std::move(out));
517  }
518  } else {
519  valueExtract(dv, injectionType, lastValue);
520  }
521  } else {
522  if (checkForNeededCoreRetrieval(lastValue.index(),
523  injectionType,
524  helicsType<remove_cv_ref<X>>())) {
525  forceCoreDataUpdate();
526  }
527  }
528 
529  return getValueRefImpl<remove_cv_ref<X>>(lastValue);
530 }
531 } // namespace helics
naming a set of types that are interchangeable and recognizable inside the HELICS application API and...
Definition: Inputs.hpp:38
const std::string & getPublicationType() const
Definition: Inputs.hpp:180
void addTarget(std::string_view target)
Definition: Inputs.hpp:194
virtual const std::string & getDisplayName() const override
Definition: Inputs.hpp:403
void setMinimumChange(double deltaV) noexcept
Definition: Inputs.hpp:272
void setDefault(X &&val)
Definition: Inputs.hpp:263
const std::string & getUnits() const
Definition: Inputs.hpp:190
auto getValue()
Definition: Inputs.hpp:367
const std::string & getType() const
Definition: Inputs.hpp:188
void enableChangeDetection(bool enabled=true) noexcept
Definition: Inputs.hpp:287
void getValue(X &out)
Definition: Inputs.hpp:360
DataType getHelicsType() const
Definition: Inputs.hpp:389
Input()=default
DataType getHelicsInjectionType() const
Definition: Inputs.hpp:392
void setInputNotificationCallback(std::function< void(const X &, Time)> callback)
Definition: Inputs.hpp:224
const std::string & getString()
Definition: Inputs.hpp:377
double getDouble()
Definition: Inputs.hpp:375
Definition: LocalFederateId.hpp:65
Definition: application_api/Federate.hpp:875
static X interpret(const data_view &block)
Definition: ValueConverter.hpp:147
Definition: application_api/ValueFederate.hpp:28
Definition: data_view.hpp:22
@ HELICS_MULTI_INPUT_OR_OPERATION
Definition: helics_enums.h:329
@ HELICS_MULTI_INPUT_DIFF_OPERATION
Definition: helics_enums.h:334
@ HELICS_MULTI_INPUT_NO_OP
Definition: helics_enums.h:322
@ HELICS_MULTI_INPUT_MAX_OPERATION
Definition: helics_enums.h:336
@ HELICS_MULTI_INPUT_AND_OPERATION
Definition: helics_enums.h:326
@ HELICS_MULTI_INPUT_SUM_OPERATION
Definition: helics_enums.h:331
@ HELICS_MULTI_INPUT_VECTORIZE_OPERATION
Definition: helics_enums.h:324
@ HELICS_MULTI_INPUT_MIN_OPERATION
Definition: helics_enums.h:338
@ HELICS_MULTI_INPUT_AVERAGE_OPERATION
Definition: helics_enums.h:340
the main namespace for the helics co-simulation library User functions will be in the helics namespac...
Definition: AsyncFedCallInfo.hpp:14
constexpr DataType helicsType()
Definition: helicsTypes.hpp:378
DataType
Definition: helicsTypes.hpp:273
constexpr double invalidDouble
defined constant for an invalid value as a double
Definition: helicsTypes.hpp:499
const std::string & typeNameStringRef(DataType type)
Definition: helicsTypes.cpp:58
void valueExtract(const defV &data, std::string &val)
Definition: helicsPrimaryTypes.cpp:170
double doubleExtractAndConvert(const data_view &dv, const std::shared_ptr< units::precise_unit > &inputUnits, const std::shared_ptr< units::precise_unit > &outputUnits)
Definition: Inputs.cpp:775
int64_t make_valid(bool obj)
Definition: HelicsPrimaryTypes.hpp:68
InterfaceVisibility
Definition: helicsTypes.hpp:40
bool changeDetected(const defV &prevValue, const std::string &val, double)
Definition: helicsPrimaryTypes.cpp:16
std::conditional_t< helicsType< remove_cv_ref< X > >() !=DataType::HELICS_CUSTOM, std::integral_constant< int, primaryType >, std::conditional_t< isConvertableType< remove_cv_ref< X > >(), std::integral_constant< int, convertibleType >, std::integral_constant< int, nonConvertibleType > >> typeCategory
Definition: helicsTypes.hpp:553
TimeRepresentation< count_time< 9 > > Time
Definition: helicsTime.hpp:27
std::variant< double, int64_t, std::string, std::complex< double >, std::vector< double >, std::vector< std::complex< double > >, NamedPoint > defV
Definition: HelicsPrimaryTypes.hpp:37