5#include <ChimeraTK/SystemTags.h>
14 PriorityMode mode, std::unordered_set<std::string> tagsToAggregate,
15 const std::unordered_set<std::string>& outputTags, std::string warnMixedMessage)
16 :
ApplicationModule(owner,
".", description, outputTags), _output(this, name), _mode(mode),
17 _tagsToAggregate(std::move(tagsToAggregate)), _warnMixedMessage(std::move(warnMixedMessage)) {
21 throw ChimeraTK::logic_error(
22 "StatusAggregator: List of tagsToAggregate is currently limited to one tag (see #13256).");
39 std::set<std::string> inputPathsSet;
41 std::set<std::string> anotherStatusAgregatorInputSet;
43 std::map<std::string, std::string> statusToMessagePathsMap;
46 auto scanModel = [&](
auto proxy) {
49 auto checkTag = [&](
const auto& nodeOrProxy) ->
bool {
53 return std::ranges::all_of(
_tagsToAggregate, [&](
const auto& tagToAgregate) {
54 if(tagToAgregate.starts_with(
'!')) {
56 return nodeOrProxy.getTags().find(negateTag(tagToAgregate)) == nodeOrProxy.getTags().end();
59 return nodeOrProxy.getTags().find(tagToAgregate) != nodeOrProxy.getTags().end();
65 auto* staAggPtr =
dynamic_cast<StatusAggregator*
>(&proxy.getApplicationModule());
66 if(staAggPtr !=
nullptr) {
67 if(staAggPtr ==
this) {
76 inputPathsSet.insert(staAggPtr->_output._status.getModel().getFullyQualifiedPath());
78 statusToMessagePathsMap[staAggPtr->_output._status.getModel().getFullyQualifiedPath()] =
81 for(
auto& anotherStatusAgregatorInput : staAggPtr->_inputs) {
82 anotherStatusAgregatorInputSet.insert(
83 anotherStatusAgregatorInput._status.getModel().getFullyQualifiedPath());
96 auto tags = proxy.getTags();
104 if(tags.find(ChimeraTK::SystemTags::statusOutput) != tags.end()) {
106 if(!checkTag(proxy)) {
110 inputPathsSet.insert(proxy.getFullyQualifiedPath());
113 std::string fqn = proxy.getFullyQualifiedPath();
115 statusToMessagePathsMap[proxy.getFullyQualifiedPath()] = fqn +
"_message";
121 model.visit(scanModel, ChimeraTK::Model::keepApplicationModules || ChimeraTK::Model::keepProcessVariables,
122 ChimeraTK::Model::breadthFirstSearch, ChimeraTK::Model::keepOwnership);
124 for(
const auto& pathToBeRemoved : anotherStatusAgregatorInputSet) {
125 inputPathsSet.erase(pathToBeRemoved);
128 for(
const auto& pathToBeAggregated : inputPathsSet) {
130 this, pathToBeAggregated, pathToBeAggregated, std::unordered_set<std::string>{
tagInternalVars});
131 if(!statusToMessagePathsMap[pathToBeAggregated].empty()) {
132 _inputs.back().setMessageSource(statusToMessagePathsMap[pathToBeAggregated]);
140 using Status = StatusOutput::Status;
148 static_assert(int(Status::OK) == 0);
149 static_assert(int(Status::FAULT) == 1);
150 static_assert(int(Status::OFF) == 2);
151 static_assert(int(Status::WARNING) == 3);
153 constexpr auto priority_table = std::array{
155 std::array<int32_t, 4>{
162 std::array<int32_t, 4>{
169 std::array<int32_t, 4>{
176 std::array<int32_t, 4>{
184 return priority_table[int(
_mode)][int(status)];
205 std::map<TransferElementID, StatusWithMessageInput*> inputsMap;
207 inputsMap[x._status.getId()] = &x;
208 if(x.hasMessageSource) {
209 inputsMap[x._message.getId()] = &x;
216 StatusOutput::Status status{StatusOutput::Status::FAULT};
226 bool statusSet =
false;
229 bool hasInvalidInput{
false};
230 bool forceValid{
false};
232 for(
auto& inputPair :
_inputs) {
237 if(input.dataValidity() == DataValidity::faulty) {
238 hasInvalidInput =
true;
249 if(!statusSet || prio > statusPrio ||
250 (input == status && statusOrigin !=
nullptr &&
251 input.getVersionNumber() < statusOrigin->
_status.getVersionNumber())) {
253 statusOrigin = &inputPair;
257 else if(prio == -1) {
258 if(statusPrio == -1 && input != status) {
259 status = StatusOutput::Status::WARNING;
260 statusOrigin =
nullptr;
270 auto validity = (!hasInvalidInput || forceValid) ? DataValidity::ok : DataValidity::faulty;
279 assert(status == StatusOutput::Status::WARNING);
283 if(status != StatusOutput::Status::OK) {
285 auto msg = statusOrigin->getMessage();
295 auto change = rag.readAny();
296 auto f = inputsMap.find(change);
297 if(f != inputsMap.end()) {
298 auto* varPair = f->second;
299 if(!varPair->update(change)) {
305 if(change ==
_debug.getId()) {
307 myLog <<
"StatusAggregtor (";
316 myLog <<
"fw_warn_mixed";
323 <<
" debug info:" << std::endl;
324 for(
auto& inputPair :
_inputs) {
326 myLog << static_cast<VariableNetworkNode>(input).getQualifiedName() <<
" = " << input;
327 if(inputPair.hasMessageSource) {
329 << std::string(inputPair._message);
335 myLog <<
"debug info finished." << std::endl;
344 return DataValidity::ok;
Logger::StreamProxy logger(Logger::Severity severity)
Convenicene function to obtain a logger stream with the given Severity.
ChimeraTK::Model::ApplicationModuleProxy getModel()
Return the application model proxy representing this module.
void addTag(const std::string &tag)
Add a tag to all Application-type nodes inside this group.
void addTag(const std::string &tag)
Add a tag.
Model::ProcessVariableProxy getModel() const
std::string getFullyQualifiedPath() const
Return the fully qualified path.
std::string getQualifiedName() const override
Get the fully qualified name of the module instance, i.e.
EntityOwner * _owner
Owner of this instance.
ChimeraTK::ReadAnyGroup readAnyGroup()
Create a ChimeraTK::ReadAnyGroup for all readable variables in this Module.
Class describing a node of a variable network.
constexpr bool isApplicationModule(const PROPERTY_OR_PROXY &)
constexpr bool isVariable(const PROPERTY_OR_PROXY &)
InvalidityTracer application module.
constexpr auto explicitDataValidityTag
Special tag to designate that a node should not automatically take over DataValidity of its owning mo...
The StatusAggregator collects results of multiple StatusMonitor instances and aggregates them into a ...
VoidInput _debug
Allow runtime debugging.
StatusAggregator()=default
void mainLoop() override
To be implemented by the user: function called in a separate thread executing the main loop of the mo...
PriorityMode
Possible status priority modes used during aggregation of unequal Status values.
@ fw_warn_mixed
fault - warning - ok or off, mixed state of ok or off results in warning
@ ofwk
off - fault - warning - ok
@ fwko
fault - warning - ok - off
@ fwok
fault - warning - off - ok
void populateStatusInput()
Recursivly search for StatusMonitors and other StatusAggregators.
void setWarnMixedMessage(std::string message)
Set a custom message for the warn mixed state.
std::vector< StatusWithMessageInput > _inputs
All status inputs to be aggregated.
int getPriority(StatusOutput::Status status) const
Convert Status value into a priority (high integer value = high priority), depending on chosen Priori...
PriorityMode _mode
Priority mode used in aggregation.
StatusWithMessage _output
The aggregated status output.
DataValidity getDataValidity() const override
Return the data validity flag.
std::string _warnMixedMessage
Error message for the warn_mixed condition.
static constexpr auto tagInternalVars
Reserved tag which is used to mark internal variables which should not be visible in the virtual hier...
std::unordered_set< std::string > _tagsToAggregate
List of tags to aggregate.
static constexpr auto tagAggregatedStatus
Reserved tag which is used to mark aggregated status outputs (need to stop searching further down the...
static constexpr auto tagStatusHasMessage
Reserved tag which is used to mark presense of the message output.
void writeIfDifferent(StatusOutput::Status status, std::string message)
ScalarOutput< std::string > _message
void writeOkIfDifferent()