* Copyright (c) 2016-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See Sim0MQ License.
*
* $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
* initial version April 10, 2017
* @author Alexander Verbraeck
*/
public final class MM1FederationManager20
{
/**
* @param args parameters for main
* @throws Sim0MQException on error
*/
public static void main(final String[] args) throws Sim0MQException
{
if (args.length < 5)
{
System.err.println("Use as FederationManager federationName federationManagerPortNumber "
+ "federateStarterIPorName federateStarterPortNumber modelFolder");
System.exit(-1);
}
String federationName = args[0];
String fmsPort = args[1];
int fmPort = 0;
try
{
fmPort = Integer.parseInt(fmsPort);
}
catch (NumberFormatException nfe)
{
System.err.println("Use as FederationManager fedName fmPort fsIP fsPort modelFolder, where fmPort is a number");
System.exit(-1);
}
if (fmPort == 0 || fmPort > 65535)
{
System.err.println("fmPort should be between 1 and 65535");
System.exit(-1);
}
String fsServerNameOrIP = args[2];
String fsPortString = args[3];
int fsPort = 0;
try
{
fsPort = Integer.parseInt(fsPortString);
}
catch (NumberFormatException nfe)
{
System.err.println("Use as FederationManager fedName fmPort fsIP fsPort modelFolder, where fmPort is a number");
System.exit(-1);
}
if (fsPort == 0 || fsPort > 65535)
{
System.err.println("fsPort should be between 1 and 65535");
System.exit(-1);
}
String mm1ModelFolder = args[4];
new MM1FederationManager20(federationName, fmPort, fsServerNameOrIP, fsPort, mm1ModelFolder);
}
/**
* Send an FM.1 message to the FederateStarter.
* @param federationName the name of the federation
* @param fmPort the port number to listen on
* @param fsServerNameOrIP name or IP address of the federate starter we are using
* @param fsPort the port where the federate starter can be reached
* @param mm1ModelFolder location on the computer of the federate starter where the model can be found
* @throws Sim0MQException on error
*/
private MM1FederationManager20(final String federationName, final int fmPort, final String fsServerNameOrIP,
final int fsPort, final String mm1ModelFolder) throws Sim0MQException
{
AtomicLong messageCount = new AtomicLong(0L);
AtomicInteger nrRunning = new AtomicInteger();
Map> statMap =
Collections.synchronizedMap(new LinkedHashMap>());
for (int modelNr = 0; modelNr < 20; modelNr++)
{
new Thread()
{
@Override
public void run()
{
final int nr = nrRunning.getAndIncrement();
StateMachine stateMachine = null;
System.out.println("inc modelNr to " + nr);
try
{
stateMachine =
new StateMachine(messageCount, federationName, fsServerNameOrIP, fsPort, mm1ModelFolder, nr);
}
catch (Sim0MQException | SerializationException exception)
{
exception.printStackTrace();
}
int decNr = nrRunning.decrementAndGet();
System.out.println("dec modelNr to " + decNr);
synchronized (statMap)
{
statMap.put(nr, stateMachine.getStatistics());
}
}
}.start();
}
while (nrRunning.get() > 0)
{
Thread.yield();
}
synchronized (statMap)
{
for (int nr : statMap.keySet())
{
Map stats = statMap.get(nr);
StringBuilder s = new StringBuilder();
s.append(String.format("%2d ", nr));
for (String code : stats.keySet())
{
s.append(String.format("%10s=%10.4f ", code, stats.get(code).doubleValue()));
}
System.out.println(s.toString());
}
}
}
/**
* State machine to run several models in parallel.
*
* Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
*
* BSD-style license. See Sim0MQ License.
*
* $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
* initial version May 5, 2017
* @author Alexander Verbraeck
*/
static class StateMachine
{
/** the state of the started model. */
private ModelState state;
/** the model socket. */
private ZMQ.Socket modelSocket;
/** the model name. */
private String modelName;
/** the federate starter socket. */
private ZMQ.Socket fsSocket;
/** the context. */
private ZContext fmContext;
/** the message counter. */
private AtomicLong messageCount;
/** statistics. */
private Map statistics = new LinkedHashMap<>();
/**
* @param messageCount AtomicLong; message counter
* @param federationName the name of the federation
* @param fsServerNameOrIP name or IP address of the federate starter we are using
* @param fsPort the port where the federate starter can be reached
* @param mm1ModelFolder location on the computer of the federate starter where the model can be found
* @param modelNr sequence number of the model to run
* @throws Sim0MQException on error
* @throws SerializationException on serialization problem
*/
StateMachine(final AtomicLong messageCount, final String federationName, final String fsServerNameOrIP,
final int fsPort, final String mm1ModelFolder, final int modelNr) throws Sim0MQException, SerializationException
{
this.fmContext = new ZContext(1);
this.fsSocket = this.fmContext.createSocket(SocketType.REQ);
this.fsSocket.setIdentity(UUID.randomUUID().toString().getBytes());
this.modelName = "MM1." + modelNr;
this.messageCount = messageCount;
this.modelSocket = this.fmContext.createSocket(SocketType.REQ);
this.modelSocket.setIdentity(UUID.randomUUID().toString().getBytes());
this.state = ModelState.NOT_STARTED;
boolean ready = false;
while (!ready)
{
System.out.println(this.state);
switch (this.state)
{
case NOT_STARTED:
// federationName, fsServerNameOrIP, fsPort, mm1ModelFolder
startModel(federationName, fsServerNameOrIP, fsPort, mm1ModelFolder);
break;
case STARTED:
sendSimRunControl(federationName);
break;
case RUNCONTROL:
setParameters(federationName);
break;
case PARAMETERS:
sendSimStart(federationName);
break;
case SIMULATORSTARTED:
waitForSimEnded(federationName);
break;
case SIMULATORENDED:
requestStatistics(federationName);
break;
case STATISTICSGATHERED:
killFederate(federationName);
ready = true;
break;
case ERROR:
killFederate(federationName);
ready = true;
break;
default:
break;
}
}
this.fsSocket.close();
this.modelSocket.close();
this.fmContext.destroy();
this.fmContext.close();
}
/**
* Send the FM.1 message to the FederateStarter to start the MM1 model.
* @param federationName the name of the federation
* @param fsServerNameOrIP name or IP address of the federate starter we are using
* @param fsPort the port where the federate starter can be reached
* @param mm1ModelFolder location on the computer of the federate starter where the model can be found
* @throws Sim0MQException on error
* @throws SerializationException on serialization problem
*/
private void startModel(final String federationName, final String fsServerNameOrIP, final int fsPort,
final String mm1ModelFolder) throws Sim0MQException, SerializationException
{
// Start model mmm1.jar
byte[] fm1Message = new FM1StartFederateMessage(federationName, "FM", "FS", this.messageCount.getAndIncrement(),
this.modelName, "java8+", "-jar", mm1ModelFolder + "/mm1.jar", this.modelName + " %PORT%", mm1ModelFolder,
"", mm1ModelFolder + "/out_" + this.modelName + ".txt", mm1ModelFolder + "/err_" + this.modelName + ".txt",
false, true, true).createByteArray();
this.fsSocket.connect("tcp://" + fsServerNameOrIP + ":" + fsPort);
this.fsSocket.send(fm1Message);
byte[] reply = this.fsSocket.recv(0);
try
{
Object[] fs2Fields = Sim0MQMessage.decode(reply).createObjectArray();
System.out.println("Received\n" + Sim0MQMessage.print(fs2Fields));
FS2FederateStartedMessage message = new FS2FederateStartedMessage(fs2Fields);
if (message.getStatus().toString().equals("started") && message.getInstanceId().equals(this.modelName))
{
this.state = ModelState.STARTED;
this.modelSocket.connect("tcp://" + fsServerNameOrIP + ":" + message.getModelPort());
}
else
{
this.state = ModelState.ERROR;
System.err.println("Model not started correctly -- state = " + message.getStatus());
System.err.println("Started model = " + message.getInstanceId() + " on port " + message.getModelPort());
System.err.println("Error message = " + message.getError());
}
}
catch (Exception exception)
{
this.state = ModelState.ERROR;
System.err.println("Model not started correctly -- error = " + exception.getClass().getSimpleName());
System.err.println("Started instance of model = " + this.modelName);
System.err.println("Error message = " + exception.getMessage());
}
}
/**
* Send the SimRunControl message FM.2.
* @param federationName the name of the federation
* @throws Sim0MQException on error
* @throws SerializationException on serialization problem
*/
private void sendSimRunControl(final String federationName) throws Sim0MQException, SerializationException
{
long messageNumber = this.messageCount.get();
byte[] fm2Message = new FM2SimRunControlMessage(federationName, "FM", this.modelName, this.messageCount.getAndIncrement(),
100.0, 0.0, 0.0, Double.POSITIVE_INFINITY, 1, 0, new HashMap