From ae588d89554ab5651e744b58f51b878a93151472 Mon Sep 17 00:00:00 2001 From: Geir Horn Date: Wed, 10 Jan 2024 16:26:09 +0100 Subject: [PATCH] First release - Added build script and AMPL license file - Fixed merge errors for the makefile - Extended the makefile header - Added initial AMQ message topics - Tested remote build - Removed AMPL license file - Validated build script - Accepting the metric definition message from the EMS - Execution control status messages + solver type command line option - Executing solver component Change-Id: I3972b7e24a65eae8555aa60404d5f75cb4fc0705 --- .vscode/c_cpp_properties.json | 4 +-- AMPLSolver.cpp | 14 ++++++-- AMPLSolver.hpp | 15 ++++---- ExecutionControl.cpp | 20 +++++++++-- ExecutionControl.hpp | 68 ++++++++++++++++++++++++++++++++++- SolverComponent.cpp | 47 ++++++++++++++++-------- SolverManager.hpp | 4 +++ 7 files changed, 144 insertions(+), 28 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index d70a9a5..acf1e67 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -10,7 +10,8 @@ "/home/GHo/Documents/Code/Theron++/Communication", "/home/GHo/Documents/Code/Theron++/Communication/AMQ", "/opt/AMPL/amplapi/include/ampl", - "${workspaceFolder}/**" + "${workspaceFolder}/**", + "/home/GHo/Documents/Code/Theron++" ], "defines": [], "cStandard": "c23", @@ -23,7 +24,6 @@ "-I/opt/AMPL/amplapi/include/ampl" ], "cppStandard": "c++23", - "compilerPathInCppPropertiesJson": "/usr/bin/g++", "mergeConfigurations": false, "configurationProvider": "ms-vscode.makefile-tools", "browse": { diff --git a/AMPLSolver.cpp b/AMPLSolver.cpp index 84aee4f..f80a455 100644 --- a/AMPLSolver.cpp +++ b/AMPLSolver.cpp @@ -15,6 +15,8 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/) #include // Standard exceptions #include // Error codes +#include "Utility/ConsolePrint.hpp" + #include "AMPLSolver.hpp" namespace NebulOuS @@ -92,7 +94,12 @@ std::string AMPLSolver::SaveFile( const JSON & TheMessage, void AMPLSolver::DefineProblem(const Solver::OptimisationProblem & TheProblem, const Address TheOracle) { - ProblemDefinition.read( SaveFile( TheProblem ) ); + Theron::ConsoleOutput Output; + Output << "AMPL Solver received the AMPL problem: " << TheProblem.dump(2) + << std::endl; + + ProblemDefinition.read( SaveFile( TheProblem ) ); + Output << "Problem loaded!" << std::endl; } // The data file(s) corresponding to the current optimisation problem will be @@ -215,7 +222,8 @@ void AMPLSolver::SolveProblem( AMPLSolver::AMPLSolver( const std::string & TheActorName, const ampl::Environment & InstallationDirectory, - const std::filesystem::path & ProblemPath ) + const std::filesystem::path & ProblemPath, + const std::string TheSolverType ) : Actor( TheActorName ), StandardFallbackHandler( Actor::GetAddress().AsString() ), NetworkingActor( Actor::GetAddress().AsString() ), @@ -225,6 +233,8 @@ AMPLSolver::AMPLSolver( const std::string & TheActorName, { RegisterHandler( this, &LSolver::DataFileUpdate ); + ProblemDefinition.setOption( "solver", TheSolverType ); + Send( Theron::AMQ::NetworkLayer::TopicSubscription( Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription, Theron::AMQ::TopicName( DataFileTopic ) diff --git a/AMPLSolver.hpp b/AMPLSolver.hpp index 9a03df6..80e6094 100644 --- a/AMPLSolver.hpp +++ b/AMPLSolver.hpp @@ -223,23 +223,26 @@ public: explicit AMPLSolver( const std::string & TheActorName, const ampl::Environment & InstallationDirectory, - const std::filesystem::path & ProblemPath ); + const std::filesystem::path & ProblemPath, + std::string TheSolverType ); // If the path to the problem directory is omitted, it will be initialised to // a temporary directory. explicit AMPLSolver( const std::string & TheActorName, - const ampl::Environment & InstallationDirectory ) + const ampl::Environment & InstallationDirectory, + std::string TheSolverType ) : AMPLSolver( TheActorName, InstallationDirectory, - std::filesystem::temp_directory_path() ) + std::filesystem::temp_directory_path(), TheSolverType ) {} // If the AMPL installation environment is omitted, the installation directory // will be taken form the environment variables. explicit AMPLSolver( const std::string & TheActorName, - const std::filesystem::path & ProblemPath ) - : AMPLSolver( TheActorName, ampl::Environment(), ProblemPath ) + const std::filesystem::path & ProblemPath, + std::string TheSolverType ) + : AMPLSolver( TheActorName, ampl::Environment(), ProblemPath, TheSolverType ) {} // Finally, it is just the standard constructor taking only the name of the @@ -247,7 +250,7 @@ public: AMPLSolver( const std::string & TheActorName ) : AMPLSolver( TheActorName, ampl::Environment(), - std::filesystem::temp_directory_path() ) + std::filesystem::temp_directory_path(), "couenne" ) {} // The solver will just close the open connections for listening to data file diff --git a/ExecutionControl.cpp b/ExecutionControl.cpp index fb358f6..b02e39a 100644 --- a/ExecutionControl.cpp +++ b/ExecutionControl.cpp @@ -11,6 +11,7 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/) #include "Actor.hpp" #include "Communication/NetworkEndpoint.hpp" +#include "Communication/AMQ/AMQEndpoint.hpp" #include "ExecutionControl.hpp" namespace NebulOuS @@ -56,6 +57,9 @@ void ExecutionControl::StopMessageHandler( const StopMessage & Command, { std::lock_guard< std::mutex > Lock( TerminationLock ); + Send( StatusMessage( StatusMessage::State::Stopped ), + Address( std::string( StatusTopic ) ) ); + Send( Theron::Network::ShutDown(), Theron::Network::GetAddress( Theron::Network::Layer::Session ) ); @@ -67,14 +71,24 @@ void ExecutionControl::StopMessageHandler( const StopMessage & Command, // Constructor // ----------------------------------------------------------------------------- // -// The only action taken by the constructor is to register the handler for the -// stop message. +// The constructor registers the stop message handler and sets up a publisher +// for the status topic, and then post a message that the solver is starting. ExecutionControl::ExecutionControl( const std::string & TheActorName ) : Actor( TheActorName ), - StandardFallbackHandler( Actor::GetAddress().AsString() ) + StandardFallbackHandler( Actor::GetAddress().AsString() ), + NetworkingActor( Actor::GetAddress().AsString() ) { RegisterHandler( this, &ExecutionControl::StopMessageHandler ); + + Send( Theron::AMQ::NetworkLayer::TopicSubscription( + Theron::AMQ::NetworkLayer::TopicSubscription::Action::Publisher, + std::string( StatusTopic ) + ), GetSessionLayerAddress() ); + + Send( StatusMessage( StatusMessage::State::Starting ), + Address( std::string( StatusTopic ) ) ); + } } // namespace NebulOuS \ No newline at end of file diff --git a/ExecutionControl.hpp b/ExecutionControl.hpp index 2986579..6296031 100644 --- a/ExecutionControl.hpp +++ b/ExecutionControl.hpp @@ -16,6 +16,9 @@ to call the function to wait for termination. The threads calling the function to wait for termination will block until the required message is received. +The Agent is also involved with the general component status messages to be +sent to the Solver's status topic. + Author and Copyright: Geir Horn, University of Oslo Contact: Geir.Horn@mn.uio.no License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/) @@ -26,6 +29,10 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/) // Standard headers +#include // For constant strings +#include // Standard maps +#include // Stream conversion +#include // For standard time points #include // Execution stop management #include // Lock the condtion variable @@ -34,6 +41,12 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/) #include "Actor.hpp" // Actor base class #include "Utility/StandardFallbackHandler.hpp" // Exception unhanded messages +// AMQ communication + +#include "Communication/NetworkingActor.hpp" // The networking actor +#include "Communication/AMQ/AMQMessage.hpp" +#include "Communication/AMQ/AMQjson.hpp" // JSON messages to be sent + namespace NebulOuS { @@ -45,7 +58,9 @@ namespace NebulOuS class ExecutionControl : virtual public Theron::Actor, - virtual public Theron::StandardFallbackHandler + virtual public Theron::StandardFallbackHandler, + virtual public Theron::NetworkingActor< + typename Theron::AMQ::Message::PayloadType > { // The mechanism used for blocking other threads will be to make them wait // for a condition variable until the message handler for the exit message @@ -57,6 +72,57 @@ private: static std::mutex TerminationLock; static std::condition_variable ReadyToTerminate; +protected: + + // There is a status message class that can be used to send the status to + // other components. + + class StatusMessage + : virtual public Theron::AMQ::JSONMessage + { + public: + + enum class State + { + Starting, + Started, + Stopping, + Stopped + }; + + private: + + std::string ToString( State TheSituation ) + { + static const std::map< State, std::string > StateString { + {State::Starting, "starting"}, {State::Started, "started"}, + {State::Stopping, "stopping"}, {State::Stopped, "stopped"} }; + + return StateString.at( TheSituation ); + } + + std::string UTCNow( void ) + { + std::ostringstream TimePoint; + TimePoint << std::chrono::system_clock::now(); + return TimePoint.str(); + } + + public: + + StatusMessage( State TheSituation, + std::string AdditionalInformation = std::string() ) + : JSONMessage( std::string( StatusTopic ), + { {"when", UTCNow() }, {"state", ToString( TheSituation ) }, + {"message", AdditionalInformation } } ) + {} + }; + + // The status of the solver is communicated on the dedicated status topic + + static constexpr std::string_view StatusTopic + = "eu.nebulouscloud.solver.state"; + public: // The function used to wait for the termination message simply waits on the diff --git a/SolverComponent.cpp b/SolverComponent.cpp index 2945dd8..ff2fa54 100644 --- a/SolverComponent.cpp +++ b/SolverComponent.cpp @@ -17,6 +17,7 @@ The command line arguments that can be givne to the Solver Component are -M ir --ModelDir for model and data files -N or --name The AMQ identity of the solver (see below) -P or --port the port to use on the AMQ broker URL +-S or --Solver