NRP Core  1.4.1
engine_client_interface.h
Go to the documentation of this file.
1 /* * NRP Core - Backend infrastructure to synchronize simulations
2  *
3  * Copyright 2020-2023 NRP Team
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * This project has received funding from the European Union’s Horizon 2020
18  * Framework Programme for Research and Innovation under the Specific Grant
19  * Agreement No. 945539 (Human Brain Project SGA3).
20  */
21 
22 #ifndef ENGINE_CLIENT_INTERFACE_H
23 #define ENGINE_CLIENT_INTERFACE_H
24 
31 
32 #include <set>
33 #include <vector>
34 #include <future>
35 
38 
39 
44  : public PtrTemplates<EngineClientInterface>
45 {
46  public:
48  virtual ~EngineClientInterface();
49 
54  virtual const std::string engineName() const = 0;
55 
59  virtual const nlohmann::json &engineConfig() const = 0;
60 
64  virtual nlohmann::json &engineConfig() = 0;
65 
69  virtual const std::vector<std::string> engineProcStartParams() const = 0;
70 
75  virtual pid_t launchEngine();
76 
82  virtual void initialize() = 0;
83 
89  virtual void reset() = 0;
90 
96  virtual void shutdown() = 0;
97 
102  virtual SimulationTime getEngineTimestep() const = 0;
103 
108  virtual SimulationTime getEngineTime() const = 0;
109 
115  virtual const std::string engineSchema() const = 0;
116 
125  virtual void runLoopStepAsync(SimulationTime timeStep) = 0;
126 
135  virtual void runLoopStepAsyncGet(SimulationTime timeOut) = 0;
136 
143  virtual void sendDataPacksToEngine(const datapacks_set_t &dataPacks) = 0;
144 
151  virtual datapacks_vector_t getDataPacksFromEngine(const datapack_identifiers_set_t &datapackIdentifiers) = 0;
152 
153 protected:
154 
159 };
160 
163 
165  : public PtrTemplates<EngineLauncherInterface>
166 {
167  public:
169 
171  virtual ~EngineLauncherInterface() = default;
172 
173  const engine_type_t &engineType() const;
175 
176  private:
180  const engine_type_t _engineType;
181 };
182 
185 
190 template<class ENGINE, const char *SCHEMA>
192  : public EngineClientInterface
193 {
194  public:
195  using engine_t = ENGINE;
196 
201  template<const char *ENGINE_TYPE>
203  : public EngineLauncherInterface
204  {
205  public:
207  : EngineLauncherInterface(ENGINE_TYPE)
208  {}
209 
212  {}
213 
214  ~EngineLauncher() override = default;
215 
223  {
224  EngineClientInterfaceSharedPtr engine(new ENGINE(engineConfig, std::move(launcher)));
225 
226  switch (engine->launchEngine())
227  {
228  case 0: { // TODO: process not forked (error)
230  "\"{}\" Engine (type: \"{}\") could NOT be launched.", engine->engineName(), this->engineType());
231  }; break;
232  case -1: { // process not forked (empty launcher, expected behaviour)
234  "\"{}\" EngineClient (type: \"{}\") won't launch an EngineServer. Assume it's already been launched.", engine->engineName(), this->engineType());
235  }; break;
236  default: { // success
238  "\"{}\" Engine (type: \"{}\") launched successfully", engine->engineName(), this->engineType());
239  }; break;
240  };
241 
242  return engine;
243  }
244  };
245 
252  : EngineClientInterface(std::move(launcher)),
253  engineConfig_(engineConfig)
254  {
255  // validate engine config
257 
258  // setting process start and env params to an empty vector since this can't be done from json schema
259  setDefaultProperty<std::vector<std::string>>("EngineProcStartParams", std::vector<std::string>());
260  setDefaultProperty<std::vector<std::string>>("EngineEnvParams", std::vector<std::string>());
261  setDefaultProperty<nlohmann::json>("EngineExtraConfigs", nlohmann::json(json::value_t::object));
262  }
263 
264  ~EngineClient() override = default;
265 
266  const std::string engineName() const override final
267  { return this->engineConfig().at("EngineName"); }
268 
269  SimulationTime getEngineTimestep() const override final
270  {
271  // We need to cast floating-point seconds to integers with units of SimulationTime type
272  return toSimulationTime<float, std::ratio<1>>(this->engineConfig().at("EngineTimestep"));
273  }
274 
278  const nlohmann::json &engineConfig() const override final
279  { return engineConfig_; }
280 
284  nlohmann::json &engineConfig() override final
285  { return engineConfig_; }
286 
290  const std::string engineSchema() const override final
291  { return schema; }
292 
300  SimulationTime getEngineTime() const override
301  {
302  return this->_engineTime;
303  }
304 
316  void runLoopStepAsync(SimulationTime timeStep) override
317  {
318  if(this->_loopStepThread.valid())
319  {
320  throw NRPException::logCreate("Engine \"" + this->engineName() + "\" runLoopStepAsync has overrun");
321  }
322 
323  this->_loopStepThread = std::async(std::launch::async, std::bind(&EngineClient::runLoopStepCallback, this, timeStep));
324  }
325 
337  void runLoopStepAsyncGet(SimulationTime timeOut) override
338  {
339  NRP_LOGGER_TRACE("{} called", __FUNCTION__);
340 
341  // If thread state is invalid, loop thread has completed and runLoopStepAsyncGet was called once before
342  if(!this->_loopStepThread.valid())
343  return;
344 
345  // Wait until timeOut has passed
346  if(timeOut > SimulationTime::zero())
347  {
348  if(this->_loopStepThread.wait_for(timeOut) != std::future_status::ready)
349  throw NRPException::logCreate("Engine \"" + this->engineName() + "\" loop is taking too long to complete");
350  }
351 
352  // Retrieve the engine time returned from the loop step
353 
354  this->_engineTime = this->_loopStepThread.get();
355  }
356 
357  protected:
358 
359  virtual void resetEngineTime()
360  {
361  this->_engineTime = SimulationTime(0);
362  }
363 
370  template<class T>
371  void setDefaultProperty(std::string key, T value)
372  {
373  json_utils::setDefault<T>(this->engineConfig(), key, value);
374  }
375 
386  virtual SimulationTime runLoopStepCallback(SimulationTime timeStep) = 0;
387 
388  private:
389 
390  nlohmann::json engineConfig_;
391  std::string schema = std::string(SCHEMA);
395  std::future<SimulationTime> _loopStepThread;
396 
400  SimulationTime _engineTime = SimulationTime::zero();
401 };
402 
403 #endif // ENGINE_CLIENT_INTERFACE_H
EngineClientInterface::getDataPacksFromEngine
virtual datapacks_vector_t getDataPacksFromEngine(const datapack_identifiers_set_t &datapackIdentifiers)=0
Gets requested datapacks from engine.
datapacks_vector_t
std::vector< std::shared_ptr< const DataPackInterface > > datapacks_vector_t
Definition: datapack_interface.h:220
EngineClientInterface::shutdown
virtual void shutdown()=0
Shutdown engine.
EngineClient::engineConfig
nlohmann::json & engineConfig() override final
Get Engine Configuration.
Definition: engine_client_interface.h:284
EngineClientInterface::launchEngine
virtual pid_t launchEngine()
Launch the engine.
Definition: engine_client_interface.cpp:31
fixed_string.h
datapacks_set_t
std::set< std::shared_ptr< const DataPackInterface >, DataPackPointerComparator > datapacks_set_t
Definition: datapack_interface.h:219
PtrTemplates< ProcessLauncherInterface >::unique_ptr
std::unique_ptr< ProcessLauncherInterface > unique_ptr
Definition: ptr_templates.h:34
EngineClientInterface::~EngineClientInterface
virtual ~EngineClientInterface()
EngineLauncherInterface::engine_type_t
decltype(DataPackIdentifier::Type) engine_type_t
Definition: engine_client_interface.h:168
json_utils::validateJson
void validateJson(nlohmann::json &instance, std::string schema_path, bool addPatch)
Validates a json object using a given json schema.
Definition: json_schema_utils.cpp:65
DataPackIdentifier::Type
std::string Type
DataPack Type.
Definition: datapack_interface.h:54
EngineClientInterface::sendDataPacksToEngine
virtual void sendDataPacksToEngine(const datapacks_set_t &dataPacks)=0
Sends datapacks to engine.
EngineClientInterface::runLoopStepAsyncGet
virtual void runLoopStepAsyncGet(SimulationTime timeOut)=0
Waits and gets the results of the loop step started by EngineClientInterface::runLoopStepAsync()
EngineClient::runLoopStepAsync
void runLoopStepAsync(SimulationTime timeStep) override
Concrete implementation of EngineClientInterface::runLoopStepAsync()
Definition: engine_client_interface.h:316
EngineClient::engineName
const std::string engineName() const override final
Get Engine Name.
Definition: engine_client_interface.h:266
EngineClient::~EngineClient
~EngineClient() override=default
process_launcher.h
datapack_interface.h
EngineClientInterface
Interface to engines.
Definition: engine_client_interface.h:43
EngineClientInterface::_process
ProcessLauncherInterface::unique_ptr _process
Process Launcher. Will be used to stop process at end.
Definition: engine_client_interface.h:158
EngineClientInterface::getEngineTime
virtual SimulationTime getEngineTime() const =0
Get current engine time.
EngineClientInterface::reset
virtual void reset()=0
Reset engine.
EngineClient
Base class for all Engines.
Definition: engine_client_interface.h:191
EngineLauncherInterface::EngineLauncherInterface
EngineLauncherInterface(const engine_type_t &engineType)
Definition: engine_client_interface.cpp:43
PtrTemplates< EngineClientInterface >::const_shared_ptr
std::shared_ptr< const EngineClientInterface > const_shared_ptr
Definition: ptr_templates.h:32
EngineClientInterface::engineConfig
virtual const nlohmann::json & engineConfig() const =0
Get engine config data.
EngineClient::EngineLauncher::EngineLauncher
EngineLauncher(const engine_type_t &engineType)
Definition: engine_client_interface.h:210
EngineClient::engineConfig
const nlohmann::json & engineConfig() const override final
Get Engine Configuration.
Definition: engine_client_interface.h:278
EngineClient::getEngineTimestep
SimulationTime getEngineTimestep() const override final
Get engine timestep.
Definition: engine_client_interface.h:269
NRPLogger::info
static void info(const FormatString &fmt, const Args &...args)
NRP logging function with message formatting for info level.
Definition: nrp_logger.h:138
EngineClient::runLoopStepAsyncGet
void runLoopStepAsyncGet(SimulationTime timeOut) override
Concrete implementation of EngineClientInterface::runLoopStepAsyncGet()
Definition: engine_client_interface.h:337
EngineClientInterface::getEngineTimestep
virtual SimulationTime getEngineTimestep() const =0
Get engine timestep.
EngineClient::runLoopStepCallback
virtual SimulationTime runLoopStepCallback(SimulationTime timeStep)=0
Executes a single loop step.
PythonEngineGRPCNRPClient
PythonGRPCEngine client.
Definition: python_engine_grpc_nrp_client.h:48
datapack_identifiers_set_t
std::set< DataPackIdentifier > datapack_identifiers_set_t
Definition: datapack_interface.h:221
EngineClient::EngineLauncher::~EngineLauncher
~EngineLauncher() override=default
EngineClientInterface::initialize
virtual void initialize()=0
Initialize engine.
EngineClientInterfaceConstSharedPtr
EngineClientInterface::const_shared_ptr EngineClientInterfaceConstSharedPtr
Definition: engine_client_interface.h:162
EngineLauncherInterface::launchEngine
virtual EngineClientInterfaceSharedPtr launchEngine(nlohmann::json &engineConfig, ProcessLauncherInterface::unique_ptr &&launcher)=0
EngineClient::engineSchema
const std::string engineSchema() const override final
Get json schema for this engine type.
Definition: engine_client_interface.h:290
EngineClient::EngineLauncher::EngineLauncher
EngineLauncher()
Definition: engine_client_interface.h:206
PtrTemplates
Definition: ptr_templates.h:28
EngineClient::resetEngineTime
virtual void resetEngineTime()
Definition: engine_client_interface.h:359
ptr_templates.h
NRPException::logCreate
static EXCEPTION logCreate(LOG_EXCEPTION_T &exception, const std::string &msg, NRPLogger::spdlog_out_fcn_t spdlogCall=NRPLogger::critical)
Definition: nrp_exceptions.h:73
EngineClientInterface::engineSchema
virtual const std::string engineSchema() const =0
Get json schema for this specific engine type.
json_schema_utils.h
time_utils.h
PtrTemplates< EngineClientInterface >::shared_ptr
std::shared_ptr< EngineClientInterface > shared_ptr
Definition: ptr_templates.h:31
EngineClient::setDefaultProperty
void setDefaultProperty(std::string key, T value)
Attempts to set a default value for a property in the engine configuration. If the property has been ...
Definition: engine_client_interface.h:371
EngineLauncherInterfaceConstSharedPtr
EngineLauncherInterface::const_shared_ptr EngineLauncherInterfaceConstSharedPtr
Definition: engine_client_interface.h:184
EngineClient::EngineLauncher
Class for launching engine.
Definition: engine_client_interface.h:202
EngineClientInterface::runLoopStepAsync
virtual void runLoopStepAsync(SimulationTime timeStep)=0
Starts a single loop step in a separate thread.
EngineLauncherInterfaceSharedPtr
EngineLauncherInterface::shared_ptr EngineLauncherInterfaceSharedPtr
Definition: engine_client_interface.h:183
EngineClientInterface::engineName
virtual const std::string engineName() const =0
Get Engine Name.
NRPLogger::error
static void error(const FormatString &fmt, const Args &...args)
NRP logging function with message formatting for error level.
Definition: nrp_logger.h:160
EngineClientInterfaceSharedPtr
EngineClientInterface::shared_ptr EngineClientInterfaceSharedPtr
Definition: engine_client_interface.h:161
EngineLauncherInterface::~EngineLauncherInterface
virtual ~EngineLauncherInterface()=default
EngineClient::getEngineTime
SimulationTime getEngineTime() const override
Returns current engine (simulation) time.
Definition: engine_client_interface.h:300
EngineLauncherInterface
Definition: engine_client_interface.h:164
EngineLauncherInterface::engineType
const engine_type_t & engineType() const
Definition: engine_client_interface.cpp:47
EngineClient::EngineClient
EngineClient(nlohmann::json &engineConfig, ProcessLauncherInterface::unique_ptr &&launcher)
Constructor.
Definition: engine_client_interface.h:251
EngineClient::EngineLauncher::launchEngine
EngineClientInterfaceSharedPtr launchEngine(nlohmann::json &engineConfig, ProcessLauncherInterface::unique_ptr &&launcher) override
Launches an engine. Configures config and forks a new child process for the engine.
Definition: engine_client_interface.h:222
EngineClientInterface::EngineClientInterface
EngineClientInterface(ProcessLauncherInterface::unique_ptr &&launcher)
Definition: engine_client_interface.cpp:25
SimulationTime
std::chrono::nanoseconds SimulationTime
Definition: time_utils.h:31
EngineClientInterface::engineProcStartParams
virtual const std::vector< std::string > engineProcStartParams() const =0
Get all Engine Process Startup parameters.
NRP_LOGGER_TRACE
#define NRP_LOGGER_TRACE(...)
trace log macro. It is voided by defining \PRODUCTION_RELEASE
Definition: nrp_logger.h:39
json
nlohmann::json json
Definition: engine_json_server.cpp:31