ChimeraTK-DeviceAccess  03.18.00
LNMMathPlugin.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2 // SPDX-License-Identifier: LGPL-3.0-or-later
3 
4 #include "LNMMathPlugin.h"
5 
6 #include "BackendFactory.h"
10 #include "TransferElement.h"
11 
12 #include <ChimeraTK/cppext/finally.hpp>
13 
14 namespace ChimeraTK::LNMBackend {
15 
16  thread_local int64_t MathPlugin::_writeLockCounter = 0;
17 
18  /********************************************************************************************************************/
19 
21  const LNMBackendRegisterInfo& info, size_t pluginIndex, std::map<std::string, std::string> parameters)
22  : AccessorPlugin(info, pluginIndex), _parameters(std::move(parameters)) {
23  // extract parameters
24  if(_parameters.find("formula") == _parameters.end()) {
25  throw ChimeraTK::logic_error("LogicalNameMappingBackend MultiplierPlugin: Missing parameter 'formula'.");
26  }
27  _formula = _parameters.at("formula");
28  _parameters.erase("formula");
29  if(_parameters.find("enable_push_parameters") != _parameters.end()) {
30  _enablePushParameters = true;
31  _parameters.erase("enable_push_parameters");
32  }
33  }
34 
35  /********************************************************************************************************************/
36 
38  // Change data type to non-integral
41 
42  // Fix to unidirectional operation
43  if(_info.writeable && _info.readable) {
44  _info.readable = false;
45  }
46 
48 
49  if(!_isWrite) { // reading MathPlugin
52  "MathPlugin (reading) does not support push_parameters: " + _info.getRegisterName());
53  }
54  }
55  }
56 
57  /********************************************************************************************************************/
58 
59  void MathPlugin::openHook(const boost::shared_ptr<LogicalNameMappingBackend>& backend) {
60  // make sure backend catalogue is updated with target backend information
61  auto catalogue = backend->getRegisterCatalogue();
62 
63  // produce logic_error if MathPlugin has insufficient access rights to parameters
64  if(_isWrite && !_info.isWriteable()) {
65  throw ChimeraTK::logic_error("MathPlugin target not writeable:" + _info.name);
66  }
67  for(const auto& parpair : _parameters) {
68  auto r = catalogue.getRegister(parpair.second);
69 
70  if(!r.isReadable()) {
71  throw ChimeraTK::logic_error("MathPlugin parameter not readable:" + parpair.second);
72  }
73  }
74 
75  // we require that all values used in the formula need to be written after open, before we provide first result
76  {
77  std::unique_lock<std::recursive_mutex> lk(_writeMutex);
80  }
81  }
82 
83  /********************************************************************************************************************/
84 
85  void MathPlugin::postParsingHook(const boost::shared_ptr<const LogicalNameMappingBackend>& backend) {
86  // whether this plugin is write mode depends on catalogue of target device so we need to update catalogue
87  // note, some target devices (e.g. DOOCS backend) provide their catalogue only on open, so it's not final here.
88  auto catalogue = backend->getRegisterCatalogue();
89  if(_isWrite) {
90  // Write direction: check that we have only lnm defined variables as parameters
91  // Current push implementation (via LNMBackendVariableAccessor<UserType>::doPostWrite) is only for variables.
92  // Therefore, we agreed to disallow non-variables, even when push-feature not requested.
93  for(const auto& parpair : _parameters) {
94  std::string pname = RegisterPath(parpair.second); // conversion to RegisterPath and back adds leading '/'
95  if(backend->_variables.find(pname) == backend->_variables.end()) {
96  throw logic_error("no LNM variable defined for parameter " + pname);
97  }
98  // set up connections for push-enabled variables. It is important that we do this already before openHook,
99  // since RegisterAccessor to Variable can be requested earlier!
101  _hasPushParameter = true;
102  backend->_variables[pname].usingFormulas.insert(this);
103  }
104  }
106  throw ChimeraTK::logic_error("MathPlugin (writing) with push_parameters requested but there is no parameter!");
107  }
108  }
109  }
110 
111  /********************************************************************************************************************/
112 
113  boost::shared_ptr<MathPluginFormulaHelper> MathPlugin::getFormulaHelper(
114  boost::shared_ptr<LogicalNameMappingBackend> backend) {
115  // lock against concurrent creation
116  std::unique_lock<std::recursive_mutex> lk{_writeMutex};
117  auto p = _h.lock();
118  if(!p) {
119  if(!backend) {
120  return nullptr;
121  }
122  _creatingFormulaHelper = true;
123  p = boost::make_shared<MathPluginFormulaHelper>(this, backend);
124  _creatingFormulaHelper = false;
125  _h = p;
126  }
127  return p;
128  }
129 
130  /********************************************************************************************************************/
131 
133  auto paramDataValidity = ChimeraTK::DataValidity::ok;
134  for(auto& p : params) {
135  p.first->readLatest();
136  if(p.first->dataValidity() == ChimeraTK::DataValidity::faulty) {
137  // probably compiler optimize it automatically and assign it only once.
138  paramDataValidity = ChimeraTK::DataValidity::faulty;
139  }
140  }
141  return paramDataValidity;
142  }
143 
144  /********************************************************************************************************************/
145 
147  // Note: _target might be invalid until _mp->_mainValueWrittenAfterOpen == true
148 
149  try {
150  std::unique_lock<std::recursive_mutex> lk(_mp->_writeMutex);
151 
152  auto paramDataValidity = updateParameters();
153 
155  return;
156  }
157 
158  assert(_mp->_lastMainValue.size() == _target->getNumberOfSamples());
159 
160  computeResult(_mp->_lastMainValue, _target->accessChannel(0));
161  // pass validity to target and delegate preWrite
163  _target->setDataValidity(ChimeraTK::DataValidity::ok);
164  }
165  else {
166  _target->setDataValidity(ChimeraTK::DataValidity::faulty);
167  }
168 
169  // if versionNumber at target register is already greater, take it instead of supplied versionNumber
170  auto writeVs = std::max<ChimeraTK::VersionNumber>(versionNumber, _target->getVersionNumber());
171  _target->writeDestructively(writeVs);
172  }
173  catch(runtime_error& ex) {
174  // runtime_error from param.readLatest() or target->write()
175  // we could actually even ignore it, since we don't expect exceptions on param.readLatest(), and target->write()
176  // already puts backend into exception state.
177  _target->getExceptionBackend()->setException(ex.what());
178  }
179  }
180 
181  /********************************************************************************************************************/
182 
184 
185  /********************************************************************************************************************/
186 
188  closeHook();
189  }
190 
191  /********************************************************************************************************************/
192 
195  return true;
196  }
197 
198  for(const auto& acc : _accessorMap) {
199  // Version number check will notice whether valid data has been provided after open. This works for both push and
200  // poll, since the LNM variables always pass through the version number from the write operation to the read.
201  if(acc.second->getVersionNumber() <= _backend->getVersionOnOpen()) {
202  return false;
203  }
204  }
207  }
208 
209  /********************************************************************************************************************/
210 
211  template<typename UserType>
214 
215  MathPluginDecorator(boost::shared_ptr<LogicalNameMappingBackend>& backend,
216  const boost::shared_ptr<ChimeraTK::NDRegisterAccessor<double>>& target, MathPlugin* p);
217 
218  void doPreRead(TransferType type) override {
219  if(_p->_isWrite) {
220  throw ChimeraTK::logic_error("This register with MathPlugin enabled is not readable: " + _target->getName());
221  }
222  _target->preRead(type);
223  }
224 
225  // registers are either readable or writeable
226  [[nodiscard]] bool isReadable() const override { return !_p->_isWrite; }
227 
228  void doPostRead(TransferType type, bool hasNewData) override;
229 
230  void doPreWrite(TransferType type, VersionNumber versionNumber) override;
231 
232  void doPostWrite(TransferType type, VersionNumber versionNumber) override;
233 
236 
237  boost::shared_ptr<MathPluginFormulaHelper> _h;
239 
240  // If not all parameters have been updated in the plugin, all parts of the write
241  // transaction (preWrite, writeTransfer and postWrite) are not delegated to the target
242  bool _skipWriteDelegation{false};
243 
245 
246  void setExceptionBackend(boost::shared_ptr<DeviceBackend>) override;
247  };
248 
249  /********************************************************************************************************************/
250 
251  template<typename UserType>
252  MathPluginDecorator<UserType>::MathPluginDecorator(boost::shared_ptr<LogicalNameMappingBackend>& backend,
253  const boost::shared_ptr<ChimeraTK::NDRegisterAccessor<double>>& target, MathPlugin* p)
254  : ChimeraTK::NDRegisterAccessorDecorator<UserType, double>(target), _p(p) {
255  // 2D arrays are not yet supported
256  if(_target->getNumberOfChannels() != 1) {
258  "The LogicalNameMapper MathPlugin supports only scalar or 1D array registers. Register name: " +
259  this->getName());
260  }
261 
262  // Although this is a decorator we do not use the exceptions backend from the target because this decorator is
263  // given out by a backend
264  target->setExceptionBackend(backend);
265  this->_exceptionBackend = backend;
266 
267  _h = _p->getFormulaHelper(backend);
268  }
269 
270  /********************************************************************************************************************/
271 
272  template<typename UserType>
274  _target->postRead(type, hasNewData);
275  if(!hasNewData) return;
276 
277  auto paramDataValidity = _h->updateParameters();
278 
279  // evaluate the expression and store into application buffer
280  _h->computeResult(_target->accessChannel(0), buffer_2D[0]);
281 
282  // update version number and validity from target
283  this->_versionNumber = _target->getVersionNumber();
284  this->_dataValidity = _target->dataValidity();
285  if(paramDataValidity == ChimeraTK::DataValidity::faulty) {
286  this->_dataValidity = ChimeraTK::DataValidity::faulty;
287  }
288  }
289 
290  /********************************************************************************************************************/
291 
292  boost::shared_ptr<LogicalNameMappingBackend> MathPluginFormulaHelper::getBackend() {
293  return _backend;
294  }
295 
296  /********************************************************************************************************************/
297 
298  template<typename UserType>
300  if(!_p->_isWrite) {
301  throw ChimeraTK::logic_error("This register with MathPlugin enabled is not writeable: " + _target->getName());
302  }
303  // LNM backend
304  auto backend = _h->getBackend();
305  if(!backend->isOpen()) {
306  throw ChimeraTK::logic_error("LNM backend not opened!");
307  }
308  backend->checkActiveException();
309 
310  // The readLatest might throw an exception. In this case preWrite() is never delegated and we must not call the
311  // target's postWrite().
312  _skipWriteDelegation = true;
313 
314  auto paramDataValidity = _h->updateParameters();
315 
316  // convert from UserType to double - use the target accessor's buffer as a temporary buffer (this is a bit a hack,
317  // but it is safe to overwrite the buffer and we can avoid the need for an additional permanent buffer which might
318  // not even be used if the register is never written).
319  for(size_t k = 0; k < buffer_2D[0].size(); ++k) {
320  _target->accessData(0, k) = userTypeToNumeric<double>(buffer_2D[0][k]);
321  }
322 
323  // update last written data buffer for other threads if needed
324  if(_p->_hasPushParameter) {
325  // Accquire the lock and hold it until the transaction is completed in postWrite.
326  // This is safe because it is guaranteed by the framework that pre- and post actions are called in pairs.
327  // Do this before the first call to the target, which might create its own locks.
328  _p->_writeMutex.lock();
329  // preWrite() might be called multiple times before postWrite() is called. There are multiple conditions
330  // whether the writeMutex is locked (_hasPushParameters, _skipWriteDelegation, exceptions) so we count
331  // separately how many times the lock has been aquired, so we can release it the exact right amount of times.
332  ++(_p->_writeLockCounter);
333  _p->_lastMainValue = _target->accessChannel(0);
334  _p->_lastMainValidity = _target->dataValidity();
335  _p->_mainValueWrittenAfterOpen = true;
336 
337  if(!_h->checkAllParametersWritten()) {
338  return;
339  }
340  }
341 
342  // There either are only poll-type parameters, or all push-type parameters have been received.
343  // We are OK to go through with the transfer
344  _skipWriteDelegation = false;
345 
346  // evaluate the expression and store into target accessor
347  _h->computeResult(_target->accessChannel(0), _target->accessChannel(0));
348 
349  // pass validity to target and delegate preWrite
350  if(paramDataValidity == ChimeraTK::DataValidity::ok && this->_dataValidity == ChimeraTK::DataValidity::ok) {
351  _target->setDataValidity(ChimeraTK::DataValidity::ok);
352  }
353  else {
354  _target->setDataValidity(ChimeraTK::DataValidity::faulty);
355  }
356  // if versionNumber at target register is already greater, take it instead of supplied versionNumber
357  auto writeVs = std::max<ChimeraTK::VersionNumber>(versionNumber, _target->getVersionNumber());
358  _target->preWrite(type, writeVs);
359  }
360 
361  /********************************************************************************************************************/
362 
363  template<typename UserType>
365  if(_skipWriteDelegation) {
366  return false; // No data loss. Value has been stored in preWrite for the parameters thread.
367  }
368 
369  return _target->writeTransfer(versionNumber);
370  }
371 
372  /********************************************************************************************************************/
373 
374  template<typename UserType>
376  return doWriteTransfer(versionNumber);
377  }
378 
379  /********************************************************************************************************************/
380 
381  template<typename UserType>
383  // Make sure the mutex is released, even if the delegated postWrite kicks out with an exception.
384  // This has to happen at the very end, after all delegations, such that the target can release all its internal locks first.
385  auto _ = cppext::finally([&] {
386  if(_p->_writeLockCounter > 0) {
387  --(_p->_writeLockCounter);
388  _p->_writeMutex.unlock();
389  }
390  });
391 
392  if(_skipWriteDelegation && (this->_activeException != nullptr)) {
393  // Something has thrown before the target's preWrite was called. Re-throw it here.
394  // Do not unlock the mutex. It never has been locked.
395  std::rethrow_exception(this->_activeException);
396  }
397 
398  if(_skipWriteDelegation) {
399  return; // the trarget preWrite() has not been executed, so stop here
400  }
401 
402  // delegate to the target
403  _target->setActiveException(this->_activeException);
404  _target->postWrite(type, versionNumber);
405  // (the "finally" lambda releasing the lock is executed here latest)
406  } // namespace LNMBackend
407 
408  /********************************************************************************************************************/
409 
410  template<typename UserType>
411  void MathPluginDecorator<UserType>::setExceptionBackend(boost::shared_ptr<DeviceBackend> exceptionBackend) {
412  this->_exceptionBackend = exceptionBackend;
413  _target->setExceptionBackend(exceptionBackend);
414  _h->setExceptionBackend(exceptionBackend);
415  }
416 
417  /********************************************************************************************************************/
418 
419  void MathPluginFormulaHelper::setExceptionBackend(boost::shared_ptr<DeviceBackend> exceptionBackend) {
420  for(auto& p : params) {
421  p.first->setExceptionBackend(exceptionBackend);
422  }
423  }
424 
425  /********************************************************************************************************************/
426 
427  template<typename UserType, typename TargetType>
428  boost::shared_ptr<NDRegisterAccessor<UserType>> MathPlugin::decorateAccessor(
429  boost::shared_ptr<LogicalNameMappingBackend>& backend, boost::shared_ptr<NDRegisterAccessor<TargetType>>& target,
430  const UndecoratedParams&) {
431  if constexpr(std::is_same_v<TargetType, double>) {
432  return boost::make_shared<MathPluginDecorator<UserType>>(backend, target, this);
433  }
434  else {
435  // this code branch is compiled because of mpl for loop over types, but must never run
436  assert(false);
437  return {};
438  }
439  }
440 
441  /********************************************************************************************************************/
442 
444  MathPlugin* p, const boost::shared_ptr<LogicalNameMappingBackend>& backend)
445  : _backend(backend), _mp(p) {
446  auto* info = _mp->info();
447  auto length = info->length;
448 
449  _target = backend->getRegisterAccessor_impl<double>(info->getRegisterName(), 0, 0, {}, _mp->_pluginIndex + 1);
450 
451  for(const auto& parpair : _mp->_parameters) {
452  // Even push-type parameters should not be obtained with wait_for_new_data, since the variable accessor will
453  // trigger the math plugin update in its postWrite in that case. Using wait_for_new_data here would leave
454  // exceptions in the queues across recovery which would bring the backend into the exception state again.
455  auto acc = backend->getRegisterAccessor<double>(parpair.second, 0, 0, {});
456  if(acc->getNumberOfChannels() != 1) {
458  "The LogicalNameMapper MathPlugin supports only scalar or 1D array registers. Register name: '" +
459  info->name + "', parameter name: '" + parpair.first + "'");
460  }
461  _accessorMap[parpair.first] = acc;
462  }
463  if(_mp->_hasPushParameter) {
464  _mp->_lastMainValue.resize(length);
465  }
466 
467  // compile formula
469  varName = info->name;
470  }
471 
472  /********************************************************************************************************************/
473 
474  void MathPluginFormulaHelper::compileFormula(const std::string& formula,
475 
476  const std::map<std::string, boost::shared_ptr<ChimeraTK::NDRegisterAccessor<double>>>& parameters,
477  size_t nElements) {
478  // create exprtk parser
479  exprtk::parser<double> parser;
480 
481  // add basic constants like pi
482  symbols.add_constants();
483 
484  // Add vector manipulation functions
485  symbols.add_package(vecOpsPkg);
486 
487  // Create vector view for the value and add it to the symbol table. We need to use a vector view instead of adding
488  // the buffer directly as a vector, since our buffers might be swapped and hence the address of the data can
489  // change. The pointer used for the view is for now to a temporary vector and will become invalid once this
490  // function returns. This is acceptable, since before using the view the pointer will be updated to the right
491  // buffer. Using a nullptr instead of the temporary buffer does not work, as the buffer seems to be accessible
492  // during compilation of the formula.
493  std::vector<double> temp(nElements);
494  valueView = std::make_unique<exprtk::vector_view<double>>(exprtk::make_vector_view(temp, nElements));
495  symbols.add_vector("x", *valueView);
496 
497  // iterate parameters, add all but 'formula' parameter as a variable.
498  for(const auto& parpair : parameters) {
499  if(parpair.first == "formula") continue;
500  const auto& acc = parpair.second;
501  acc->setExceptionBackend(_backend);
502  if(acc->getNumberOfChannels() != 1) {
504  "The LogicalNameMapper MathPlugin supports only scalar or 1D array registers. Register name: '" + varName +
505  "', parameter name: '" + parpair.first + "'");
506  }
507  auto view = std::make_unique<exprtk::vector_view<double>>(
508  exprtk::make_vector_view(acc->accessChannel(0), acc->getNumberOfSamples()));
509  symbols.add_vector(parpair.first, *view);
510  params[acc] = std::move(view);
511  }
512 
513  // compile the expression
514  expression.register_symbol_table(symbols);
515  bool success = parser.compile(formula, expression);
516  if(!success) {
517  throw ChimeraTK::logic_error("LogicalNameMapping MathPlugin for register '" + varName +
518  "': failed to compile expression '" + formula + "': " + parser.error());
519  }
520  }
521 
522  /********************************************************************************************************************/
523 
524  template<typename T>
525  void MathPluginFormulaHelper::computeResult(std::vector<double>& x, std::vector<T>& resultBuffer) {
526  // inform the value view of the new data pointer - the buffer might have been swapped
527  valueView->rebase(x.data());
528 
529  // update parameter buffers
530  for(auto& p : params) {
531  p.second->rebase(p.first->accessChannel(0).data());
532  }
533 
534  // evaluate the expression, obtain the result in a way so it also works when using the return statement
535  double valueWhenNotUsingReturn = expression.value();
536  exprtk::results_context<double> results = expression.results();
537 
538  // extract result depending on how it was returned
539  if(results.count() == 0) {
540  // if results.count() is 0, the return statement presumably has not been used
541  if(resultBuffer.size() != 1) {
542  throw ChimeraTK::logic_error("LogicalNameMapping MathPlugin for register '" + varName +
543  "': The expression returns a scalar but " + std::to_string(resultBuffer.size()) + " expected.");
544  }
545  resultBuffer[0] = numericToUserType<T>(valueWhenNotUsingReturn);
546  }
547  else if(results.count() == 1) {
548  // return statement has been used to return exactly one value (note: this value might be an array)
549  exprtk::type_store<double> result = results[0];
550 
551  // make sure we got a numeric result
552  if(result.type != exprtk::type_store<double>::e_scalar && result.type != exprtk::type_store<double>::e_vector) {
553  throw ChimeraTK::logic_error("LogicalNameMapping MathPlugin for register '" + varName +
554  "': The expression did not return a numeric result.");
555  }
556 
557  // create vector view and check that its size matches
558  exprtk::type_store<double>::type_view<double> view(result);
559  if(view.size() != resultBuffer.size()) {
560  throw ChimeraTK::logic_error("LogicalNameMapping MathPlugin for register '" + varName +
561  "': The expression returns " + std::to_string(view.size()) + " elements but " +
562  std::to_string(resultBuffer.size()) + " expected.");
563  }
564 
565  // convert and copy data into target buffer
566  for(size_t k = 0; k < view.size(); ++k) {
567  resultBuffer[k] = numericToUserType<T>(view[k]);
568  }
569  }
570  else {
571  // multiple results in return statement are unexpected
572  throw ChimeraTK::logic_error("LogicalNameMapping MathPlugin for register '" + varName +
573  "': The expression returned " + std::to_string(results.count()) + " results, expect exactly one result.");
574  }
575  }
576 
577 } // namespace ChimeraTK::LNMBackend
LNMMathPlugin.h
ChimeraTK::LNMBackend::MathPluginDecorator::setExceptionBackend
void setExceptionBackend(boost::shared_ptr< DeviceBackend >) override
Definition: LNMMathPlugin.cc:411
ChimeraTK::runtime_error::what
const char * what() const noexcept override
Return the message describing what exactly went wrong.
Definition: Exception.cpp:14
ChimeraTK::LNMBackend::MathPluginFormulaHelper::updateParameters
ChimeraTK::DataValidity updateParameters()
Definition: LNMMathPlugin.cc:132
ChimeraTK::LNMBackend::MathPluginFormulaHelper::checkAllParametersWritten
bool checkAllParametersWritten()
Definition: LNMMathPlugin.cc:193
ChimeraTK::LNMBackend::MathPluginFormulaHelper::computeResult
void computeResult(std::vector< double > &x, std::vector< T > &resultBuffer)
Definition: LNMMathPlugin.cc:525
ChimeraTK::LNMBackend::MathPluginDecorator
Definition: LNMMathPlugin.cc:212
ChimeraTK::LNMBackend::MathPlugin::_formula
std::string _formula
Definition: LNMMathPlugin.h:42
ChimeraTK::AccessMode::raw
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
ChimeraTK::LNMBackendRegisterInfo::getRegisterName
RegisterPath getRegisterName() const override
Return full path name of the register (including modules)
Definition: LNMBackendRegisterInfo.h:32
ChimeraTK::LNMBackend::MathPlugin::_parameters
std::map< std::string, std::string > _parameters
Definition: LNMMathPlugin.h:41
ChimeraTK::DataValidity::faulty
@ faulty
The data is considered valid.
ChimeraTK::LNMBackend::MathPluginFormulaHelper::_mp
MathPlugin * _mp
Definition: LNMMathPluginFormulaHelper.h:61
ChimeraTK::LNMBackend::AccessorPlugin
Base class for plugins that modify the behaviour of accessors in the logical name mapping backend.
Definition: LNMAccessorPlugin.h:104
ChimeraTK::LNMBackend::MathPluginDecorator::doPreRead
void doPreRead(TransferType type) override
Definition: LNMMathPlugin.cc:218
ChimeraTK::LNMBackend::MathPlugin::doRegisterInfoUpdate
void doRegisterInfoUpdate() override
Implementation of the plugin specific register information update.
Definition: LNMMathPlugin.cc:37
ChimeraTK::LNMBackend
Definition: LNMMathPluginFormulaHelper.h:16
TransferElement.h
ChimeraTK::LNMBackend::MathPlugin::_allParametersWrittenAfterOpen
bool _allParametersWrittenAfterOpen
Definition: LNMMathPlugin.h:56
ChimeraTK::LNMBackend::MathPlugin
Math Plugin: Apply mathematical formula to register's data.
Definition: LNMMathPlugin.h:17
ChimeraTK::LNMBackend::MathPluginFormulaHelper::MathPluginFormulaHelper
MathPluginFormulaHelper(MathPlugin *p, const boost::shared_ptr< LogicalNameMappingBackend > &backend)
Definition: LNMMathPlugin.cc:443
ChimeraTK::AccessModeFlags::remove
void remove(AccessMode flag)
Remove the given flag from the set.
Definition: AccessMode.cc:56
ChimeraTK::LNMBackend::MathPlugin::decorateAccessor
boost::shared_ptr< NDRegisterAccessor< UserType > > decorateAccessor(boost::shared_ptr< LogicalNameMappingBackend > &backend, boost::shared_ptr< NDRegisterAccessor< TargetType >> &target, const UndecoratedParams &accessorParams)
Definition: LNMMathPlugin.cc:428
ChimeraTK::LNMBackend::MathPluginFormulaHelper::symbols
exprtk::symbol_table< double > symbols
Definition: LNMMathPluginFormulaHelper.h:52
ChimeraTK::LNMBackendRegisterInfo::name
RegisterPath name
Name of the registrer.
Definition: LNMBackendRegisterInfo.h:47
ChimeraTK::LNMBackend::MathPlugin::_hasPushParameter
bool _hasPushParameter
Definition: LNMMathPlugin.h:44
ChimeraTK::LNMBackend::MathPluginDecorator::_h
boost::shared_ptr< MathPluginFormulaHelper > _h
Definition: LNMMathPlugin.cc:237
ChimeraTK::LNMBackend::MathPluginFormulaHelper::valueView
std::unique_ptr< exprtk::vector_view< double > > valueView
Definition: LNMMathPluginFormulaHelper.h:54
ChimeraTK::runtime_error
Exception thrown when a runtime error has occured.
Definition: Exception.h:18
LNMMathPluginFormulaHelper.h
NDRegisterAccessorDecorator.h
ChimeraTK::LNMBackend::MathPluginDecorator::doWriteTransferDestructively
bool doWriteTransferDestructively(ChimeraTK::VersionNumber) override
Definition: LNMMathPlugin.cc:375
ChimeraTK::LNMBackend::UndecoratedParams
Helper struct to hold extra parameters needed by some plugins, used in decorateAccessor()
Definition: LNMAccessorPlugin.h:13
ChimeraTK::LNMBackend::MathPluginFormulaHelper::getBackend
boost::shared_ptr< LogicalNameMappingBackend > getBackend()
Definition: LNMMathPlugin.cc:292
ChimeraTK::LNMBackendRegisterInfo::writeable
bool writeable
Flag if the register is writeable.
Definition: LNMBackendRegisterInfo.h:103
ChimeraTK::DataDescriptor
Class describing the actual payload data format of a register in an abstract manner.
Definition: DataDescriptor.h:19
ChimeraTK::LNMBackend::MathPluginDecorator::isReadable
bool isReadable() const override
Definition: LNMMathPlugin.cc:226
ChimeraTK::LNMBackend::MathPlugin::closeHook
void closeHook() override
Hook called when the backend is closed, at the beginning of the close() function when the device is s...
Definition: LNMMathPlugin.cc:183
ChimeraTK::LNMBackend::MathPluginFormulaHelper::varName
std::string varName
Definition: LNMMathPluginFormulaHelper.h:50
ChimeraTK::LNMBackend::MathPlugin::getFormulaHelper
boost::shared_ptr< MathPluginFormulaHelper > getFormulaHelper(boost::shared_ptr< LogicalNameMappingBackend > backend)
if not yet existing, creates the instance and returns it if already existing, backend ptr may be empt...
Definition: LNMMathPlugin.cc:113
ChimeraTK::LNMBackend::MathPluginFormulaHelper::updateResult
void updateResult(ChimeraTK::VersionNumber versionNumber)
Definition: LNMMathPlugin.cc:146
ChimeraTK::LNMBackend::MathPlugin::_creatingFormulaHelper
bool _creatingFormulaHelper
Definition: LNMMathPlugin.h:61
ChimeraTK::LNMBackend::MathPluginFormulaHelper::vecOpsPkg
exprtk::rtl::vecops::package< double > vecOpsPkg
Definition: LNMMathPluginFormulaHelper.h:53
ChimeraTK::DataValidity::ok
@ ok
ChimeraTK::DataValidity
DataValidity
The current state of the data.
Definition: TransferElement.h:41
ChimeraTK::LNMBackend::MathPlugin::_writeLockCounter
static thread_local int64_t _writeLockCounter
Definition: LNMMathPlugin.h:59
ChimeraTK::LNMBackendRegisterInfo
RegisterInfo structure for the LogicalNameMappingBackend.
Definition: LNMBackendRegisterInfo.h:22
ChimeraTK::LNMBackend::MathPlugin::info
LNMBackendRegisterInfo * info()
Definition: LNMMathPlugin.h:37
ChimeraTK::LNMBackend::AccessorPluginBase::_info
LNMBackendRegisterInfo _info
RegisterInfo describing the the target register for which this plugin instance should work.
Definition: LNMAccessorPlugin.h:93
ChimeraTK::LNMBackend::MathPluginDecorator::doPostWrite
void doPostWrite(TransferType type, VersionNumber versionNumber) override
Definition: LNMMathPlugin.cc:382
ChimeraTK::LNMBackend::MathPluginFormulaHelper::expression
exprtk::expression< double > expression
Definition: LNMMathPluginFormulaHelper.h:51
ChimeraTK::LNMBackend::MathPluginFormulaHelper::compileFormula
void compileFormula(const std::string &formula, const std::map< std::string, boost::shared_ptr< ChimeraTK::NDRegisterAccessor< double >>> &parameters, size_t nElements)
Definition: LNMMathPlugin.cc:474
ChimeraTK::LNMBackend::MathPlugin::_lastMainValue
std::vector< double > _lastMainValue
Definition: LNMMathPlugin.h:57
ChimeraTK::LNMBackend::MathPluginDecorator::doWriteTransfer
bool doWriteTransfer(ChimeraTK::VersionNumber) override
Definition: LNMMathPlugin.cc:364
ChimeraTK::TransferType
TransferType
Used to indicate the applicable operation on a Transferelement.
Definition: TransferElement.h:51
ChimeraTK::LNMBackend::MathPlugin::_writeMutex
std::recursive_mutex _writeMutex
Definition: LNMMathPlugin.h:54
ChimeraTK::LNMBackend::MathPluginFormulaHelper::_target
boost::shared_ptr< NDRegisterAccessor< double > > _target
Definition: LNMMathPluginFormulaHelper.h:58
ChimeraTK::DataType
A class to describe which of the supported data types is used.
Definition: SupportedUserTypes.h:599
ChimeraTK::LNMBackend::MathPluginDecorator::doPreWrite
void doPreWrite(TransferType type, VersionNumber versionNumber) override
Definition: LNMMathPlugin.cc:299
ChimeraTK::LNMBackend::MathPlugin::_isWrite
bool _isWrite
Definition: LNMMathPlugin.h:39
ChimeraTK::LNMBackend::MathPlugin::MathPlugin
MathPlugin(const LNMBackendRegisterInfo &info, size_t pluginIndex, std::map< std::string, std::string > parameters)
Definition: LNMMathPlugin.cc:20
ChimeraTK::NDRegisterAccessorDecorator
Base class for decorators of the NDRegisterAccessor.
Definition: NDRegisterAccessorDecorator.h:120
ChimeraTK::LNMBackendRegisterInfo::_dataDescriptor
DataDescriptor _dataDescriptor
Definition: LNMBackendRegisterInfo.h:111
ChimeraTK::LNMBackend::MathPluginFormulaHelper::setExceptionBackend
void setExceptionBackend(boost::shared_ptr< DeviceBackend > exceptionBackend)
Definition: LNMMathPlugin.cc:419
ChimeraTK::LNMBackend::MathPlugin::_lastMainValidity
ChimeraTK::DataValidity _lastMainValidity
Definition: LNMMathPlugin.h:58
ChimeraTK::LNMBackend::MathPluginFormulaHelper::_accessorMap
std::map< std::string, boost::shared_ptr< NDRegisterAccessor< double > > > _accessorMap
Definition: LNMMathPluginFormulaHelper.h:63
ChimeraTK::RegisterPath
Class to store a register path name.
Definition: RegisterPath.h:16
ChimeraTK::LNMBackend::MathPluginDecorator::MathPluginDecorator
MathPluginDecorator(boost::shared_ptr< LogicalNameMappingBackend > &backend, const boost::shared_ptr< ChimeraTK::NDRegisterAccessor< double >> &target, MathPlugin *p)
Definition: LNMMathPlugin.cc:252
BackendFactory.h
ChimeraTK::LNMBackend::MathPlugin::openHook
void openHook(const boost::shared_ptr< LogicalNameMappingBackend > &backend) override
Hook called when the backend is opened, at the end of the open() function after all backend work has ...
Definition: LNMMathPlugin.cc:59
ChimeraTK::LNMBackendRegisterInfo::supportedFlags
AccessModeFlags supportedFlags
Supported AccessMode flags.
Definition: LNMBackendRegisterInfo.h:106
ChimeraTK::LNMBackend::MathPluginFormulaHelper::params
std::map< boost::shared_ptr< NDRegisterAccessor< double > >, std::unique_ptr< exprtk::vector_view< double > > > params
Definition: LNMMathPluginFormulaHelper.h:55
ChimeraTK::VersionNumber
Class for generating and holding version numbers without exposing a numeric representation.
Definition: VersionNumber.h:23
ChimeraTK::LNMBackend::MathPlugin::exceptionHook
void exceptionHook() override
Hook called when an exception is reported to the the backend via setException(), after the backend ha...
Definition: LNMMathPlugin.cc:187
ChimeraTK::LNMBackendRegisterInfo::length
unsigned int length
The length of the range (i.e.
Definition: LNMBackendRegisterInfo.h:62
ChimeraTK::LNMBackend::MathPluginDecorator::doPostRead
void doPostRead(TransferType type, bool hasNewData) override
Definition: LNMMathPlugin.cc:273
ChimeraTK::LNMBackend::MathPlugin::_enablePushParameters
bool _enablePushParameters
Definition: LNMMathPlugin.h:43
ChimeraTK::LNMBackend::AccessorPlugin::_pluginIndex
size_t _pluginIndex
Index of the plugin instance within the stack of plugins on a particular register.
Definition: LNMAccessorPlugin.h:155
LNMBackendRegisterInfo.h
ChimeraTK::LNMBackend::MathPluginFormulaHelper::_backend
boost::shared_ptr< LogicalNameMappingBackend > _backend
Definition: LNMMathPluginFormulaHelper.h:57
ChimeraTK::LNMBackend::MathPluginDecorator::_skipWriteDelegation
bool _skipWriteDelegation
Definition: LNMMathPlugin.cc:242
ChimeraTK
Definition: DummyBackend.h:16
ChimeraTK::to_string
std::string to_string(Boolean &value)
Definition: SupportedUserTypes.h:59
ChimeraTK::LNMBackend::MathPlugin::_mainValueWrittenAfterOpen
bool _mainValueWrittenAfterOpen
Definition: LNMMathPlugin.h:55
ChimeraTK::LNMBackend::MathPlugin::postParsingHook
void postParsingHook(const boost::shared_ptr< const LogicalNameMappingBackend > &backend) override
Definition: LNMMathPlugin.cc:85
ChimeraTK::NDRegisterAccessor
N-dimensional register accessor.
Definition: ForwardDeclarations.h:17
ChimeraTK::LNMBackendRegisterInfo::isWriteable
bool isWriteable() const override
Return whether the register is writeable.
Definition: LNMBackendRegisterInfo.h:42
ChimeraTK::LNMBackendRegisterInfo::readable
bool readable
Flag if the register is readable.
Definition: LNMBackendRegisterInfo.h:99
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51
ChimeraTK::LNMBackend::MathPluginDecorator::_p
MathPlugin * _p
Definition: LNMMathPlugin.cc:238