package com.plectix.simulator.random;
import java.util.List;
import com.plectix.simulator.controller.SimulatorResultsData;
import com.plectix.simulator.controller.SimulatorStatusInterface;
import com.plectix.simulator.io.ConsoleOutputManager;
import com.plectix.simulator.simulationclasses.injections.Injection;
import com.plectix.simulator.simulationclasses.perturbations.ComplexPerturbation;
import com.plectix.simulator.simulationclasses.perturbations.TimeCondition;
import com.plectix.simulator.simulationclasses.solution.OperationMode;
import com.plectix.simulator.simulator.ObservablesLiveDataSource;
import com.plectix.simulator.simulator.SimulationArguments;
import com.plectix.simulator.simulator.SimulationClock;
import com.plectix.simulator.simulator.SimulationData;
import com.plectix.simulator.simulator.SimulationState;
import com.plectix.simulator.simulator.Simulator;
import com.plectix.simulator.simulator.SimulatorMessage;
import com.plectix.simulator.simulator.UpdatesPerformer;
import com.plectix.simulator.simulator.SimulationArguments.SimulationType;
import com.plectix.simulator.simulator.api.OperationType;
import com.plectix.simulator.simulator.api.steps.AbstractOperation;
import com.plectix.simulator.staticanalysis.Rule;
import com.plectix.simulator.staticanalysis.RuleApplicator;
import com.plectix.simulator.staticanalysis.stories.storage.StoryStorageException;
import com.plectix.simulator.streaming.LiveDataSourceInterface;
import com.plectix.simulator.streaming.LiveDataStreamer;
import com.plectix.simulator.util.Info.InfoType;
import com.plectix.simulator.util.io.PlxLogger;
public class TalkingAlotSimulationOperation extends AbstractOperation<Object> {
private final Simulator simulator;
private final double time;
private final long events;
/**
* Be careful using this constructor, you should strictly control the type of the second parameter
* @param simulator
* @param time
*/
public TalkingAlotSimulationOperation(Simulator simulator) {
super(simulator.getSimulationData(), OperationType.SIMULATION);
this.simulator = simulator;
this.correctSimulationArguments();
SimulationData simulationData = simulator.getSimulationData();
SimulationArguments arguments = simulationData.getSimulationArguments();
if (simulationData.getSimulationArguments().isTime()) {
this.time = arguments.getTimeLimit();
this.events = -1;
} else {
this.time = -1;
this.events = arguments.getMaxNumberOfEvents();
simulationData.getConsoleOutputManager().println("*Warning* No time limit.");
}
}
private void correctSimulationArguments() {
simulator.getSimulationData().getSimulationArguments().setSimulationType(SimulationType.SIM);
}
protected Object performDry() throws Exception {
if (time < 0) {
this.performEventsSimulation();
} else {
this.performTimeSimulation();
}
simulator.getSimulationData().getKappaSystem().getState().refreshSimulationType(SimulationType.SIM);
return null;
}
private void performEventsSimulation() throws Exception {
SimulationClock clock = new SimulationClock(simulator.getSimulationData());
clock.setEvent(events);
this.runSimulation(clock);
}
private void performTimeSimulation() throws Exception {
SimulationClock clock = new SimulationClock(simulator.getSimulationData());
clock.setTimeLimit(time);
this.runSimulation(clock);
}
private void updateFinalState(Simulator simulator) {
SimulationState state = simulator.getState();
SimulationData simulationData = simulator.getSimulationData();
if (simulationData.getSimulationArguments().isTime()) {
simulationData.checkOutputFinalState(simulationData
.getSimulationArguments().getTimeLimit());
} else {
simulationData.checkOutputFinalState(state.getCurrentTime());
}
}
private void runSimulation(SimulationClock clock) throws StoryStorageException {
Object statusLock = simulator.getStatusLock();
final SimulationState state = simulator.initializeSimulationState();
final SimulationData simulationData = simulator.getSimulationData();
final SimulatorStatusInterface simulatorStatus = simulator.getStatus();
final SimulatorResultsData simulatorResultsData = simulator.getSimulatorResultsData();
final PlxLogger logger = simulator.getLogger();
final RuleApplicator ruleApplicator = new RuleApplicator(simulationData);
final LiveDataStreamer liveDataStreamer = simulator.getLiveDataStreamer();
clock.setClockStamp(System.currentTimeMillis());
ConsoleOutputManager consoleOutputManager = simulationData.getConsoleOutputManager();
consoleOutputManager.addAdditionalInfo(InfoType.INFO, "-Simulation...");
int seed = simulationData.getSimulationArguments().getSeed();
consoleOutputManager.addAdditionalInfo(InfoType.INFO,
"--Seeding random number generator with given seed " + seed);
synchronized (statusLock) {
state.setEventsToZero();
}
boolean finalStateIsAlreadyComputed = false;
long clashesNumber = 0;
long currentNumberOfClashes = 0;
boolean isEndRules = false;
boolean isCalculateObs = true;
LiveDataSourceInterface liveDataSource = new ObservablesLiveDataSource(
simulationData.getKappaSystem().getObservables());
liveDataStreamer.reset(simulationData.getSimulationArguments()
.getLiveDataInterval(), simulationData.getSimulationArguments()
.getLiveDataPoints(), simulationData.getSimulationArguments()
.getLiveDataConsumerClassname(), liveDataSource);
simulatorStatus.setStatusMessage(SimulatorMessage.STATUS_RUNNING);
simulationData.getKappaSystem().getObservables().addInitialState();
while (!clock.isEndSimulation(state, currentNumberOfClashes)) {
if (Thread.interrupted()) {
// TODO: Do any necessary clean-up and collect data we can
// return
consoleOutputManager
.println("Simulation is interrupted because the thread is cancelled");
simulatorResultsData.setCancelled(true);
simulatorStatus.setProgress(1.0);
break;
}
while (simulationData.checkSnapshots(state.getCurrentTime())) {
simulationData.createSnapshots(state.getCurrentTime());
}
simulationData.getKappaSystem().checkPerturbation(state.getCurrentTime());
simulationData.getKappaSystem().updateRuleActivities();
Rule rule = simulationData.getKappaSystem().getRandomRule();
if (rule == null) {
List<ComplexPerturbation<?, ?>> perturbations = simulationData
.getKappaSystem().getPerturbations();
double tmpTime = simulationData.getSimulationArguments()
.getTimeLimit();
ComplexPerturbation<TimeCondition, ?> tmpPerturbation = null;
for (ComplexPerturbation<?, ?> perturbation : perturbations) {
if (perturbation.getCondition() instanceof TimeCondition) {
// TODO awful type cast
ComplexPerturbation<TimeCondition, ?> castedPerturbation = (ComplexPerturbation<TimeCondition, ?>) perturbation;
double conditionTimeLimit = castedPerturbation
.getCondition().getTimeLimit();
if (conditionTimeLimit > state.getCurrentTime()
&& conditionTimeLimit < tmpTime) {
tmpTime = conditionTimeLimit;
tmpPerturbation = castedPerturbation;
}
}
}
// TODO is it right way: to add timeSampleMin to currentTime for
// applying the perturbation?
if (tmpPerturbation != null) {
state.setCurrentTime(tmpPerturbation.getCondition().getTimeLimit()
+ simulationData.getKappaSystem().getObservables()
.getTimeSampleMin());
simulationData.getKappaSystem().checkPerturbation(
state.getCurrentTime());
rule = simulationData.getKappaSystem().getRandomRule();
} else {
isEndRules = true;
clock.setTimeLimit(state.getCurrentTime());
consoleOutputManager.println("#");
break;
}
}
/*
* update current time
*/
if (!rule.hasInfiniteRate()) {
synchronized (statusLock) {
state.setCurrentTime(state.getCurrentTime() + simulationData.getKappaSystem()
.getTimeValue());
}
liveDataStreamer.addNewDataPoint(state.getCurrentEventNumber(),
state.getCurrentTime());
}
/*
* if this is the last iteration we need to make final snapshots
* BEFORE the application of choosen rule
*
*/
if (clock.isEndSimulation(state, currentNumberOfClashes)) {
this.updateFinalState(simulator);
finalStateIsAlreadyComputed = true;
}
if (isCalculateObs
&& simulationData.getSimulationArguments().getReportExactSampleTime()
&& simulationData.getSimulationArguments().isTime()) {
simulationData.getKappaSystem().getObservables().calculateExactSampleObs(
state.getCurrentTime(),
state.getCurrentEventNumber(),
true);
}
if (logger.isDebugEnabled()) {
logger.debug("Rule: " + rule.getName());
}
List<Injection> injectionsList = simulationData.getKappaSystem()
.chooseInjectionsForRuleApplication(rule);
isCalculateObs = false;
if (injectionsList != null) {
// negative update
currentNumberOfClashes = 0;
if (logger.isDebugEnabled())
logger.debug("negative update");
synchronized (statusLock) {
state.incCurrentEventNumber();
}
simulationData.addInfo(InfoType.OUTPUT, state.getCurrentTime() + "");
List<Injection> newInjections = ruleApplicator.applyRule(rule,
injectionsList, simulationData);
if (newInjections != null) {
UpdatesPerformer.doNegativeUpdate(newInjections);
// positive update
if (logger.isDebugEnabled()) {
logger.debug("positive update");
}
// on the 4th mode we should set only super injections, so
// we do it manually
// directly after the rule application
if (simulationData.getSimulationArguments()
.getOperationMode() != OperationMode.FOURTH) {
simulationData.getKappaSystem().doPositiveUpdate(rule,
newInjections);
}
simulationData.getKappaSystem().getSolution()
.flushPoolContent(rule.getPool());
isCalculateObs = true;
// simulationData.getKappaSystem().getObservables().calculateObs(currentTime,
// currentEventNumber,
// simulationData.getSimulationArguments().isTime());
} else {
if (logger.isDebugEnabled()) {
logger.debug("Rule rejected");
}
}
} else {
consoleOutputManager.addAdditionalInfo(InfoType.INTERNAL,
"Application of rule exp is clashing");
if (logger.isDebugEnabled()) {
logger.debug("Clash");
}
clashesNumber++;
currentNumberOfClashes++;
}
if (simulationData.getSimulationArguments().getLiveDataInterval() != -1) {
simulationData.getKappaSystem().getObservables().updateLastValues();
}
if (isCalculateObs &&
!(simulationData.getSimulationArguments().getReportExactSampleTime()
&& simulationData.getSimulationArguments().isTime())) {
simulationData.getKappaSystem().getObservables().calculateObs(
state.getCurrentTime(), state.getCurrentEventNumber(),
simulationData.getSimulationArguments().isTime());
}
}
/*
* If we still
*/
if (!finalStateIsAlreadyComputed
&& clock.isEndSimulation(state, currentNumberOfClashes)) {
this.updateFinalState(simulator);
}
liveDataStreamer.stop();
simulatorStatus.setStatusMessage(SimulatorMessage.STATUS_WRAPPING);
// simulationData.getKappaSystem().getObservables().calculateObsLast(
// currentTime, currentEventNumber);
endSimulation(simulationData.getSimulationArguments()
.getOutputTypeForAdditionalInfo(), isEndRules, logger);
}
private final void endSimulation(InfoType outputType, boolean noRulesLeft, PlxLogger logger) {
switch (outputType) {
case OUTPUT:
if (noRulesLeft) {
logger.info("end of simulation: there are no active rules");
} else {
logger.info("end of simulation: time");
}
break;
}
}
@Override
protected boolean noNeedToPerform() {
return false;
}
@Override
protected Object retrievePreparedResult() {
return null;
}
}