GMLC-TDC / HELICS
Showing 31 of 219 files from the diff.
Other files ignored by Codecov
CHANGELOG.md has changed.
CMakeLists.txt has changed.
appveyor.yml has changed.
docs/ROADMAP.md has changed.
.gitattributes has changed.

@@ -38,6 +38,11 @@
Loading
38 38
    int32_t required_connections{0};  //!< the number of required connections 0 is no requirement
39 39
    /** check the value if it is the same as the most recent data and if changed, store it*/
40 40
    bool CheckSetValue(const char* dataToCheck, uint64_t len);
41 +
    /** add a new subscriber to the publication
42 +
   @return true if the subscriber was added false if duplicate
43 +
   */
44 +
    bool addSubscriber(global_handle newSubscriber);
45 +
41 46
    /** remove a subscriber*/
42 47
    void removeSubscriber(global_handle subscriberToRemove);
43 48
};

@@ -257,25 +257,47 @@
Loading
257 257
                return 0;
258 258
            }
259 259
        }
260 -
        auto sz = socket_.send(asio::buffer(buffer, dataLength));
261 -
        assert(sz == dataLength);
262 -
        return sz;
260 +
261 +
        size_t sz;
262 +
        size_t sent_size{dataLength};
263 +
        size_t p{0};
264 +
        int count{0};
265 +
        while (count++ < 5 &&
266 +
               (sz = socket_.send(asio::buffer(reinterpret_cast<const char*>(buffer) + p,
267 +
                                               sent_size))) != sent_size) {
268 +
            sent_size -= sz;
269 +
            p += sz;
270 +
            //   std::cerr << "DEBUG partial buffer sent" << std::endl;
271 +
        }
272 +
        if (count >= 5) {
273 +
            std::cerr << "TcpConnection send terminated " << std::endl;
274 +
            return 0;
275 +
        }
276 +
        return dataLength;
277 +
278 +
        //  assert(sz == dataLength);
279 +
        //  return sz;
263 280
    }
264 281
265 282
    size_t TcpConnection::send(const std::string& dataString)
266 283
    {
267 -
        if (!isConnected()) {
268 -
            if (!waitUntilConnected(300ms)) {
269 -
                std::cerr << "connection timeout waiting again" << std::endl;
270 -
            }
271 -
            if (!waitUntilConnected(200ms)) {
272 -
                std::cerr << "connection timeout twice, now returning" << std::endl;
273 -
                return 0;
274 -
            }
275 -
        }
276 -
        auto sz = socket_.send(asio::buffer(dataString));
277 -
        assert(sz == dataString.size());
284 +
        size_t sz;
285 +
        sz = send(&dataString[0], dataString.size());
278 286
        return sz;
287 +
        /*
288 +
                if (!isConnected()) {
289 +
                    if (!waitUntilConnected(300ms)) {
290 +
                        std::cerr << "connection timeout waiting again" << std::endl;
291 +
                    }
292 +
                    if (!waitUntilConnected(200ms)) {
293 +
                        std::cerr << "connection timeout twice, now returning" << std::endl;
294 +
                        return 0;
295 +
                    }
296 +
                }
297 +
                auto sz = socket_.send(asio::buffer(dataString));
298 +
                assert(sz == dataString.size());
299 +
                return sz;
300 +
        */
279 301
    }
280 302
281 303
    size_t TcpConnection::receive(void* buffer, size_t maxDataSize)
@@ -541,7 +563,7 @@
Loading
541 563
                acc->set_option(tcp::acceptor::reuse_address(false));
542 564
            }
543 565
            acc->setAcceptCall([this](TcpAcceptor::pointer accPtr, TcpConnection::pointer conn) {
544 -
                handle_accept(accPtr, conn);
566 +
                handle_accept(std::move(accPtr), std::move(conn));
545 567
            });
546 568
            acceptors.push_back(std::move(acc));
547 569
        }

@@ -251,8 +251,9 @@
Loading
251 251
                auto units = getOrDefault(sub, "unit", emptyStr);
252 252
                replaceIfMember(sub, "units", units);
253 253
                subAct = &registerInput(emptyStr, type, units);
254 +
                subAct->addTarget(key);
254 255
            }
255 -
            subAct->addTarget(key);
256 +
256 257
            loadOptions(this, sub, *subAct);
257 258
        }
258 259
    }

@@ -110,13 +110,20 @@
Loading
110 110
    }
111 111
}
112 112
113 -
void InputInfo::addSource(global_handle newSource,
113 +
bool InputInfo::addSource(global_handle newSource,
114 114
                          const std::string& sourceName,
115 115
                          const std::string& stype,
116 116
                          const std::string& sunits)
117 117
{
118 +
    for (const auto& is : input_sources) {
119 +
        if (is == newSource) {
120 +
            return false;
121 +
        }
122 +
    }
123 +
    // clear this since it isn't well defined what the units are once a new source is added
118 124
    inputUnits.clear();
119 125
    inputType.clear();
126 +
120 127
    input_sources.push_back(newSource);
121 128
    source_info.emplace_back(sourceName, stype, sunits);
122 129
    data_queues.resize(input_sources.size());
@@ -124,10 +131,12 @@
Loading
124 131
    current_data_time.resize(input_sources.size(), {Time::minVal(), 0});
125 132
    deactivated.push_back(Time::maxVal());
126 133
    has_target = true;
134 +
    return true;
127 135
}
128 136
129 137
void InputInfo::removeSource(global_handle sourceToRemove, Time minTime)
130 138
{
139 +
    // the inputUnits and type are not determined anymore since the source list has changed
131 140
    inputUnits.clear();
132 141
    inputType.clear();
133 142
    for (size_t ii = 0; ii < input_sources.size(); ++ii) {

@@ -63,6 +63,8 @@
Loading
63 63
  protected:
64 64
    std::atomic<modes> currentMode{modes::startup};  //!< the current state of the simulation
65 65
    char nameSegmentSeparator = '/';  //!< the separator between automatically prependend names
66 +
    bool strictConfigChecking =
67 +
        true;  //!< set to false to allow some invalid configurations to be ignored instead of error
66 68
  private:
67 69
    local_federate_id fedID;  //!< the federate ID of the object for use in the core
68 70
  protected:
@@ -217,7 +219,7 @@
Loading
217 219
    Time requestTime(Time nextInternalTimeStep);
218 220
219 221
    /** request a time advancement to the next allowed time
220 -
  @return the granted time step*/
222 +
    @return the granted time step*/
221 223
    Time requestNextStep() { return requestTime(timeZero); }
222 224
223 225
    /** request a time advancement by a certain amount
@@ -347,12 +349,12 @@
Loading
347 349
348 350
    /** get the results of an async query
349 351
    @details the call will block until the results are returned inquiry of queryCompleted() to check
350 -
   if the results have been returned or not yet
352 +
    if the results have been returned or not yet
351 353
352 354
    @param queryIndex the int value returned from the queryAsync call
353 -
   @return a string with the value requested.  the format of the string will be either a single
354 -
   string a string vector like "[string1; string2]" or JSON The string "#invalid" is returned if the
355 -
   query was not valid
355 +
    @return a string with the value requested.  the format of the string will be either a single
356 +
    string a string vector like "[string1; string2]" or JSON The string "#invalid" is returned if
357 +
    the query was not valid
356 358
    */
357 359
    std::string queryComplete(query_id_t queryIndex);
358 360
@@ -361,6 +363,16 @@
Loading
361 363
    */
362 364
    bool isQueryCompleted(query_id_t queryIndex) const;
363 365
366 +
    /** supply a query callback function
367 +
    @details the intention of the query callback is to allow federates to answer particular requests
368 +
    through the query interface this allows other federates to make requests or queries of other
369 +
    federates in an asynchronous fashion.
370 +
    @param queryFunction  a function object that returns a string as a result of a query in the form
371 +
    of const string ref. This callback will be called when a federate received a query that cannot
372 +
    be answered internally that is directed at that particular federate
373 +
    */
374 +
    void setQueryCallback(const std::function<std::string(const std::string&)>& queryFunction);
375 +
364 376
    /** set a federation global value
365 377
    @details this overwrites any previous value for this name
366 378
    @param valueName the name of the global to set

@@ -17,6 +17,17 @@
Loading
17 17
    return false;
18 18
}
19 19
20 +
bool PublicationInfo::addSubscriber(global_handle newSubscriber)
21 +
{
22 +
    for (const auto& sub : subscribers) {
23 +
        if (sub == newSubscriber) {
24 +
            return false;
25 +
        }
26 +
    }
27 +
    subscribers.push_back(newSubscriber);
28 +
    return true;
29 +
}
30 +
20 31
void PublicationInfo::removeSubscriber(global_handle subscriberToRemove)
21 32
{
22 33
    subscribers.erase(std::remove(subscribers.begin(), subscribers.end(), subscriberToRemove),

@@ -179,6 +179,19 @@
Loading
179 179
    }
180 180
    /** get the payload as a string*/
181 181
    const std::string& to_string() const { return data.to_string(); }
182 +
    /** clear all data from the message*/
183 +
    void clear()
184 +
    {
185 +
        time = timeZero;
186 +
        flags = 0;
187 +
        messageID = 0;
188 +
        data.resize(0);
189 +
        dest.clear();
190 +
        source.clear();
191 +
        original_source.clear();
192 +
        original_dest.clear();
193 +
        counter = 0;
194 +
    }
182 195
};
183 196
184 197
/**

@@ -391,4 +391,7 @@
Loading
391 391
    /** close an interface*/
392 392
    void closeInterface(interface_handle handle, handle_type type);
393 393
};
394 +
395 +
/** convert the state into a human readable string*/
396 +
const std::string& fedStateString(federate_state state);
394 397
}  // namespace helics

@@ -163,7 +163,7 @@
Loading
163 163
}
164 164
federate_state FederateState::getState() const
165 165
{
166 -
    return state;
166 +
    return state.load();
167 167
}
168 168
169 169
int32_t FederateState::getCurrentIteration() const
@@ -1147,18 +1147,20 @@
Loading
1147 1147
        case CMD_ADD_PUBLISHER: {
1148 1148
            auto* subI = interfaceInformation.getInput(cmd.dest_handle);
1149 1149
            if (subI != nullptr) {
1150 -
                subI->addSource(cmd.getSource(),
1151 -
                                cmd.name,
1152 -
                                cmd.getString(typeStringLoc),
1153 -
                                cmd.getString(unitStringLoc));
1154 -
                addDependency(cmd.source_id);
1150 +
                if (subI->addSource(cmd.getSource(),
1151 +
                                    cmd.name,
1152 +
                                    cmd.getString(typeStringLoc),
1153 +
                                    cmd.getString(unitStringLoc))) {
1154 +
                    addDependency(cmd.source_id);
1155 +
                }
1155 1156
            }
1156 1157
        } break;
1157 1158
        case CMD_ADD_SUBSCRIBER: {
1158 1159
            auto* pubI = interfaceInformation.getPublication(cmd.dest_handle);
1159 1160
            if (pubI != nullptr) {
1160 -
                pubI->subscribers.emplace_back(cmd.source_id, cmd.source_handle);
1161 -
                addDependent(cmd.source_id);
1161 +
                if (pubI->addSubscriber(cmd.getSource())) {
1162 +
                    addDependent(cmd.source_id);
1163 +
                }
1162 1164
            }
1163 1165
        } break;
1164 1166
        case CMD_ADD_DEPENDENCY:
@@ -1408,6 +1410,7 @@
Loading
1408 1410
            ignore_unit_mismatch = value;
1409 1411
            break;
1410 1412
        case defs::flags::slow_responding:
1413 +
        case defs::flags::debugging:
1411 1414
            slow_responding = value;
1412 1415
            break;
1413 1416
        case defs::flags::terminate_on_error:
@@ -1500,6 +1503,7 @@
Loading
1500 1503
        case defs::flags::source_only:
1501 1504
            return source_only;
1502 1505
        case defs::flags::slow_responding:
1506 +
        case defs::flags::debugging:
1503 1507
            return slow_responding;
1504 1508
        case defs::flags::terminate_on_error:
1505 1509
            return terminate_on_error;
@@ -1650,6 +1654,35 @@
Loading
1650 1654
    }
1651 1655
}
1652 1656
1657 +
const std::string& fedStateString(federate_state state)
1658 +
{
1659 +
    static const std::string c1{"created"};
1660 +
    static const std::string estate{"error"};
1661 +
    static const std::string init{"initializing"};
1662 +
    static const std::string dis{"disconnected"};
1663 +
    static const std::string exec{"executing"};
1664 +
    static const std::string term{"terminating"};
1665 +
    static const std::string unk{"unknown"};
1666 +
1667 +
    switch (state) {
1668 +
        case federate_state::HELICS_CREATED:
1669 +
            return c1;
1670 +
        case federate_state::HELICS_INITIALIZING:
1671 +
            return init;
1672 +
        case federate_state::HELICS_EXECUTING:
1673 +
            return exec;
1674 +
        case federate_state::HELICS_TERMINATING:
1675 +
            return term;
1676 +
        case federate_state::HELICS_FINISHED:
1677 +
            return dis;
1678 +
        case federate_state::HELICS_ERROR:
1679 +
            return estate;
1680 +
        case federate_state::HELICS_UNKNOWN:
1681 +
        default:
1682 +
            return unk;
1683 +
    }
1684 +
}
1685 +
1653 1686
std::string FederateState::processQueryActual(const std::string& query) const
1654 1687
{
1655 1688
    if (query == "publications") {
@@ -1699,13 +1732,21 @@
Loading
1699 1732
        base["name"] = getIdentifier();
1700 1733
        base["id"] = global_id.load().baseValue();
1701 1734
        base["parent"] = parent_->getGlobalId().baseValue();
1702 -
        base["state"] = static_cast<int>(state.load());
1735 +
        base["state"] = fedStateString(state.load());
1703 1736
        base["publications"] = publicationCount();
1704 1737
        base["input"] = inputCount();
1705 1738
        base["endpoints"] = endpointCount();
1706 1739
        base["granted_time"] = static_cast<double>(grantedTime());
1707 1740
        return generateJsonString(base);
1708 1741
    }
1742 +
    if (query == "global_state") {
1743 +
        Json::Value base;
1744 +
        base["name"] = getIdentifier();
1745 +
        base["id"] = global_id.load().baseValue();
1746 +
        base["parent"] = parent_->getGlobalId().baseValue();
1747 +
        base["state"] = fedStateString(state.load());
1748 +
        return generateJsonString(base);
1749 +
    }
1709 1750
    if (query == "timeconfig") {
1710 1751
        Json::Value base;
1711 1752
        timeCoord->generateConfig(base);
@@ -1764,12 +1805,12 @@
Loading
1764 1805
std::string FederateState::processQuery(const std::string& query) const
1765 1806
{
1766 1807
    std::string qstring;
1767 -
    if (query == "publications" || query == "inputs" ||
1768 -
        query == "endpoints") {  // these never need to be locked
1808 +
    if (query == "publications" || query == "inputs" || query == "endpoints" ||
1809 +
        query == "global_state") {  // these never need to be locked
1769 1810
        qstring = processQueryActual(query);
1770 1811
    } else if ((query == "queries") || (query == "available_queries")) {
1771 1812
        qstring =
1772 -
            "publications;inputs;endpoints;interfaces;subscriptions;dependencies;timeconfig;config;dependents;current_time";
1813 +
            "publications;inputs;endpoints;interfaces;subscriptions;current_state;global_state;dependencies;timeconfig;config;dependents;current_time";
1773 1814
    } else {  // the rest might to prevent a race condition
1774 1815
        if (try_lock()) {
1775 1816
            qstring = processQueryActual(query);

@@ -483,8 +483,9 @@
Loading
483 483
std::string TimeCoordinator::printTimeStatus() const
484 484
{
485 485
    return fmt::format(
486 -
        R"raw({{"granted_time":{}, "exec":{}, "allow":{}, "value":{}, "message":{}, "minDe":{}, "minminDe":{}}})raw",
486 +
        R"raw({{"granted_time":{},"requested_time":{}, "exec":{}, "allow":{}, "value":{}, "message":{}, "minDe":{}, "minminDe":{}}})raw",
487 487
        static_cast<double>(time_granted),
488 +
        static_cast<double>(time_requested),
488 489
        static_cast<double>(time_exec),
489 490
        static_cast<double>(time_allow),
490 491
        static_cast<double>(time_value),

@@ -23,7 +23,7 @@
Loading
23 23
                                    void* userdata,
24 24
                                    helics_error* err)
25 25
{
26 -
    auto brk = getBroker(broker, err);
26 +
    auto* brk = getBroker(broker, err);
27 27
    if (brk == nullptr) {
28 28
        return;
29 29
    }
@@ -46,7 +46,7 @@
Loading
46 46
                                  void* userdata,
47 47
                                  helics_error* err)
48 48
{
49 -
    auto cr = getCore(core, err);
49 +
    auto* cr = getCore(core, err);
50 50
    if (cr == nullptr) {
51 51
        return;
52 52
    }
@@ -70,7 +70,7 @@
Loading
70 70
                                      void* userdata,
71 71
                                      helics_error* err)
72 72
{
73 -
    auto fedptr = getFed(fed, err);
73 +
    auto* fedptr = getFed(fed, err);
74 74
    if (fedptr == nullptr) {
75 75
        return;
76 76
    }
@@ -88,3 +88,56 @@
Loading
88 88
        helicsErrorHandler(err);  // LCOV_EXCL_LINE
89 89
    }
90 90
}
91 +
92 +
void helicsFederateSetQueryCallback(helics_federate fed,
93 +
                                    void (*queryAnswer)(const char* query, int querySize, helics_query_buffer buffer, void* userdata),
94 +
                                    void* userdata,
95 +
                                    helics_error* err)
96 +
{
97 +
    auto* fedptr = getFed(fed, err);
98 +
    if (fedptr == nullptr) {
99 +
        return;
100 +
    }
101 +
102 +
    try {
103 +
        if (queryAnswer == nullptr) {
104 +
            fedptr->setQueryCallback({});
105 +
        } else {
106 +
            fedptr->setQueryCallback([queryAnswer, userdata](const std::string& query) {
107 +
                std::string buffer(1, '>');
108 +
                queryAnswer(query.c_str(), static_cast<int>(query.size()), &buffer, userdata);
109 +
                buffer.pop_back();
110 +
                return buffer;
111 +
            });
112 +
        }
113 +
    }
114 +
    catch (...) {  // LCOV_EXCL_LINE
115 +
        helicsErrorHandler(err);  // LCOV_EXCL_LINE
116 +
    }
117 +
}
118 +
119 +
void helicsQueryBufferFill(helics_query_buffer buffer, const char* string, int stringSize, helics_error* err)
120 +
{
121 +
    static const char* invalidBuffer = "The given buffer is not valid";
122 +
123 +
    if (((err) != nullptr) && ((err)->error_code != 0)) {
124 +
        return;
125 +
    }
126 +
    if (buffer == nullptr) {
127 +
        assignError(err, helics_error_invalid_object, invalidBuffer);
128 +
        return;
129 +
    }
130 +
131 +
    auto* bufferStr = reinterpret_cast<std::string*>(buffer);
132 +
    if (bufferStr->empty() || bufferStr->back() != '>') {
133 +
        assignError(err, helics_error_invalid_object, invalidBuffer);
134 +
        return;
135 +
    }
136 +
    if (stringSize <= 0 || string == nullptr) {
137 +
        bufferStr->clear();
138 +
        bufferStr->push_back('>');
139 +
    }
140 +
    bufferStr->reserve(stringSize + 1);
141 +
    bufferStr->assign(string, string + stringSize);
142 +
    bufferStr->push_back('>');
143 +
}

@@ -314,6 +314,8 @@
Loading
314 314
    void disconnectBroker(BasicBrokerInfo& brk);
315 315
    /** mark this broker and all other that have this as a parent as disconnected*/
316 316
    void markAsDisconnected(global_broker_id brkid);
317 +
    /** check to make sure there are no inflight queries that need to be resolved*/
318 +
    void checkInFlightQueries(global_broker_id brkid);
317 319
    /** run a check for a named interface*/
318 320
    void checkForNamedInterface(ActionMessage& command);
319 321
    /** remove a named target from an interface*/
@@ -359,6 +361,7 @@
Loading
359 361
360 362
    /** generate a time barrier request*/
361 363
    void generateTimeBarrier(ActionMessage& m);
364 +
    int generateMapObjectCounter() const;
362 365
    friend class TimeoutMonitor;
363 366
};
364 367

@@ -119,8 +119,10 @@
Loading
119 119
    bool updateTimeNextIteration(Time newTime);
120 120
    /** get the event based on the event queue*/
121 121
    Time nextValueTime() const;
122 -
    /** add a new source target to the input*/
123 -
    void addSource(global_handle newSource,
122 +
    /** add a new source target to the input
123 +
    @return true if the source was added false if duplicate
124 +
    */
125 +
    bool addSource(global_handle newSource,
124 126
                   const std::string& sourceName,
125 127
                   const std::string& stype,
126 128
                   const std::string& sunits);

@@ -657,6 +657,19 @@
Loading
657 657
    broadcast(m);
658 658
}
659 659
660 +
int CoreBroker::generateMapObjectCounter() const
661 +
{
662 +
    int result = static_cast<int>(brokerState.load());
663 +
    for (const auto& brk : _brokers) {
664 +
        result += static_cast<int>(brk.state);
665 +
    }
666 +
    for (const auto& fed : _federates) {
667 +
        result += static_cast<int>(fed.state);
668 +
    }
669 +
    result += static_cast<int>(handles.size());
670 +
    return result;
671 +
}
672 +
660 673
void CoreBroker::transmitDelayedMessages()
661 674
{
662 675
    auto msg = delayTransmitQueue.pop();
@@ -2296,6 +2309,40 @@
Loading
2296 2309
    }
2297 2310
}
2298 2311
2312 +
void CoreBroker::checkInFlightQueries(global_broker_id brkid)
2313 +
{
2314 +
    for (auto& mb : mapBuilders) {
2315 +
        auto& builder = std::get<0>(mb);
2316 +
        auto& requestors = std::get<1>(mb);
2317 +
        if (builder.isCompleted()) {
2318 +
            return;
2319 +
        }
2320 +
        if (builder.clearComponents(brkid.baseValue())) {
2321 +
            auto str = builder.generate();
2322 +
            for (int ii = 0; ii < static_cast<int>(requestors.size()) - 1; ++ii) {
2323 +
                if (requestors[ii].dest_id == global_broker_id_local) {
2324 +
                    activeQueries.setDelayedValue(requestors[ii].messageID, str);
2325 +
                } else {
2326 +
                    requestors[ii].payload = str;
2327 +
                    routeMessage(std::move(requestors[ii]));
2328 +
                }
2329 +
            }
2330 +
            if (requestors.back().dest_id == global_broker_id_local) {
2331 +
                // TODO(PT) add rvalue reference method
2332 +
                activeQueries.setDelayedValue(requestors.back().messageID, str);
2333 +
            } else {
2334 +
                requestors.back().payload = std::move(str);
2335 +
                routeMessage(std::move(requestors.back()));
2336 +
            }
2337 +
2338 +
            requestors.clear();
2339 +
            if (std::get<2>(mb)) {
2340 +
                builder.reset();
2341 +
            }
2342 +
        }
2343 +
    }
2344 +
}
2345 +
2299 2346
void CoreBroker::markAsDisconnected(global_broker_id brkid)
2300 2347
{
2301 2348
    bool isCore{false};
@@ -2331,6 +2378,7 @@
Loading
2331 2378
void CoreBroker::disconnectBroker(BasicBrokerInfo& brk)
2332 2379
{
2333 2380
    markAsDisconnected(brk.global_id);
2381 +
    checkInFlightQueries(brk.global_id);
2334 2382
    if (brokerState < broker_state_t::operating) {
2335 2383
        if (isRootc) {
2336 2384
            ActionMessage dis(CMD_BROADCAST_DISCONNECT);
@@ -2437,7 +2485,8 @@
Loading
2437 2485
    current_time_map = 2,
2438 2486
    dependency_graph = 3,
2439 2487
    data_flow_graph = 4,
2440 -
    version_all = 5
2488 +
    version_all = 5,
2489 +
    global_state = 6
2441 2490
};
2442 2491
2443 2492
static const std::map<std::string, std::pair<std::uint16_t, bool>> mapIndex{
@@ -2446,6 +2495,7 @@
Loading
2446 2495
    {"dependency_graph", {dependency_graph, false}},
2447 2496
    {"data_flow_graph", {data_flow_graph, false}},
2448 2497
    {"version_all", {version_all, false}},
2498 +
    {"global_state", {global_state, true}},
2449 2499
};
2450 2500
2451 2501
std::string CoreBroker::generateQueryAnswer(const std::string& request)
@@ -2465,8 +2515,8 @@
Loading
2465 2515
    }
2466 2516
    if ((request == "queries") || (request == "available_queries")) {
2467 2517
        return "[isinit;isconnected;name;identifier;address;queries;address;counts;summary;federates;brokers;inputs;endpoints;"
2468 -
               "publications;filters;federate_map;dependency_graph;data_flow_graph;dependencies;dependson;dependents;"
2469 -
               "current_time;current_state;status;global_time;version;version_all;exists]";
2518 +
               "publications;filters;federate_map;dependency_graph;counter;data_flow_graph;dependencies;dependson;dependents;"
2519 +
               "current_time;current_state;global_state;status;global_time;version;version_all;exists]";
2470 2520
    }
2471 2521
    if (request == "address") {
2472 2522
        return getAddress();
@@ -2474,6 +2524,9 @@
Loading
2474 2524
    if (request == "version") {
2475 2525
        return versionString;
2476 2526
    }
2527 +
    if (request == "counter") {
2528 +
        return fmt::format("{}", generateMapObjectCounter());
2529 +
    }
2477 2530
    if (request == "status") {
2478 2531
        Json::Value base;
2479 2532
        base["name"] = getIdentifier();
@@ -2528,8 +2581,8 @@
Loading
2528 2581
            fedstate["id"] = fed.global_id.baseValue();
2529 2582
            base["federates"].append(std::move(fedstate));
2530 2583
        }
2531 -
        base["brokers"] = Json::arrayValue;
2532 2584
        base["cores"] = Json::arrayValue;
2585 +
        base["brokers"] = Json::arrayValue;
2533 2586
        for (const auto& brk : _brokers) {
2534 2587
            Json::Value brkstate;
2535 2588
            brkstate["state"] = state_string(brk.state);
@@ -2553,16 +2606,25 @@
Loading
2553 2606
    if (mi != mapIndex.end()) {
2554 2607
        auto index = mi->second.first;
2555 2608
        if (isValidIndex(index, mapBuilders) && !mi->second.second) {
2556 -
            if (std::get<0>(mapBuilders[index]).isCompleted()) {
2557 -
                return std::get<0>(mapBuilders[index]).generate();
2609 +
            auto& builder = std::get<0>(mapBuilders[index]);
2610 +
            if (builder.isCompleted()) {
2611 +
                auto center = generateMapObjectCounter();
2612 +
                if (center == builder.getCounterCode()) {
2613 +
                    return builder.generate();
2614 +
                }
2615 +
                builder.reset();
2558 2616
            }
2559 -
            if (std::get<0>(mapBuilders[index]).isActive()) {
2617 +
            if (builder.isActive()) {
2560 2618
                return "#wait";
2561 2619
            }
2562 2620
        }
2563 2621
2564 2622
        initializeMapBuilder(request, index, mi->second.second);
2565 2623
        if (std::get<0>(mapBuilders[index]).isCompleted()) {
2624 +
            if (!mi->second.second) {
2625 +
                auto center = generateMapObjectCounter();
2626 +
                std::get<0>(mapBuilders[index]).setCounterCode(center);
2627 +
            }
2566 2628
            return std::get<0>(mapBuilders[index]).generate();
2567 2629
        }
2568 2630
        return "#wait";
@@ -2654,6 +2716,7 @@
Loading
2654 2716
    gidString.push_back(']');
2655 2717
    return gidString;
2656 2718
}
2719 +
2657 2720
void CoreBroker::initializeMapBuilder(const std::string& request, std::uint16_t index, bool reset)
2658 2721
{
2659 2722
    if (!isValidIndex(index, mapBuilders)) {
@@ -2677,21 +2740,57 @@
Loading
2677 2740
    queryReq.source_id = global_broker_id_local;
2678 2741
    queryReq.counter = index;  // indicating which processing to use
2679 2742
    bool hasCores = false;
2743 +
    bool hasBrokers = false;
2680 2744
    for (const auto& broker : _brokers) {
2681 2745
        if (broker.parent == global_broker_id_local) {
2682 -
            int brkindex;
2683 -
            if (broker._core) {
2684 -
                if (!hasCores) {
2685 -
                    hasCores = true;
2686 -
                    base["cores"] = Json::arrayValue;
2687 -
                }
2688 -
                brkindex = builder.generatePlaceHolder("cores");
2689 -
            } else {
2690 -
                brkindex = builder.generatePlaceHolder("brokers");
2746 +
            switch (broker.state) {
2747 +
                case connection_state::connected:
2748 +
                case connection_state::init_requested:
2749 +
                case connection_state::operating: {
2750 +
                    int brkindex;
2751 +
                    if (broker._core) {
2752 +
                        if (!hasCores) {
2753 +
                            hasCores = true;
2754 +
                            base["cores"] = Json::arrayValue;
2755 +
                        }
2756 +
                        brkindex =
2757 +
                            builder.generatePlaceHolder("cores", broker.global_id.baseValue());
2758 +
                    } else {
2759 +
                        if (!hasBrokers) {
2760 +
                            hasBrokers = true;
2761 +
                            base["brokers"] = Json::arrayValue;
2762 +
                        }
2763 +
                        brkindex =
2764 +
                            builder.generatePlaceHolder("brokers", broker.global_id.baseValue());
2765 +
                    }
2766 +
                    queryReq.messageID = brkindex;
2767 +
                    queryReq.dest_id = broker.global_id;
2768 +
                    transmit(broker.route, queryReq);
2769 +
                } break;
2770 +
                case connection_state::error:
2771 +
                case connection_state::disconnected:
2772 +
                case connection_state::request_disconnect:
2773 +
                    if (index == global_state) {
2774 +
                        Json::Value brkstate;
2775 +
                        brkstate["state"] = state_string(broker.state);
2776 +
                        brkstate["name"] = broker.name;
2777 +
                        brkstate["id"] = broker.global_id.baseValue();
2778 +
                        if (broker._core) {
2779 +
                            if (!hasCores) {
2780 +
                                base["cores"] = Json::arrayValue;
2781 +
                                hasCores = true;
2782 +
                            }
2783 +
                            base["cores"].append(std::move(brkstate));
2784 +
                        } else {
2785 +
                            if (!hasBrokers) {
2786 +
                                base["brokers"] = Json::arrayValue;
2787 +
                                hasBrokers = true;
2788 +
                            }
2789 +
                            base["brokers"].append(std::move(brkstate));
2790 +
                        }
2791 +
                    }
2792 +
                    break;
2691 2793
            }
2692 -
            queryReq.messageID = brkindex;
2693 -
            queryReq.dest_id = broker.global_id;
2694 -
            transmit(broker.route, queryReq);
2695 2794
        }
2696 2795
    }
2697 2796
    switch (index) {
@@ -2713,6 +2812,10 @@
Loading
2713 2812
        case version_all:
2714 2813
            base["version"] = versionString;
2715 2814
            break;
2815 +
        case global_state:
2816 +
            base["state"] = brokerStateName(brokerState.load());
2817 +
            base["status"] = isConnected();
2818 +
            break;
2716 2819
    }
2717 2820
}
2718 2821
@@ -2889,6 +2992,8 @@
Loading
2889 2992
            requestors.clear();
2890 2993
            if (std::get<2>(mapBuilders[m.counter])) {
2891 2994
                builder.reset();
2995 +
            } else {
2996 +
                builder.setCounterCode(generateMapObjectCounter());
2892 2997
            }
2893 2998
        }
2894 2999
    }

@@ -146,6 +146,10 @@
Loading
146 146
        "--conservative_time_policy,--restrictive_time_policy",
147 147
        restrictive_time_policy,
148 148
        "specify that a broker should use a conservative time policy in the time coordinator");
149 +
    hApp->add_flag(
150 +
        "--debugging",
151 +
        debugging,
152 +
        "specify that a broker/core should operate in user debugging mode equivalent to --slow_responding --disable_timer");
149 153
    hApp->add_flag("--terminate_on_error,--halt_on_error",
150 154
                   terminate_on_error,
151 155
                   "specify that a broker should cause the federation to terminate on an error");
@@ -278,6 +282,10 @@
Loading
278 282
279 283
void BrokerBase::configureBase()
280 284
{
285 +
    if (debugging) {
286 +
        no_ping = true;
287 +
        disable_timer = true;
288 +
    }
281 289
    if (networkTimeout < timeZero) {
282 290
        networkTimeout = 4.0;
283 291
    }
@@ -427,6 +435,18 @@
Loading
427 435
    }
428 436
}
429 437
438 +
bool BrokerBase::getFlagValue(int32_t flag) const
439 +
{
440 +
    switch (flag) {
441 +
        case helics_flag_dumplog:
442 +
            return dumplog;
443 +
        case helics_flag_force_logging_flush:
444 +
            return forceLoggingFlush.load();
445 +
        default:
446 +
            return false;
447 +
    }
448 +
}
449 +
430 450
void BrokerBase::setLoggerFunction(
431 451
    std::function<void(int, const std::string&, const std::string&)> logFunction)
432 452
{
@@ -770,8 +790,8 @@
Loading
770 790
                NMess.from_string(command.getString(ii));
771 791
                auto V = commandProcessor(NMess);
772 792
                if (V != CMD_IGNORE) {
773 -
                    // overwrite the abort command but ignore ticks in a multi-message context they
774 -
                    // shouldn't be there
793 +
                    // overwrite the abort command but ignore ticks in a multi-message context
794 +
                    // they shouldn't be there
775 795
                    if (V != CMD_TICK) {
776 796
                        command = NMess;
777 797
                        return V;

@@ -70,6 +70,7 @@
Loading
70 70
        false};  //!< flag indicating the broker should use a conservative time policy
71 71
    bool terminate_on_error{
72 72
        false};  //!< flag indicating that the federation should halt on any error
73 +
    bool debugging{false};  //!< flag indicating operation in a user debugging mode
73 74
  private:
74 75
    std::atomic<bool> mainLoopIsRunning{
75 76
        false};  //!< flag indicating that the main processing loop is running
@@ -212,6 +213,8 @@
Loading
212 213
    void setErrorState(int eCode, const std::string& estring);
213 214
    /** set the logging file if using the default logger*/
214 215
    void setLoggingFile(const std::string& lfile);
216 +
    /** get the value of a particular flag*/
217 +
    bool getFlagValue(int32_t flag) const;
215 218
216 219
  public:
217 220
    /** generate a callback function for the logging purposes*/

@@ -125,9 +125,21 @@
Loading
125 125
126 126
void ValueFederateManager::addTarget(const Input& inp, const std::string& target)
127 127
{
128 +
    {
129 +
        auto iTHandle = inputTargets.lock();
130 +
        auto rng = iTHandle->equal_range(inp.handle);
131 +
        for (auto el = rng.first; el != rng.second; ++el) {
132 +
            if (el->second == target) {
133 +
                fed->logWarningMessage(std::string("Duplicate input targets detected for ") +
134 +
                                       inp.actualName + "::" + target);
135 +
                return;
136 +
            }
137 +
        }
138 +
    }
139 +
128 140
    coreObject->addSourceTarget(inp.handle, target);
129 -
    targetIDs.lock()->emplace(target, inp.handle);
130 141
    inputTargets.lock()->emplace(inp.handle, target);
142 +
    targetIDs.lock()->emplace(target, inp.handle);
131 143
}
132 144
133 145
void ValueFederateManager::removeTarget(const Publication& pub, const std::string& target)

@@ -182,6 +182,7 @@
Loading
182 182
        mo = HELICS_NULL_POINTER;
183 183
        return mreturn;
184 184
    }
185 +
    void clear() { helicsMessageClear(mo, HELICS_IGNORE_ERROR); }
185 186
    /** generate a new message in a federate*/
186 187
    Message& newMessageObject(const Federate& fed);
187 188

@@ -136,8 +136,9 @@
Loading
136 136
{
137 137
    if (openPorts.getDefaultStartingPort() < 0) {
138 138
        auto dport = PortNumber - getDefaultBrokerPort();
139 -
        auto start = (dport < 10 * count) ? getDefaultBrokerPort() + 10 * count * (dport + 1) :
140 -
                                            PortNumber + 5 * count;
139 +
        auto start = (dport < 10 * count && dport >= 0) ?
140 +
            getDefaultBrokerPort() + 10 * count * (dport + 1) :
141 +
            PortNumber + 5 * count;
141 142
        openPorts.setStartingPortNumber(start);
142 143
    }
143 144
    return openPorts.findOpenPort(count, host);

@@ -10,6 +10,7 @@
Loading
10 10
11 11
#include "../shared_api_library/MessageFilters.h"
12 12
#include "../shared_api_library/helics.h"
13 +
#include "../shared_api_library/helicsCallbacks.h"
13 14
#include "Filter.hpp"
14 15
#include "config.hpp"
15 16
#include "helicsExceptions.hpp"
@@ -18,6 +19,11 @@
Loading
18 19
#include <string>
19 20
#include <vector>
20 21
22 +
#if defined(HELICS_HAS_FUNCTIONAL) && HELICS_HAS_FUNCTIONAL != 0
23 +
#    include <functional>
24 +
#    include <utility>
25 +
#endif
26 +
21 27
namespace helicscpp {
22 28
/** hold federate information in the C++98 API*/
23 29
class FederateInfo {
@@ -153,6 +159,22 @@
Loading
153 159
    helics_federate_info fi;  //!< handle for the underlying federate_info object
154 160
};
155 161
162 +
#if defined(HELICS_HAS_FUNCTIONAL) && HELICS_HAS_FUNCTIONAL != 0
163 +
namespace details {
164 +
    /** helper function for the callback executor for queries*/
165 +
    inline void helicCppQueryCallbackExecutor(const char* query,
166 +
                                              int stringSize,
167 +
                                              helics_query_buffer buffer,
168 +
                                              void* userData)
169 +
    {
170 +
        auto cback = reinterpret_cast<std::function<std::string(const std::string&)>*>(userData);
171 +
        std::string val(query, stringSize);
172 +
        std::string result = (*cback)(val);
173 +
        helicsQueryBufferFill(buffer, result.c_str(), static_cast<int>(result.size()), nullptr);
174 +
    }
175 +
}  // namespace details
176 +
#endif
177 +
156 178
/** an iteration time structure */
157 179
typedef struct {
158 180
  public:
@@ -199,6 +221,13 @@
Loading
199 221
        if (fed != HELICS_NULL_POINTER) {
200 222
            helicsFederateFree(fed);
201 223
        }
224 +
#if defined(HELICS_HAS_FUNCTIONAL) && HELICS_HAS_FUNCTIONAL != 0
225 +
        if (callbackBuffer != nullptr) {
226 +
            auto cback =
227 +
                reinterpret_cast<std::function<std::string(const std::string&)>*>(callbackBuffer);
228 +
            delete cback;
229 +
        }
230 +
#endif
202 231
    }
203 232
    /** cast operator to get the underlying helics_federate object*/
204 233
    operator helics_federate() const { return fed; }
@@ -469,6 +498,26 @@
Loading
469 498
        return result;
470 499
    }
471 500
501 +
    void setQueryCallback(
502 +
        void (*queryAnswer)(const char* query, int querySize, helics_query_buffer, void* userdata),
503 +
        void* userdata)
504 +
505 +
    {
506 +
        helicsFederateSetQueryCallback(fed, queryAnswer, userdata, hThrowOnError());
507 +
    }
508 +
509 +
#if defined(HELICS_HAS_FUNCTIONAL) && HELICS_HAS_FUNCTIONAL != 0
510 +
    void setQueryCallback(std::function<std::string(const std::string&)> callback)
511 +
512 +
    {
513 +
        callbackBuffer = new std::function<std::string(const std::string&)>(std::move(callback));
514 +
        helicsFederateSetQueryCallback(fed,
515 +
                                       details::helicCppQueryCallbackExecutor,
516 +
                                       callbackBuffer,
517 +
                                       hThrowOnError());
518 +
    }
519 +
520 +
#endif
472 521
    /** define a filter interface
473 522
    @details a filter will modify messages coming from or going to target endpoints
474 523
    @param type the type of the filter to register
@@ -599,7 +648,12 @@
Loading
599 648
  protected:
600 649
    helics_federate fed;  //!< underlying helics_federate object
601 650
    bool exec_async_iterate;  //!< indicator that the federate is in an async operation
651 +
#if defined(HELICS_HAS_FUNCTIONAL) && HELICS_HAS_FUNCTIONAL != 0
652 +
  private:
653 +
    void* callbackBuffer{nullptr};  //!< buffer to contain pointer to a callback
654 +
#endif
602 655
};
603 656
604 657
}  // namespace helicscpp
658 +
605 659
#endif

@@ -9,6 +9,7 @@
Loading
9 9
#include "../common/GuardedTypes.hpp"
10 10
#include "../common/addTargets.hpp"
11 11
#include "../common/configFileHelpers.hpp"
12 +
#include "../common/fmt_format.h"
12 13
#include "../core/BrokerFactory.hpp"
13 14
#include "../core/Core.hpp"
14 15
#include "../core/CoreFactory.hpp"
@@ -74,6 +75,7 @@
Loading
74 75
    // this call will throw an error on failure
75 76
    fedID = coreObject->registerFederate(name, fi);
76 77
    nameSegmentSeparator = fi.separator;
78 +
    strictConfigChecking = fi.checkFlagProperty(helics_flag_strict_config_checking, true);
77 79
    currentTime = coreObject->getCurrentTime(fedID);
78 80
    asyncCallInfo = std::make_unique<shared_guarded_m<AsyncFedCallInfo>>();
79 81
    fManager = std::make_unique<FilterFederateManager>(coreObject.get(), this, fedID);
@@ -111,6 +113,7 @@
Loading
111 113
    }
112 114
    fedID = coreObject->registerFederate(name, fi);
113 115
    nameSegmentSeparator = fi.separator;
116 +
    strictConfigChecking = fi.checkFlagProperty(helics_flag_strict_config_checking, true);
114 117
    currentTime = coreObject->getCurrentTime(fedID);
115 118
    asyncCallInfo = std::make_unique<shared_guarded_m<AsyncFedCallInfo>>();
116 119
    fManager = std::make_unique<FilterFederateManager>(coreObject.get(), this, fedID);
@@ -140,6 +143,7 @@
Loading
140 143
    coreObject = std::move(fed.coreObject);
141 144
    currentTime = fed.currentTime;
142 145
    nameSegmentSeparator = fed.nameSegmentSeparator;
146 +
    strictConfigChecking = fed.strictConfigChecking;
143 147
    asyncCallInfo = std::move(fed.asyncCallInfo);
144 148
    fManager = std::move(fed.fManager);
145 149
    name = std::move(fed.name);
@@ -153,6 +157,7 @@
Loading
153 157
    coreObject = std::move(fed.coreObject);
154 158
    currentTime = fed.currentTime;
155 159
    nameSegmentSeparator = fed.nameSegmentSeparator;
160 +
    strictConfigChecking = fed.strictConfigChecking;
156 161
    asyncCallInfo = std::move(fed.asyncCallInfo);
157 162
    fManager = std::move(fed.fManager);
158 163
    name = std::move(fed.name);
@@ -834,12 +839,27 @@
Loading
834 839
835 840
            auto opType = filterTypeFromString(operation);
836 841
            if ((useTypes) && (operation != "custom")) {
837 -
                std::cerr << "input and output types may only be specified for custom filters\n";
842 +
                if (strictConfigChecking) {
843 +
                    logMessage(helics_log_level_error,
844 +
                               "input and output types may only be specified for custom filters");
845 +
                    throw(InvalidParameter(
846 +
                        "input and output types may only be specified for custom filters"));
847 +
                }
848 +
                logMessage(helics_log_level_warning,
849 +
                           "input and output types may only be specified for custom filters");
838 850
                continue;
839 851
            }
840 852
            if (!useTypes) {
841 853
                if (opType == filter_types::unrecognized) {
842 -
                    std::cerr << "unrecognized filter operation:" << operation << '\n';
854 +
                    if (strictConfigChecking) {
855 +
                        std::string emessage =
856 +
                            fmt::format("unrecognized filter operation:{}", operation);
857 +
                        logMessage(helics_log_level_error, emessage);
858 +
859 +
                        throw(InvalidParameter(emessage));
860 +
                    }
861 +
                    logMessage(helics_log_level_warning,
862 +
                               fmt::format("unrecognized filter operation:{}", operation));
843 863
                    continue;
844 864
                }
845 865
            }
@@ -857,8 +877,16 @@
Loading
857 877
                if (props.isArray()) {
858 878
                    for (const auto& prop : props) {
859 879
                        if ((!prop.isMember("name")) || (!prop.isMember("value"))) {
860 -
                            std::cerr
861 -
                                << "properties must be specified with \"name\" and \"value\" fields\n";
880 +
                            if (strictConfigChecking) {
881 +
                                logMessage(
882 +
                                    helics_log_level_error,
883 +
                                    R"(filter properties require "name" and "value" fields)");
884 +
885 +
                                throw(InvalidParameter(
886 +
                                    R"(filter properties require "name" and "value" fields)"));
887 +
                            }
888 +
                            logMessage(helics_log_level_warning,
889 +
                                       R"(filter properties require "name" and "value" fields)");
862 890
                            continue;
863 891
                        }
864 892
                        if (prop["value"].isDouble()) {
@@ -869,9 +897,18 @@
Loading
869 897
                    }
870 898
                } else {
871 899
                    if ((!props.isMember("name")) || (!props.isMember("value"))) {
872 -
                        std::cerr
873 -
                            << "properties must be specified with \"name\" and \"value\" fields\n";
874 -
                    } else if (props["value"].isDouble()) {
900 +
                        if (strictConfigChecking) {
901 +
                            logMessage(helics_log_level_error,
902 +
                                       R"(filter properties require "name" and "value" fields)");
903 +
904 +
                            throw(InvalidParameter(
905 +
                                R"(filter properties require "name" and "value" fields)"));
906 +
                        }
907 +
                        logMessage(helics_log_level_warning,
908 +
                                   R"(filter properties require "name" and "value" fields)");
909 +
                        continue;
910 +
                    }
911 +
                    if (props["value"].isDouble()) {
875 912
                        filter.set(props["name"].asString(), props["value"].asDouble());
876 913
                    } else {
877 914
                        filter.setString(props["name"].asString(), props["value"].asString());
@@ -921,12 +958,25 @@
Loading
921 958
922 959
            auto opType = filterTypeFromString(operation);
923 960
            if ((useTypes) && (operation != "custom")) {
924 -
                std::cerr << "input and output types may only be specified for custom filters\n";
961 +
                if (strictConfigChecking) {
962 +
                    logMessage(helics_log_level_error,
963 +
                               "input and output types may only be specified for custom filters");
964 +
                    throw(InvalidParameter(
965 +
                        "input and output types may only be specified for custom filters"));
966 +
                }
967 +
                logMessage(helics_log_level_warning,
968 +
                           "input and output types may only be specified for custom filters");
925 969
                continue;
926 970
            }
927 971
            if (!useTypes) {
928 972
                if (opType == filter_types::unrecognized) {
929 -
                    std::cerr << "unrecognized filter operation:" << operation << '\n';
973 +
                    auto emessage = fmt::format("unrecognized filter operation:{}", operation);
974 +
                    if (strictConfigChecking) {
975 +
                        logMessage(helics_log_level_error, emessage);
976 +
977 +
                        throw(InvalidParameter(emessage));
978 +
                    }
979 +
                    logMessage(helics_log_level_warning, emessage);
930 980
                    continue;
931 981
                }
932 982
            }
@@ -951,8 +1001,16 @@
Loading
951 1001
                        auto propval = toml::find_or(prop, "value", uVal);
952 1002
953 1003
                        if ((propname.empty()) || (propval.is_uninitialized())) {
954 -
                            std::cerr
955 -
                                << "properties must be specified with \"name\" and \"value\" fields\n";
1004 +
                            if (strictConfigChecking) {
1005 +
                                logMessage(
1006 +
                                    helics_log_level_error,
1007 +
                                    R"(filter properties require "name" and "value" fields)");
1008 +
1009 +
                                throw(InvalidParameter(
1010 +
                                    R"(filter properties require "name" and "value" fields)"));
1011 +
                            }
1012 +
                            logMessage(helics_log_level_warning,
1013 +
                                       R"(filter properties require "name" and "value" fields)");
956 1014
                            continue;
957 1015
                        }
958 1016
                        if (propval.is_floating()) {
@@ -968,9 +1026,18 @@
Loading
968 1026
                    auto propval = toml::find_or(props, "value", uVal);
969 1027
970 1028
                    if ((propname.empty()) || (propval.is_uninitialized())) {
971 -
                        std::cerr
972 -
                            << "properties must be specified with \"name\" and \"value\" fields\n";
973 -
                    } else if (propval.is_floating()) {
1029 +
                        if (strictConfigChecking) {
1030 +
                            logMessage(helics_log_level_error,
1031 +
                                       R"(filter properties require "name" and "value" fields)");
1032 +
1033 +
                            throw(InvalidParameter(
1034 +
                                R"(filter properties require "name" and "value" fields)"));
1035 +
                        }
1036 +
                        logMessage(helics_log_level_warning,
1037 +
                                   R"(filter properties require "name" and "value" fields)");
1038 +
                        continue;
1039 +
                    }
1040 +
                    if (propval.is_floating()) {
974 1041
                        filter.set(propname, propval.as_floating());
975 1042
                    } else {
976 1043
                        filter.setString(propname, propval.as_string());
@@ -1085,6 +1152,16 @@
Loading
1085 1152
    return {"#invalid"};
1086 1153
}
1087 1154
1155 +
void Federate::setQueryCallback(const std::function<std::string(const std::string&)>& queryFunction)
1156 +
{
1157 +
    if (coreObject) {
1158 +
        coreObject->setQueryCallback(fedID, queryFunction);
1159 +
    } else {
1160 +
        throw(InvalidFunctionCall(
1161 +
            " setQueryCallback cannot be called on uninitialized federate or after finalize call"));
1162 +
    }
1163 +
}
1164 +
1088 1165
bool Federate::isQueryCompleted(query_id_t queryIndex) const  // NOLINT
1089 1166
{
1090 1167
    auto asyncInfo = asyncCallInfo->lock();

@@ -32,10 +32,10 @@
Loading
32 32
    return (jMap) && (missing_components.empty());
33 33
}
34 34
35 -
int JsonMapBuilder::generatePlaceHolder(const std::string& location)
35 +
int JsonMapBuilder::generatePlaceHolder(const std::string& location, int32_t code)
36 36
{
37 37
    int index = static_cast<int>(missing_components.size()) + 2;
38 -
    missing_components.emplace(index, location);
38 +
    missing_components.emplace(index, std::make_pair(location, code));
39 39
    return index;
40 40
}
41 41
@@ -44,14 +44,14 @@
Loading
44 44
    auto loc = missing_components.find(index);
45 45
    if (loc != missing_components.end()) {
46 46
        if (info == "#invalid") {
47 -
            (*jMap)[loc->second].append(Json::Value{});
47 +
            (*jMap)[loc->second.first].append(Json::Value{});
48 48
        } else {
49 49
            try {
50 50
                auto element = loadJsonStr(info);
51 -
                (*jMap)[loc->second].append(element);
51 +
                (*jMap)[loc->second.first].append(element);
52 52
            }
53 53
            catch (const std::invalid_argument&) {
54 -
                (*jMap)[loc->second].append(Json::Value{});
54 +
                (*jMap)[loc->second.first].append(Json::Value{});
55 55
            }
56 56
        }
57 57
@@ -62,6 +62,17 @@
Loading
62 62
    return false;
63 63
}
64 64
65 +
bool JsonMapBuilder::clearComponents(int32_t code)
66 +
{
67 +
    for (auto b = missing_components.begin(); b != missing_components.end(); ++b) {
68 +
        if (b->second.second == code) {
69 +
            missing_components.erase(b);
70 +
            return missing_components.empty();
71 +
        }
72 +
    }
73 +
    return false;
74 +
}
75 +
65 76
std::string JsonMapBuilder::generate()
66 77
{
67 78
    if (jMap) {
@@ -84,7 +95,7 @@
Loading
84 95
{
85 96
    stringVector res = gmlc::utilities::stringOps::splitline(
86 97
        path, "\\/:.", gmlc::utilities::stringOps::delimiter_compression::on);
87 -
    auto jv = &getJValue();
98 +
    auto* jv = &getJValue();
88 99
    size_t ii = 0;
89 100
    for (ii = 0; ii < res.size() - 1; ++ii) {
90 101
        auto& sub = (*jv)[res[ii]];
@@ -100,7 +111,7 @@
Loading
100 111
{
101 112
    stringVector res = gmlc::utilities::stringOps::splitline(
102 113
        path, "\\/:.", gmlc::utilities::stringOps::delimiter_compression::on);
103 -
    auto jv = &getJValue();
114 +
    auto* jv = &getJValue();
104 115
    size_t ii = 0;
105 116
    for (ii = 0; ii < res.size() - 1; ++ii) {
106 117
        auto& sub = (*jv)[res[ii]];
@@ -116,7 +127,7 @@
Loading
116 127
{
117 128
    stringVector res = gmlc::utilities::stringOps::splitline(
118 129
        path, "\\/:.", gmlc::utilities::stringOps::delimiter_compression::on);
119 -
    auto jv = &getJValue();
130 +
    auto* jv = &getJValue();
120 131
    size_t ii = 0;
121 132
    for (ii = 0; ii < res.size() - 1; ++ii) {
122 133
        auto& sub = (*jv)[res[ii]];
@@ -126,7 +137,7 @@
Loading
126 137
        jv = &(*jv)[res[ii]];
127 138
    }
128 139
    (*jv)[res.back()] = Json::arrayValue;
129 -
    for (auto& v : value) {
140 +
    for (const auto& v : value) {
130 141
        (*jv)[res.back()].append(v);
131 142
    }
132 143
}

@@ -594,7 +594,7 @@
Loading
594 594
    // Returns a bad request response
595 595
    auto const not_found = [&req](beast::string_view why) {
596 596
        http::response<http::string_body> res{http::status::not_found, req.version()};
597 -
        res.set(http::field::server, "HELICS_WEB_SERVER" HELICS_VERSION_STRING);
597 +
        res.set(http::field::server, "HELICS_WEB_SERVER " HELICS_VERSION_STRING);
598 598
        res.set(http::field::content_type, "text/html");
599 599
        res.keep_alive(req.keep_alive());
600 600
        res.body() = std::string(why);
@@ -602,49 +602,18 @@
Loading
602 602
        return res;
603 603
    };
604 604
605 -
    // generate the main page
606 -
    auto const main_page = [&req]() {
607 -
        http::response<http::string_body> res{http::status::ok, req.version()};
608 -
        res.set(http::field::server, "HELICS_WEB_SERVER" HELICS_VERSION_STRING);
609 -
        res.set(http::field::content_type, "text/html");
610 -
        res.keep_alive(req.keep_alive());
611 -
        if (req.method() != http::verb::head) {
612 -
            res.body() = index_page;
613 -
            res.prepare_payload();
614 -
        } else {
615 -
            res.set(http::field::content_length, index_page.size());
616 -
        }
617 -
        return res;
618 -
    };
619 -
620 605
    // generate a conversion response
621 -
    auto const response_text = [&req](const std::string& value) {
606 +
    auto const response_ok = [&req](const std::string& resp, beast::string_view content_type) {
622 607
        http::response<http::string_body> res{http::status::ok, req.version()};
623 -
        res.set(http::field::server, "HELICS_WEB_SERVER" HELICS_VERSION_STRING);
624 -
        res.set(http::field::content_type, "text/plain");
625 -
        res.keep_alive(req.keep_alive());
626 -
        if (req.method() != http::verb::head) {
627 -
            res.body() = value;
628 -
            res.prepare_payload();
629 -
        } else {
630 -
            res.set(http::field::content_length, value.size());
631 -
        }
632 -
        return res;
633 -
    };
634 -
635 -
    // generate a conversion response
636 -
    auto const response_json = [&req](const std::string& resp) {
637 -
        http::response<http::string_body> res{http::status::ok, req.version()};
638 -
        res.set(http::field::server, "HELICS_WEB_SERVER" HELICS_VERSION_STRING);
639 -
        res.set(http::field::content_type, "application/json");
608 +
        res.set(http::field::server, "HELICS_WEB_SERVER " HELICS_VERSION_STRING);
609 +
        res.set(http::field::content_type, content_type);
640 610
        res.keep_alive(req.keep_alive());
641 611
        if (req.method() != http::verb::head) {
642 612
            res.body() = resp;
643 613
            res.prepare_payload();
644 614
        } else {
645 -
            res.set(http::field::content_length, resp.size());
615 +
            res.set(http::field::content_length, std::to_string(resp.size()));
646 616
        }
647 -
648 617
        return res;
649 618
    };
650 619
@@ -669,7 +638,7 @@
Loading
669 638
670 639
    beast::string_view target(req.target());
671 640
    if (target == "/index.html" || (target == "/" && !(req.payload_size()))) {
672 -
        return send(main_page());
641 +
        return send(response_ok(index_page, "text/html"));
673 642
    }
674 643
675 644
    auto reqpr = processRequestParameters(target, req.body());
@@ -700,12 +669,12 @@
Loading
700 669
        case return_val::ok:
701 670
        default:
702 671
            if (res.second.empty()) {
703 -
                return send(main_page());
672 +
                return send(response_ok(index_page, "text/html"));
704 673
            }
705 674
            if (res.second.front() == '{') {
706 -
                return send(response_json(res.second));
675 +
                return send(response_ok(res.second, "application/json"));
707 676
            }
708 -
            return send(response_text(res.second));
677 +
            return send(response_ok(res.second, "text/plain"));
709 678
    }
710 679
}
711 680

@@ -198,7 +198,7 @@
Loading
198 198
std::string makePortAddress(const std::string& networkInterface, int portNumber)
199 199
{
200 200
    std::string newAddress = networkInterface;
201 -
    if (portNumber >= 0) {
201 +
    if (portNumber != 0) {
202 202
        newAddress.push_back(':');
203 203
        newAddress.append(std::to_string(portNumber));
204 204
    }

@@ -482,7 +482,8 @@
Loading
482 482
    void sendDisconnect();
483 483
    /** broadcast a message to all federates*/
484 484
    void broadcastToFederates(ActionMessage& cmd);
485 -
485 +
    /** generate a counter for when to reset object*/
486 +
    int generateMapObjectCounter() const;
486 487
    friend class TimeoutMonitor;
487 488
};
488 489

@@ -19,12 +19,14 @@
Loading
19 19
 */
20 20
class HELICS_CXX_EXPORT FederateInfo: public CoreFederateInfo {
21 21
  public:
22 -
    int uniqueKey = 0;  //!< location for keying the info for application purposes
23 -
    char separator = '/';  //!< separator for global name of localFederates
24 -
    bool autobroker =
25 -
        false;  //!< specify that the core should generate a broker if not found otherwise
26 -
    core_type coreType = core_type::DEFAULT;  //!< the type of the core
27 -
    int brokerPort = -1;  //!< broker port information
22 +
    int uniqueKey{0};  //!< location for keying the info for application purposes
23 +
    char separator{'/'};  //!< separator for global name of localFederates
24 +
    bool autobroker{
25 +
        false};  //!< specify that the core should generate a broker if not found otherwise
26 +
    bool debugging{false};  //!< specify that the core/federate should operate in a user debugging
27 +
                            //!< mode which will turn off some timeouts
28 +
    core_type coreType{core_type::DEFAULT};  //!< the type of the core
29 +
    int brokerPort{-1};  //!< broker port information
28 30
29 31
    std::string defName;  //!< a default name to use for a federate
30 32
    std::string coreName;  //!< the name of the core
@@ -93,6 +95,11 @@
Loading
93 95
  */
94 96
    void loadInfoFromJson(const std::string& json, bool runArgParser = true);
95 97
98 +
    /** check if a property has been set and return its value*/
99 +
    Time checkTimeProperty(int propId, Time defVal) const;
100 +
    bool checkFlagProperty(int propId, bool defVal) const;
101 +
    int checkIntProperty(int propId, int defVal) const;
102 +
96 103
  private:
97 104
    std::unique_ptr<helicsCLI11App> makeCLIApp();
98 105
    /** do some additional configuration from config files */

@@ -57,6 +57,7 @@
Loading
57 57
            return estate;
58 58
    }
59 59
}
60 +
60 61
// timeoutMon is a unique_ptr
61 62
CommonCore::CommonCore() noexcept: timeoutMon(new TimeoutMonitor) {}
62 63
@@ -834,6 +835,23 @@
Loading
834 835
835 836
bool CommonCore::getFlagOption(local_federate_id federateID, int32_t flag) const
836 837
{
838 +
    switch (flag) {
839 +
        case defs::flags::enable_init_entry:
840 +
            return (delayInitCounter.load() == 0);
841 +
        case defs::flags::delay_init_entry:
842 +
            return (delayInitCounter.load() != 0);
843 +
        case defs::flags::dumplog:
844 +
        case defs::flags::force_logging_flush:
845 +
        case defs::flags::debugging:
846 +
            return getFlagValue(flag);
847 +
        case defs::flags::forward_compute:
848 +
        case defs::flags::single_thread_federate:
849 +
        case defs::flags::rollback:
850 +
            return false;
851 +
        default:
852 +
            break;
853 +
    }
854 +
837 855
    if (federateID == local_core_id) {
838 856
        return false;
839 857
    }
@@ -987,7 +1005,7 @@
Loading
987 1005
        }
988 1006
    }
989 1007
    return emptyStr;
990 -
}
1008 +
}  // namespace helics
991 1009
992 1010
const std::string& CommonCore::getExtractionUnits(interface_handle handle) const
993 1011
{
@@ -1950,12 +1968,14 @@
Loading
1950 1968
    current_time_map = 2,
1951 1969
    dependency_graph = 3,
1952 1970
    data_flow_graph = 4,
1971 +
    global_state = 6,
1953 1972
};
1954 1973
1955 1974
static const std::map<std::string, std::pair<std::uint16_t, bool>> mapIndex{
1956 1975
    {"global_time", {current_time_map, true}},
1957 1976
    {"dependency_graph", {dependency_graph, false}},
1958 1977
    {"data_flow_graph", {data_flow_graph, false}},
1978 +
    {"global_state", {global_state, true}},
1959 1979
};
1960 1980
1961 1981
void CommonCore::setQueryCallback(local_federate_id federateID,
@@ -2055,14 +2075,13 @@
Loading
2055 2075
        return (fed->init_transmitted.load()) ? "true" : "false";
2056 2076
    }
2057 2077
    if (queryStr == "state") {
2058 -
        return std::to_string(static_cast<int>(fed->getState()));
2078 +
        return fedStateString(fed->getState());
2059 2079
    }
2060 2080
    if (queryStr == "filtered_endpoints") {
2061 2081
        return filteredEndpointQuery(fed);
2062 2082
    }
2063 2083
    if ((queryStr == "queries") || (queryStr == "available_queries")) {
2064 -
        return std::string(
2065 -
                   "[exists;isinit;state;version;queries;filtered_endpoints;current_time;") +
2084 +
        return std::string("[exists;isinit;state;version;queries;filtered_endpoints;") +
2066 2085
            fed->processQuery(queryStr) + "]";
2067 2086
    }
2068 2087
    return fed->processQuery(queryStr);
@@ -2072,7 +2091,7 @@
Loading
2072 2091
{
2073 2092
    if ((queryStr == "queries") || (queryStr == "available_queries")) {
2074 2093
        return "[isinit;isconnected;exists;name;identifier;address;queries;address;federates;inputs;endpoints;filtered_endpoints;"
2075 -
               "publications;filters;version;version_all;federate_map;dependency_graph;data_flow_graph;dependencies;dependson;dependents;current_time;global_time;current_state]";
2094 +
               "publications;filters;version;version_all;counter;federate_map;dependency_graph;data_flow_graph;dependencies;dependson;dependents;current_time;global_time;global_state;current_state]";
2076 2095
    }
2077 2096
    if (queryStr == "isconnected") {
2078 2097
        return (isConnected()) ? "true" : "false";
@@ -2131,7 +2150,8 @@
Loading
2131 2150
    if (loopFederates.size() > 0) {
2132 2151
        base["federates"] = Json::arrayValue;
2133 2152
        for (const auto& fed : loopFederates) {
2134 -
            int brkindex = builder.generatePlaceHolder("federates");
2153 +
            int brkindex =
2154 +
                builder.generatePlaceHolder("federates", fed->global_id.load().baseValue());
2135 2155
            std::string ret = federateQuery(fed.fed, request);
2136 2156
            if (ret == "#wait") {
2137 2157
                queryReq.messageID = brkindex;
@@ -2182,6 +2202,9 @@
Loading
2182 2202
                }
2183 2203
            }
2184 2204
            break;
2205 +
        case global_state:
2206 +
            base["state"] = brokerStateName(brokerState.load());
2207 +
            break;
2185 2208
        default:
2186 2209
            break;
2187 2210
    }
@@ -2242,6 +2265,9 @@
Loading
2242 2265
    if (queryStr == "address") {
2243 2266
        return getAddress();
2244 2267
    }
2268 +
    if (queryStr == "counter") {
2269 +
        return fmt::format("{}", generateMapObjectCounter());
2270 +
    }
2245 2271
    if (queryStr == "filtered_endpoints") {
2246 2272
        return filteredEndpointQuery(nullptr);
2247 2273
    }
@@ -2270,16 +2296,25 @@
Loading
2270 2296
    if (mi != mapIndex.end()) {
2271 2297
        auto index = mi->second.first;
2272 2298
        if (isValidIndex(index, mapBuilders) && !mi->second.second) {
2273 -
            if (std::get<0>(mapBuilders[index]).isCompleted()) {
2274 -
                return std::get<0>(mapBuilders[index]).generate();
2299 +
            auto& builder = std::get<0>(mapBuilders[index]);
2300 +
            if (builder.isCompleted()) {
2301 +
                auto center = generateMapObjectCounter();
2302 +
                if (center == builder.getCounterCode()) {
2303 +
                    return builder.generate();
2304 +
                }
2305 +
                builder.reset();
2275 2306
            }
2276 -
            if (std::get<0>(mapBuilders[index]).isActive()) {
2307 +
            if (builder.isActive()) {
2277 2308
                return "#wait";
2278 2309
            }
2279 2310
        }
2280 2311
2281 2312
        initializeMapBuilder(queryStr, index, mi->second.second);
2282 2313
        if (std::get<0>(mapBuilders[index]).isCompleted()) {
2314 +
            if (!mi->second.second) {
2315 +
                auto center = generateMapObjectCounter();
2316 +
                std::get<0>(mapBuilders[index]).setCounterCode(center);
2317 +
            }
2283 2318
            return std::get<0>(mapBuilders[index]).generate();
2284 2319
        }
2285 2320
        return "#wait";
@@ -2598,7 +2633,7 @@
Loading
2598 2633
2599 2634
        } break;
2600 2635
        case CMD_QUERY_REPLY:
2601 -
            if (command.dest_id == global_broker_id_local) {
2636 +
            if (command.dest_id == global_broker_id_local || command.dest_id == direct_core_id) {
2602 2637
                processQueryResponse(command);
2603 2638
            } else {
2604 2639
                transmit(getRoute(command.dest_id), command);
@@ -3627,6 +3662,8 @@
Loading
3627 3662
            requestors.clear();
3628 3663
            if (std::get<2>(mapBuilders[m.counter])) {
3629 3664
                builder.reset();
3665 +
            } else {
3666 +
                builder.setCounterCode(generateMapObjectCounter());
3630 3667
            }
3631 3668
        }
3632 3669
    }
@@ -3830,6 +3867,9 @@
Loading
3830 3867
        case defs::flags::slow_responding:
3831 3868
            no_ping = checkActionFlag(cmd, indicator_flag);
3832 3869
            break;
3870 +
        case defs::flags::debugging:
3871 +
            debugging = no_ping = checkActionFlag(cmd, indicator_flag);
3872 +
            break;
3833 3873
        case UPDATE_LOGGING_CALLBACK:
3834 3874
            if (checkActionFlag(cmd, empty_flag)) {
3835 3875
                setLoggerFunction(nullptr);
@@ -3961,6 +4001,16 @@
Loading
3961 4001
    return false;
3962 4002
}
3963 4003
4004 +
int CommonCore::generateMapObjectCounter() const
4005 +
{
4006 +
    int result = static_cast<int>(brokerState.load());
4007 +
    for (const auto& fed : loopFederates) {
4008 +
        result += static_cast<int>(fed.state);
4009 +
    }
4010 +
    result += static_cast<int>(loopHandles.size());
4011 +
    return result;
4012 +
}
4013 +
3964 4014
void CommonCore::sendDisconnect()
3965 4015
{
3966 4016
    LOG_CONNECTIONS(global_broker_id_local, "core", "sending disconnect");

@@ -8,6 +8,7 @@
Loading
8 8
#include <map>
9 9
#include <memory>
10 10
#include <string>
11 +
#include <utility>
11 12
#include <vector>
12 13
13 14
namespace Json {
@@ -19,8 +20,8 @@
Loading
19 20
class JsonMapBuilder {
20 21
  private:
21 22
    std::unique_ptr<Json::Value> jMap;
22 -
    std::map<int, std::string> missing_components;
23 -
23 +
    std::map<int, std::pair<std::string, int32_t>> missing_components;
24 +
    int counterCode{0};  // a code for the user to include for various purposes
24 25
  public:
25 26
    JsonMapBuilder() noexcept;
26 27
    ~JsonMapBuilder();
@@ -40,11 +41,15 @@
Loading
40 41
    bool addComponent(const std::string& info, int index) noexcept;
41 42
    /** generate a new location to fill in later
42 43
    @return the index value of the location for use in addComponent*/
43 -
    int generatePlaceHolder(const std::string& location);
44 +
    int generatePlaceHolder(const std::string& location, int32_t code);
44 45
    /** generate the JSON value*/
46 +
    bool clearComponents(int32_t code);
45 47
    std::string generate();
46 48
    /** reset the builder*/
47 49
    void reset();
50 +
    /** set the counter code value*/
51 +
    void setCounterCode(int code) { counterCode = code; }
52 +
    int getCounterCode() const { return counterCode; }
48 53
};
49 54
50 55
/** class to help with the generation of JSON*/

@@ -722,6 +722,7 @@
Loading
722 722
    return until the query is answered so use with caution
723 723
    */
724 724
    virtual std::string query(const std::string& target, const std::string& queryStr) = 0;
725 +
725 726
    /** supply a query callback function
726 727
    @details the intention of the query callback is to allow federates to answer particular requests
727 728
    through the query interface this allows other federates to make requests or queries of other
@@ -733,14 +734,16 @@
Loading
733 734
    */
734 735
    virtual void setQueryCallback(local_federate_id federateID,
735 736
                                  std::function<std::string(const std::string&)> queryFunction) = 0;
737 +
736 738
    /**
737 739
     * setter for the interface information
738 740
     * @param handle the identifiers for the interface to set the info data on
739 741
     * @param info a string containing the info data
740 742
     */
741 743
    virtual void setInterfaceInfo(interface_handle handle, std::string info) = 0;
744 +
742 745
    /**
743 -
     * gett for the interface information
746 +
     * getter for the interface information
744 747
     * @param handle the identifiers for the interface to query
745 748
     * @return a string containing the Info data stored in an interface
746 749
     */

@@ -990,6 +990,15 @@
Loading
990 990
    mess->data.append(static_cast<const char*>(data), inputDataLength);
991 991
}
992 992
993 +
void helicsMessageClear(helics_message_object message, helics_error* err)
994 +
{
995 +
    auto* mess = getMessageObj(message, err);
996 +
    if (mess == nullptr) {
997 +
        return;
998 +
    }
999 +
    mess->clear();
1000 +
}
1001 +
993 1002
void helicsMessageCopy(helics_message_object source_message, helics_message_object dest_message, helics_error* err)
994 1003
{
995 1004
    auto* mess_src = getMessageObj(source_message, err);

@@ -19,6 +19,7 @@
Loading
19 19
#include <iostream>
20 20
#include <map>
21 21
#include <set>
22 +
#include <unordered_map>
22 23
#include <utility>
23 24
24 25
namespace helics {
@@ -37,51 +38,80 @@
Loading
37 38
    loadInfoFromArgsIgnoreOutput(args);
38 39
}
39 40
40 -
static const std::map<std::string, int> propStringsTranslations{
41 +
static const std::unordered_map<std::string, int> propStringsTranslations{
41 42
    {"period", helics_property_time_period},
43 +
    {"timeperiod", helics_property_time_period},
44 +
    {"time_period", helics_property_time_period},
42 45
    {"timedelta", helics_property_time_delta},
43 46
    {"time_delta", helics_property_time_delta},
44 47
    {"timeDelta", helics_property_time_delta},
45 48
    {"delta", helics_property_time_delta},
46 49
    {"offset", helics_property_time_offset},
50 +
    {"timeoffset", helics_property_time_offset},
51 +
    {"time_offset", helics_property_time_offset},
47 52
    {"rtlead", helics_property_time_rt_lead},
48 53
    {"rtlag", helics_property_time_rt_lag},
49 54
    {"rttolerance", helics_property_time_rt_tolerance},
55 +
    {"timertlead", helics_property_time_rt_lead},
56 +
    {"timertlag", helics_property_time_rt_lag},
57 +
    {"timerttolerance", helics_property_time_rt_tolerance},
50 58
    {"rtLead", helics_property_time_rt_lead},
51 59
    {"rtLag", helics_property_time_rt_lag},
52 60
    {"rtTolerance", helics_property_time_rt_tolerance},
53 61
    {"rt_lead", helics_property_time_rt_lead},
54 62
    {"rt_lag", helics_property_time_rt_lag},
55 63
    {"rt_tolerance", helics_property_time_rt_tolerance},
64 +
    {"time_rt_lead", helics_property_time_rt_lead},
65 +
    {"time_rt_lag", helics_property_time_rt_lag},
66 +
    {"time_rt_tolerance", helics_property_time_rt_tolerance},
56 67
    {"inputdelay", helics_property_time_input_delay},
57 68
    {"outputdelay", helics_property_time_output_delay},
58 69
    {"inputDelay", helics_property_time_input_delay},
59 70
    {"outputDelay", helics_property_time_output_delay},
60 71
    {"input_delay", helics_property_time_input_delay},
61 72
    {"output_delay", helics_property_time_output_delay},
62 -
    {"max_iterations", helics_property_int_max_iterations},
73 +
    {"timeinputdelay", helics_property_time_input_delay},
74 +
    {"timeoutputdelay", helics_property_time_output_delay},
75 +
    {"time_input_delay", helics_property_time_input_delay},
76 +
    {"time_output_delay", helics_property_time_output_delay},
63 77
    {"loglevel", helics_property_int_log_level},
64 78
    {"log_level", helics_property_int_log_level},
65 -
    {"maxiterations", helics_property_int_max_iterations},
66 79
    {"logLevel", helics_property_int_log_level},
80 +
    {"intloglevel", helics_property_int_log_level},
81 +
    {"int_log_level", helics_property_int_log_level},
82 +
    {"consoleloglevel", helics_property_int_console_log_level},
83 +
    {"console_log_level", helics_property_int_console_log_level},
84 +
    {"intconsoleloglevel", helics_property_int_console_log_level},
85 +
    {"int_console_log_level", helics_property_int_console_log_level},
86 +
    {"fileloglevel", helics_property_int_file_log_level},
87 +
    {"file_log_level", helics_property_int_file_log_level},
88 +
    {"intfileloglevel", helics_property_int_file_log_level},
89 +
    {"int_file_log_level", helics_property_int_file_log_level},
90 +
    {"maxiterations", helics_property_int_max_iterations},
91 +
    {"max_iterations", helics_property_int_max_iterations},
67 92
    {"maxIterations", helics_property_int_max_iterations},
93 +
    {"intmaxiterations", helics_property_int_max_iterations},
94 +
    {"int_max_iterations", helics_property_int_max_iterations},
68 95
    {"iterations", helics_property_int_max_iterations}};
69 96
70 -
static const std::map<std::string, int> flagStringsTranslations{
97 +
static const std::unordered_map<std::string, int> flagStringsTranslations{
71 98
    {"source_only", helics_flag_source_only},
72 99
    {"sourceonly", helics_flag_source_only},
73 100
    {"sourceOnly", helics_flag_source_only},
74 101
    {"source", helics_flag_source_only},
102 +
    {"observer", helics_flag_observer},
75 103
    {"slow", helics_flag_slow_responding},
76 104
    {"slow_response", helics_flag_slow_responding},
77 105
    {"slow_responding", helics_flag_slow_responding},
78 106
    {"slowResponding", helics_flag_slow_responding},
79 107
    {"no_ping", helics_flag_slow_responding},
80 108
    {"disable_ping", helics_flag_slow_responding},
109 +
    {"debugging", helics_flag_debugging},
81 110
    {"only_update_on_change", helics_flag_only_update_on_change},
82 111
    {"only_transmit_on_change", helics_flag_only_transmit_on_change},
83 112
    {"forward_compute", helics_flag_forward_compute},
84 113
    {"realtime", helics_flag_realtime},
114 +
    {"real_time", helics_flag_realtime},
85 115
    {"realTime", helics_flag_realtime},
86 116
    {"restrictive_time_policy", helics_flag_restrictive_time_policy},
87 117
    {"conservative_time_policy", helics_flag_restrictive_time_policy},
@@ -93,20 +123,39 @@
Loading
93 123
    {"delayed_update", helics_flag_wait_for_current_time_update},
94 124
    {"delayedUpdate", helics_flag_wait_for_current_time_update},
95 125
    {"strict_input_type_checking", helics_handle_option_strict_type_checking},
126 +
    {"strict_config_checking", helics_flag_strict_config_checking},
127 +
    {"strictconfigchecking", helics_flag_strict_config_checking},
128 +
    {"strictConfigChecking", helics_flag_strict_config_checking},
96 129
    {"ignore_unit_mismatch", helics_handle_option_ignore_unit_mismatch},
97 130
    {"buffer_data", helics_handle_option_buffer_data},
98 131
    {"bufferData", helics_handle_option_buffer_data},
99 132
    {"required", helics_handle_option_connection_required},
100 133
    {"optional", helics_handle_option_connection_optional},
134 +
    {"nointerrupts", helics_flag_uninterruptible},
135 +
    {"no_interrupts", helics_flag_uninterruptible},
136 +
    {"uninterruptible", helics_flag_uninterruptible},
137 +
    {"interruptible", helics_flag_interruptible},
101 138
    {"wait_for_current_time", helics_flag_wait_for_current_time_update},
102 139
    {"wait_for_current_time_update", helics_flag_wait_for_current_time_update},
103 140
    {"waitforcurrenttimeupdate", helics_flag_wait_for_current_time_update},
104 141
    {"waitforcurrenttime", helics_flag_wait_for_current_time_update},
142 +
    {"delay_init_entry", helics_flag_delay_init_entry},
143 +
    {"delayinitentry", helics_flag_delay_init_entry},
144 +
    {"enable_init_entry", helics_flag_enable_init_entry},
145 +
    {"enableinitentry", helics_flag_enable_init_entry},
146 +
    {"ignore_time_mismatch_warnings", helics_flag_ignore_time_mismatch_warnings},
147 +
    {"ignoretimemismatchwarnings", helics_flag_ignore_time_mismatch_warnings},
148 +
    {"rollback", helics_flag_rollback},
149 +
    {"single_thread_federate", helics_flag_single_thread_federate},
150 +
    {"singlethreadfederate", helics_flag_single_thread_federate},
151 +
    {"force_logging_flush", helics_flag_force_logging_flush},
152 +
    {"forceloggingflush", helics_flag_force_logging_flush},
153 +
    {"dumplog", helics_flag_dumplog},
105 154
    {"terminate_on_error", helics_flag_terminate_on_error},
106 155
    {"terminateOnError", helics_flag_terminate_on_error},
107 156
    {"terminateonerror", helics_flag_terminate_on_error}};
108 157
109 -
static const std::map<std::string, int> optionStringsTranslations{
158 +
static const std::unordered_map<std::string, int> optionStringsTranslations{
110 159
    {"buffer", helics_handle_option_buffer_data},
111 160
    {"buffer_data", helics_handle_option_buffer_data},
112 161
    {"bufferdata", helics_handle_option_buffer_data},
@@ -208,6 +257,9 @@
Loading
208 257
            fi.autobroker = true;
209 258
            continue;
210 259
        }
260 +
        if (flg == "debugging") {
261 +
            fi.debugging = true;
262 +
        }
211 263
        if (flg.empty()) {
212 264
            continue;  // LCOV_EXCL_LINE
213 265
        }
@@ -390,6 +442,9 @@
Loading
390 442
    app->add_flag("--autobroker",
391 443
                  autobroker,
392 444
                  "tell the core to automatically generate a broker if needed");
445 +
    app->add_flag("--debugging",
446 +
                  debugging,
447 +
                  "tell the core to allow user debugging in a nicer fashion");
393 448
    app->add_option("--key,--broker_key",
394 449
                    key,
395 450
                    "specify a key to use to match a broker should match the broker key");
@@ -561,6 +616,36 @@
Loading
561 616
    return ret;
562 617
}
563 618
619 +
Time FederateInfo::checkTimeProperty(int propId, Time defVal) const
620 +
{
621 +
    for (const auto& tp : timeProps) {
622 +
        if (tp.first == propId) {
623 +
            return tp.second;
624 +
        }
625 +
    }
626 +
    return defVal;
627 +
}
628 +
629 +
bool FederateInfo::checkFlagProperty(int propId, bool defVal) const
630 +
{
631 +
    for (const auto& tp : flagProps) {
632 +
        if (tp.first == propId) {
633 +
            return tp.second;
634 +
        }
635 +
    }
636 +
    return defVal;
637 +
}
638 +
639 +
int FederateInfo::checkIntProperty(int propId, int defVal) const
640 +
{
641 +
    for (const auto& tp : intProps) {
642 +
        if (tp.first == propId) {
643 +
            return tp.second;
644 +
        }
645 +
    }
646 +
    return defVal;
647 +
}
648 +
564 649
void FederateInfo::loadInfoFromJson(const std::string& jsonString, bool runArgParser)
565 650
{
566 651
    Json::Value doc;
@@ -673,7 +758,9 @@
Loading
673 758
    if (fi.autobroker) {
674 759
        res.append(" --autobroker");
675 760
    }
676 -
761 +
    if (fi.debugging) {
762 +
        res.append(" --debugging");
763 +
    }
677 764
    if (!fi.brokerInitString.empty()) {
678 765
        res.append(" --brokerinit \"");
679 766
        res.append(fi.brokerInitString);
Files Coverage
src/helics 77.19%
Project Totals (210 files) 77.19%
13036.9
TRAVIS_OS_NAME=linux
13035.9
TRAVIS_OS_NAME=linux
13038.9
TRAVIS_OS_NAME=linux
13037.9
TRAVIS_OS_NAME=linux
13002.9
TRAVIS_OS_NAME=linux
12998.9
TRAVIS_OS_NAME=linux