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
This commit is contained in:
parent
79cf79e7fb
commit
ae588d8955
4
.vscode/c_cpp_properties.json
vendored
4
.vscode/c_cpp_properties.json
vendored
@ -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": {
|
||||
|
@ -15,6 +15,8 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
|
||||
#include <stdexcept> // Standard exceptions
|
||||
#include <system_error> // 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 )
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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 <string_view> // For constant strings
|
||||
#include <map> // Standard maps
|
||||
#include <sstream> // Stream conversion
|
||||
#include <chrono> // For standard time points
|
||||
#include <condition_variable> // Execution stop management
|
||||
#include <mutex> // 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
|
||||
|
@ -17,6 +17,7 @@ The command line arguments that can be givne to the Solver Component are
|
||||
-M ir --ModelDir <directory> for model and data files
|
||||
-N or --name The AMQ identity of the solver (see below)
|
||||
-P or --port <n> the port to use on the AMQ broker URL
|
||||
-S or --Solver <label> The back-end solver used by AMPL
|
||||
-U or --user <user> the user to authenticate for the AMQ broker
|
||||
-Pw or --password <password> the AMQ broker password for the user
|
||||
-? or --Help prints a help message for the options
|
||||
@ -29,6 +30,7 @@ Default values:
|
||||
-M <temporary directory created by the OS>
|
||||
-N "NebulOuS::Solver"
|
||||
-P 5672
|
||||
-S couenne
|
||||
-U admin
|
||||
-Pw admin
|
||||
|
||||
@ -38,6 +40,20 @@ will be established as "name@endpoint" and so if there are several
|
||||
solver components running, the endpoint is the only way for the AMQ solvers to
|
||||
distinguish the different solver component subscriptions.
|
||||
|
||||
Notes on use:
|
||||
|
||||
The path to the AMPL API shared libray must be in the LIB path environment
|
||||
variable. For instance, the installation of AMPL on the author's machine is in
|
||||
/opt/AMPL and so the first thing to ensure is that the path to the API library
|
||||
directory is added to the link library path, e.g.,
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/AMPL/amplapi/lib
|
||||
|
||||
The AMPL directory also needs to be in the path variable, and the path must
|
||||
be extended with the AMPL execution file path, e.g.,
|
||||
|
||||
export PATH=$PATH:/opt/AMPL
|
||||
|
||||
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/)
|
||||
@ -100,20 +116,22 @@ int main( int NumberOfCLIOptions, char ** CLIOptionStrings )
|
||||
CLIOptions.add_options()
|
||||
("A,AMPLDir", "The AMPL installation path",
|
||||
cxxopts::value<std::string>()->default_value("") )
|
||||
("B,broker", "The URL of the AMQ broker",
|
||||
("B,Broker", "The URL of the AMQ broker",
|
||||
cxxopts::value<std::string>()->default_value("localhost") )
|
||||
("E,endpoint", "The endpoint name", cxxopts::value<std::string>() )
|
||||
("E,Endpoint", "The endpoint name", cxxopts::value<std::string>() )
|
||||
("M,ModelDir", "Directory to store the model and its data",
|
||||
cxxopts::value<std::string>()->default_value("") )
|
||||
("N,name", "The name of the Solver Component",
|
||||
("N,Name", "The name of the Solver Component",
|
||||
cxxopts::value<std::string>()->default_value("NebulOuS::Solver") )
|
||||
("P,port", "TCP port on AMQ Broker",
|
||||
("P,Port", "TCP port on AMQ Broker",
|
||||
cxxopts::value<unsigned int>()->default_value("5672") )
|
||||
("U,user", "The user name used for the AMQ Broker connection",
|
||||
("S,Solver", "Solver to use, devault Couenne",
|
||||
cxxopts::value<std::string>()->default_value("couenne") )
|
||||
("U,User", "The user name used for the AMQ Broker connection",
|
||||
cxxopts::value<std::string>()->default_value("admin") )
|
||||
("Pw,password", "The password for the AMQ Broker connection",
|
||||
("Pw,Password", "The password for the AMQ Broker connection",
|
||||
cxxopts::value<std::string>()->default_value("admin") )
|
||||
("?,help", "Print help information");
|
||||
("h,help", "Print help information");
|
||||
|
||||
CLIOptions.allow_unrecognised_options();
|
||||
|
||||
@ -170,17 +188,17 @@ int main( int NumberOfCLIOptions, char ** CLIOptionStrings )
|
||||
|
||||
proton::connection_options AMQOptions;
|
||||
|
||||
AMQOptions.user( CLIValues["user"].as< std::string >() );
|
||||
AMQOptions.password( CLIValues["password"].as< std::string >() );
|
||||
AMQOptions.user( CLIValues["User"].as< std::string >() );
|
||||
AMQOptions.password( CLIValues["Password"].as< std::string >() );
|
||||
|
||||
// Then the network endpoint cna be constructed using the default names for
|
||||
// the various network endpoint servers in order to pass the defined
|
||||
// connection options.
|
||||
|
||||
Theron::AMQ::NetworkEndpoint AMQNetWork(
|
||||
CLIValues["endpoint"].as< std::string >(),
|
||||
CLIValues["broker"].as< std::string >(),
|
||||
CLIValues["port"].as< unsigned int >(),
|
||||
CLIValues["Endpoint"].as< std::string >(),
|
||||
CLIValues["Broker"].as< std::string >(),
|
||||
CLIValues["Port"].as< unsigned int >(),
|
||||
Theron::AMQ::Network::NetworkLayerLabel,
|
||||
Theron::AMQ::Network::SessionLayerLabel,
|
||||
Theron::AMQ::Network::PresentationLayerLabel,
|
||||
@ -203,11 +221,12 @@ int main( int NumberOfCLIOptions, char ** CLIOptionStrings )
|
||||
// the root solver name.
|
||||
|
||||
NebulOuS::SolverManager< NebulOuS::AMPLSolver >
|
||||
WorkloadMabager( "WorkloadManager",
|
||||
WorkloadMabager( CLIValues["Name"].as<std::string>(),
|
||||
std::string( NebulOuS::Solver::Solution::MessageIdentifier ),
|
||||
std::string( NebulOuS::Solver::ApplicationExecutionContext::MessageIdentifier ),
|
||||
1, "AMPLSolver",
|
||||
ampl::Environment( TheAMPLDirectory.native() ), ModelDirectory );
|
||||
ampl::Environment( TheAMPLDirectory.native() ), ModelDirectory,
|
||||
CLIValues["Solver"].as<std::string>() );
|
||||
|
||||
NebulOuS::MetricUpdater
|
||||
ContextMabager( "MetricUpdater", WorkloadMabager.GetAddress() );
|
||||
|
@ -299,6 +299,10 @@ public:
|
||||
Send( Theron::AMQ::NetworkLayer::TopicSubscription(
|
||||
Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
|
||||
ContextPublisherTopic ), GetSessionLayerAddress() );
|
||||
|
||||
Send( ExecutionControl::StatusMessage(
|
||||
ExecutionControl::StatusMessage::State::Started
|
||||
), Address( std::string( ExecutionControl::StatusTopic ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user