add smart-future-cache and move simulation-service to server-plugin;

This commit is contained in:
Christopher Ronnewinkel (D036654) committed 2015-02-24 15:25:47 +01:00
1 parent 4dc35e059a
commit 32ae97ec48
26 files changed
+606 -327

No files matched your search

@@ -3,10 +3,11 @@ package com.sap.sailing.gwt.ui.actions;
import java.util.Date;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
import com.sap.sailing.gwt.ui.shared.SimulatorResultsDTO;
import com.sap.sailing.gwt.ui.shared.racemap.RaceSimulationOverlay;
import com.sap.sailing.simulator.LegIdentifier;
import com.sap.sse.gwt.client.async.AsyncAction;
/**
@@ -18,19 +19,19 @@ import com.sap.sse.gwt.client.async.AsyncAction;
*/
public class GetSimulationAction implements AsyncAction<SimulatorResultsDTO> {
private final SailingServiceAsync sailingService;
private final RegattaAndRaceIdentifier raceIdentifier;
private final LegIdentifier legIdentifier;
private final Date from;
private final Date prevStartTime;
public GetSimulationAction(SailingServiceAsync sailingService, RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) {
public GetSimulationAction(SailingServiceAsync sailingService, LegIdentifier legIdentifier, Date from, Date prevStartTime) {
this.sailingService = sailingService;
this.raceIdentifier = raceIdentifier;
this.legIdentifier = legIdentifier;
this.from = from;
this.prevStartTime = prevStartTime;
}
@Override
public void execute(AsyncCallback<SimulatorResultsDTO> callback) {
sailingService.getSimulatorResults(raceIdentifier, from, prevStartTime, callback);
sailingService.getSimulatorResults(legIdentifier, from, prevStartTime, callback);
}
}
@@ -84,6 +84,7 @@ import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
import com.sap.sailing.gwt.ui.shared.VenueDTO;
import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sailing.simulator.LegIdentifier;
import com.sap.sse.common.NoCorrespondingServiceRegisteredException;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
@@ -140,7 +141,7 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS
Boolean getPolarResults(RegattaAndRaceIdentifier raceIdentifier);
SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime);
SimulatorResultsDTO getSimulatorResults(LegIdentifier legIdentifier, Date from, Date prevStartTime);
CompactRaceMapDataDTO getRaceMapData(RegattaAndRaceIdentifier raceIdentifier, Date date, Map<String, Date> fromPerCompetitorIdAsString,
Map<String, Date> toPerCompetitorIdAsString, boolean extrapolate) throws NoWindException;
@@ -74,6 +74,7 @@ import com.sap.sailing.gwt.ui.shared.TrackFileImportDeviceIdentifierDTO;
import com.sap.sailing.gwt.ui.shared.VenueDTO;
import com.sap.sailing.gwt.ui.shared.WindDTO;
import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO;
import com.sap.sailing.simulator.LegIdentifier;
import com.sap.sse.common.Util;
import com.sap.sse.common.search.KeywordQuery;
import com.sap.sse.gwt.client.BuildVersionRetriever;
@@ -188,7 +189,7 @@ public interface SailingServiceAsync extends BuildVersionRetriever, FileStorageM
void getPolarResults(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback<Boolean> callback);
void getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime, AsyncCallback<SimulatorResultsDTO> callback);
void getSimulatorResults(LegIdentifier legIdentifier, Date from, Date prevStartTime, AsyncCallback<SimulatorResultsDTO> callback);
void setWind(RegattaAndRaceIdentifier raceIdentifier, WindDTO wind, AsyncCallback<Void> callback);
@@ -388,11 +388,13 @@ import com.sap.sailing.server.operationaltransformation.UpdateLeaderboardScoreCo
import com.sap.sailing.server.operationaltransformation.UpdateRaceDelayToLive;
import com.sap.sailing.server.operationaltransformation.UpdateSeries;
import com.sap.sailing.server.operationaltransformation.UpdateSpecificRegatta;
import com.sap.sailing.server.simulation.SimulationService;
import com.sap.sailing.simulator.LegIdentifier;
import com.sap.sailing.simulator.Path;
import com.sap.sailing.simulator.PathType;
import com.sap.sailing.simulator.PolarDiagram;
import com.sap.sailing.simulator.SimulationParameters;
import com.sap.sailing.simulator.SimulationService;
import com.sap.sailing.simulator.SimulationResults;
import com.sap.sailing.simulator.TimedPositionWithSpeed;
import com.sap.sailing.simulator.impl.PolarDiagramGPS;
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
@@ -1493,107 +1495,39 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
};
@Override
public SimulatorResultsDTO getSimulatorResults(RegattaAndRaceIdentifier raceIdentifier, Date from, Date prevStartTime) {
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
public SimulatorResultsDTO getSimulatorResults(LegIdentifier legIdentifier, Date from, Date prevStartTime) {
// get simulation-results from smart-future-cached simulation-service
SimulationService simulationService = getService().getSimulationService();
SimulationResults simulationResults = simulationService.getSimulationResults(legIdentifier);
// prepare simulator-results-dto
SimulatorResultsDTO result = null;
if (trackedRace != null) {
TimePoint fromTimePoint = from == null ? new MillisecondsTimePoint(trackedRace.getStartOfRace().asMillis() + 10000) : new MillisecondsTimePoint(from);
// get previous mark or start line as start-position
TrackedLeg trackedLeg = trackedRace.getCurrentLeg(fromTimePoint);
if (trackedLeg == null) {
return result;
}
Waypoint fromWaypoint = trackedLeg.getLeg().getFrom();
// get next mark as end-position
Waypoint toWaypoint = trackedLeg.getLeg().getTo();
TimePoint startTimePoint = null;
TimePoint endTimePoint = null;
Iterable<Util.Pair<Waypoint, Util.Pair<TimePoint, TimePoint>>> markPassings = trackedRace.getMarkPassingsTimes();
long legDuration = 0;
synchronized(markPassings) {
for(Pair<Waypoint, Pair<TimePoint, TimePoint>> markPassing : markPassings) {
if (markPassing.getA().equals(fromWaypoint)) {
startTimePoint = markPassing.getB().getA();
}
if (markPassing.getA().equals(toWaypoint)) {
endTimePoint = markPassing.getB().getA();
}
Map<PathType, Path> paths = simulationResults.getPaths();
if (paths != null) {
int noOfPaths = paths.size();
PathDTO[] pathDTOs = new PathDTO[noOfPaths];
int index = noOfPaths - 1;
for (Entry<PathType, Path> entry : paths.entrySet()) {
pathDTOs[index] = new PathDTO(entry.getKey().getTxtId());
// fill pathDTO with path points where speed is true wind speed
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) {
wList.add(createSimulatorWindDTO(p));
}
pathDTOs[index].setPoints(wList);
index--;
}
legDuration = endTimePoint.asMillis() - startTimePoint.asMillis();
Position startPosition = trackedRace.getApproximatePosition(fromWaypoint, startTimePoint);
Position endPosition = trackedRace.getApproximatePosition(toWaypoint, endTimePoint);
if (startTimePoint.asDate().equals(prevStartTime)) {
return new SimulatorResultsDTO(startTimePoint.asDate(), 0, 0, null, null, null, null);
}
// determine legtype upwind/downwind/reaching
LegType legType = null;
try {
legType = trackedLeg.getLegType(fromTimePoint);
} catch (NoWindException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// get windfield
WindFieldGenerator windField = new WindFieldTrackedRaceImpl(trackedRace);
Duration timeStep = new MillisecondsDurationImpl(15 * 1000);
windField.generate(startTimePoint, null, timeStep);
// prepare simulation-parameters
List<Position> course = new ArrayList<Position>();
course.add(startPosition);
course.add(endPosition);
BoatClass boatClass = trackedRace.getRace().getBoatClass();
PolarDataService polarData = getService().getPolarDataService();
PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarData);
double simuStepSeconds = startPosition.getDistance(endPosition).getNauticalMiles()
/ ((PolarDiagramGPS) polarDiagram).getAvgSpeed() * 3600 / 100;
Duration simuStep = new MillisecondsDurationImpl(Math.round(simuStepSeconds) * 1000);
SimulationParameters simulationPars = new SimulationParametersImpl(course, polarDiagram, windField,
simuStep, SailingSimulatorConstants.ModeEvent, true, true);
// for upwind/downwind, run simulation with start-time, start-position, end-position and windfield
SimulationService simulationService = getService().getSimulationService();
Map<PathType, Path> paths = null;
if (legType != LegType.REACHING) {
paths = simulationService.getAllPaths(simulationPars);
}
// prepare simulator-results-dto
if (paths != null) {
int noOfPaths = paths.size();
PathDTO[] pathDTOs = new PathDTO[noOfPaths];
int index = noOfPaths - 1;
for (Entry<PathType, Path> entry : paths.entrySet()) {
pathDTOs[index] = new PathDTO(entry.getKey().getTxtId());
// fill pathDTO with path points where speed is true wind speed
List<SimulatorWindDTO> wList = new ArrayList<SimulatorWindDTO>();
for (TimedPositionWithSpeed p : entry.getValue().getPathPoints()) {
wList.add(createSimulatorWindDTO(p));
}
pathDTOs[index].setPoints(wList);
index--;
}
RaceMapDataDTO rcDTO;
rcDTO = new RaceMapDataDTO();
rcDTO.coursePositions = new CoursePositionsDTO();
rcDTO.coursePositions.waypointPositions = new ArrayList<PositionDTO>();
PositionDTO posDTO;
posDTO = SimulatorServiceUtils.toPositionDTO(startPosition);
rcDTO.coursePositions.waypointPositions.add(posDTO);
posDTO = SimulatorServiceUtils.toPositionDTO(endPosition);
rcDTO.coursePositions.waypointPositions.add(posDTO);
result = new SimulatorResultsDTO(startTimePoint.asDate(), timeStep.asMillis(), legDuration, rcDTO, pathDTOs, null, null);
}
RaceMapDataDTO rcDTO;
rcDTO = new RaceMapDataDTO();
rcDTO.coursePositions = new CoursePositionsDTO();
rcDTO.coursePositions.waypointPositions = new ArrayList<PositionDTO>();
PositionDTO posDTO;
posDTO = SimulatorServiceUtils.toPositionDTO(simulationResults.getStartPosition());
rcDTO.coursePositions.waypointPositions.add(posDTO);
posDTO = SimulatorServiceUtils.toPositionDTO(simulationResults.getEndPosition());
rcDTO.coursePositions.waypointPositions.add(posDTO);
result = new SimulatorResultsDTO(simulationResults.getStartTime(), simulationResults.getTimeStep(),
simulationResults.getLegDuration(), rcDTO, pathDTOs, null, null);
}
return result;
}
@@ -26,6 +26,8 @@ import com.sap.sailing.gwt.ui.shared.SimulatorWindDTO;
import com.sap.sailing.gwt.ui.simulator.racemap.FullCanvasOverlay;
import com.sap.sailing.gwt.ui.simulator.util.ColorPalette;
import com.sap.sailing.gwt.ui.simulator.util.ColorPaletteGenerator;
import com.sap.sailing.simulator.LegIdentifier;
import com.sap.sailing.simulator.impl.LegIdentifierImpl;
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
@@ -70,7 +72,7 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
if (clearCanvas) {
this.clearCanvas();
}
this.simulate(newTime);
this.simulate(newTime, newLeg);
}
}
@@ -247,8 +249,9 @@ public class RaceSimulationOverlay extends FullCanvasOverlay {
return pathTimeStr;
}
public void simulate(Date from) {
GetSimulationAction getSimulation = new GetSimulationAction(sailingService, raceIdentifier, from, prevStartTime);
public void simulate(Date from, int leg) {
LegIdentifier legIdentifier = new LegIdentifierImpl(raceIdentifier, String.valueOf(leg));
GetSimulationAction getSimulation = new GetSimulationAction(sailingService, legIdentifier, from, prevStartTime);
asyncActionsExecutor.execute(getSimulation, GET_SIMULATION_CATEGORY,
new MarkedAsyncCallback<>(new AsyncCallback<SimulatorResultsDTO>() {
@Override
@@ -9,8 +9,6 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Import-Package: com.sap.sailing.polars,
com.sap.sailing.polars.factory,
com.sap.sailing.server.gateway.deserialization,
com.sap.sailing.simulator,
com.sap.sailing.simulator.impl,
org.json.simple,
org.json.simple.parser,
org.osgi.framework;version="1.3.0",
@@ -33,7 +31,8 @@ Require-Bundle: com.sap.sailing.domain,
com.sap.sse,
com.sap.sailing.server.gateway.serialization.shared.android,
com.sap.sse.shared.android,
com.sap.sse.filestorage
com.sap.sse.filestorage,
com.sap.sailing.simulator;bundle-version="1.0.0"
Bundle-ClassPath: .
Export-Package: com.sap.sailing.server,
com.sap.sailing.server.impl;
@@ -45,5 +44,6 @@ Export-Package: com.sap.sailing.server,
com.sap.sailing.server.replication.test,
com.sap.sailing.domain.racelogtrackingadapter.test",
com.sap.sailing.server.masterdata,
com.sap.sailing.server.operationaltransformation
com.sap.sailing.server.operationaltransformation,
com.sap.sailing.server.simulation
@@ -64,7 +64,7 @@ import com.sap.sailing.domain.tracking.TrackerManager;
import com.sap.sailing.domain.tracking.WindStore;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.server.masterdata.DataImportLockWithProgress;
import com.sap.sailing.simulator.SimulationService;
import com.sap.sailing.server.simulation.SimulationService;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
import com.sap.sse.common.Util;
@@ -191,8 +191,8 @@ import com.sap.sailing.server.operationaltransformation.UpdateStartTimeReceived;
import com.sap.sailing.server.operationaltransformation.UpdateTrackedRaceStatus;
import com.sap.sailing.server.operationaltransformation.UpdateWindAveragingTime;
import com.sap.sailing.server.operationaltransformation.UpdateWindSourcesToExclude;
import com.sap.sailing.simulator.SimulationService;
import com.sap.sailing.simulator.SimulationServiceFactory;
import com.sap.sailing.server.simulation.SimulationService;
import com.sap.sailing.server.simulation.SimulationServiceFactory;
import com.sap.sse.BuildVersion;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.TypeBasedServiceFinderFactory;
@@ -505,7 +505,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
/* keepAliveTime */60, TimeUnit.SECONDS,
/* workQueue */new LinkedBlockingQueue<Runnable>());
// TODO: initialize smart-future-cache for simulation-results and add to simulation-service
simulationService = SimulationServiceFactory.INSTANCE.getService(simulatorExecutor);
simulationService = SimulationServiceFactory.INSTANCE.getService(simulatorExecutor, this);
this.raceLogReplicator = new RaceLogReplicator(this);
this.regattaLogReplicator = new RegattaLogReplicator(this);
this.raceLogScoringReplicator = new RaceLogScoringReplicator(this);
@@ -0,0 +1,11 @@
package com.sap.sailing.server.simulation;
import com.sap.sailing.simulator.LegIdentifier;
import com.sap.sailing.simulator.SimulationResults;
public interface SimulationService {
SimulationResults getSimulationResults(LegIdentifier legIdentifier);
}
@@ -0,0 +1,13 @@
package com.sap.sailing.server.simulation;
import java.util.concurrent.Executor;
import com.sap.sailing.server.RacingEventService;
public interface SimulationServiceFactory {
static SimulationServiceFactory INSTANCE = new SimulationServiceFactoryImpl();
SimulationService getService(Executor executor, RacingEventService racingEventService);
}
@@ -0,0 +1,13 @@
package com.sap.sailing.server.simulation;
import java.util.concurrent.Executor;
import com.sap.sailing.server.RacingEventService;
public class SimulationServiceFactoryImpl implements SimulationServiceFactory {
public SimulationService getService(Executor executor, RacingEventService racingEventService) {
return new SimulationServiceImpl(executor, racingEventService);
}
}
@@ -0,0 +1,219 @@
package com.sap.sailing.server.simulation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Leg;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.AbstractRaceChangeListener;
import com.sap.sailing.polars.PolarDataService;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.simulator.LegIdentifier;
import com.sap.sailing.simulator.Path;
import com.sap.sailing.simulator.PathType;
import com.sap.sailing.simulator.PolarDiagram;
import com.sap.sailing.simulator.SailingSimulator;
import com.sap.sailing.simulator.SimulationParameters;
import com.sap.sailing.simulator.SimulationResults;
import com.sap.sailing.simulator.impl.MaximumTurnTimes;
import com.sap.sailing.simulator.impl.PolarDiagramGPS;
import com.sap.sailing.simulator.impl.SailingSimulatorImpl;
import com.sap.sailing.simulator.impl.SimulationParametersImpl;
import com.sap.sailing.simulator.util.SailingSimulatorConstants;
import com.sap.sailing.simulator.windfield.WindFieldGenerator;
import com.sap.sailing.simulator.windfield.impl.WindFieldTrackedRaceImpl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.util.SmartFutureCache;
import com.sap.sse.util.SmartFutureCache.EmptyUpdateInterval;
public class SimulationServiceImpl implements SimulationService {
final private Executor executor;
final private SmartFutureCache<LegIdentifier, SimulationResults, SmartFutureCache.EmptyUpdateInterval> cache;
final private RacingEventService racingEventService;
public SimulationServiceImpl(Executor executor, RacingEventService racingEventService) {
this.executor = executor;
this.cache = new SmartFutureCache<LegIdentifier, SimulationResults, SmartFutureCache.EmptyUpdateInterval>(
new SmartFutureCache.AbstractCacheUpdater<LegIdentifier, SimulationResults, SmartFutureCache.EmptyUpdateInterval>() {
@Override
public SimulationResults computeCacheUpdate(LegIdentifier key, EmptyUpdateInterval updateInterval)
throws Exception {
return computeSimulationResults(key);
}
}, "SmartFutureCache.simulationService (" + racingEventService.toString() + ")");
this.racingEventService = racingEventService;
}
private class Listener extends AbstractRaceChangeListener {
private final LegIdentifier legIdentifier;
public Listener(LegIdentifier legIdentifier) {
this.legIdentifier = legIdentifier;
}
@Override
protected void defaultAction() {
cache.triggerUpdate(legIdentifier, null);
}
// simulation is not influenced by live-delay
@Override
public void delayToLiveChanged(long delayToLiveInMillis) {
}
}
@Override
public SimulationResults getSimulationResults(LegIdentifier legIdentifier) {
SimulationResults result = cache.get(legIdentifier, false);
if (result == null) {
TrackedRace trackedRace = racingEventService.getTrackedRace(legIdentifier);
trackedRace.addListener(new Listener(legIdentifier));
cache.triggerUpdate(legIdentifier, null);
result = cache.get(legIdentifier, false); // take first simulation result that becomes available
}
return result;
}
public SimulationResults computeSimulationResults(LegIdentifier legIdentifier) throws InterruptedException,
ExecutionException {
SimulationResults result = null;
TrackedRace trackedRace = racingEventService.getTrackedRace(legIdentifier);
if (trackedRace != null) {
Leg leg = trackedRace.getRace().getCourse().getLegs().get(legIdentifier.getLegNumber());
// get previous mark or start line as start-position
Waypoint fromWaypoint = leg.getFrom();
// get next mark as end-position
Waypoint toWaypoint = leg.getTo();
TimePoint startTimePoint = null;
TimePoint endTimePoint = null;
MarkPassing markPassing;
markPassing = trackedRace.getMarkPassingsInOrder(fromWaypoint).iterator().next();
if (markPassing != null) {
startTimePoint = markPassing.getTimePoint();
}
markPassing = trackedRace.getMarkPassingsInOrder(toWaypoint).iterator().next();
if (markPassing != null) {
endTimePoint = markPassing.getTimePoint();
}
long legDuration = 0;
if ((startTimePoint != null) && (endTimePoint != null)) {
legDuration = endTimePoint.asMillis() - startTimePoint.asMillis();
}
Position startPosition = null;
Position endPosition = null;
if (startTimePoint != null) {
startPosition = trackedRace.getApproximatePosition(fromWaypoint, startTimePoint);
}
if (endTimePoint != null) {
endPosition = trackedRace.getApproximatePosition(toWaypoint, endTimePoint);
} else if (startTimePoint != null) {
endPosition = trackedRace.getApproximatePosition(toWaypoint, startTimePoint);
}
// determine legtype upwind/downwind/reaching
LegType legType = null;
try {
legType = trackedRace.getTrackedLeg(leg).getLegType(startTimePoint);
} catch (NoWindException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// get windfield
WindFieldGenerator windField = new WindFieldTrackedRaceImpl(trackedRace);
Duration timeStep = new MillisecondsDurationImpl(15 * 1000);
windField.generate(startTimePoint, null, timeStep);
// prepare simulation-parameters
List<Position> course = new ArrayList<Position>();
course.add(startPosition);
course.add(endPosition);
BoatClass boatClass = trackedRace.getRace().getBoatClass();
PolarDataService polarDataService = racingEventService.getPolarDataService();
PolarDiagram polarDiagram = new PolarDiagramGPS(boatClass, polarDataService);
double simuStepSeconds = startPosition.getDistance(endPosition).getNauticalMiles()
/ ((PolarDiagramGPS) polarDiagram).getAvgSpeed() * 3600 / 100;
Duration simuStep = new MillisecondsDurationImpl(Math.round(simuStepSeconds) * 1000);
SimulationParameters simulationPars = new SimulationParametersImpl(course, polarDiagram, windField,
simuStep, SailingSimulatorConstants.ModeEvent, true, true);
Map<PathType, Path> paths = null;
if (legType != LegType.REACHING) {
paths = getAllPathsEvenTimed(simulationPars, timeStep.asMillis());
}
// prepare simulator-results
result = new SimulationResults(startTimePoint.asDate(), timeStep.asMillis(), legDuration, startPosition,
endPosition, paths, null);
}
return result;
}
public Map<PathType, Path> getAllPaths(SimulationParameters simuPars) throws InterruptedException,
ExecutionException {
SailingSimulator simulator = new SailingSimulatorImpl(simuPars);
Map<PathType, Path> result = new HashMap<PathType, Path>();
// schedule omniscient task
FutureTask<Path> taskOmniscient = new FutureTask<Path>(() -> simulator.getPath(PathType.OMNISCIENT, null));
executor.execute(taskOmniscient);
// schedule 1-turner tasks
FutureTask<Path> task1TurnerLeft = new FutureTask<Path>(() -> simulator.getPath(PathType.ONE_TURNER_LEFT, null));
FutureTask<Path> task1TurnerRight = new FutureTask<Path>(() -> simulator.getPath(PathType.ONE_TURNER_RIGHT, null));
executor.execute(task1TurnerLeft);
executor.execute(task1TurnerRight);
// collect 1-turner results
result.put(PathType.ONE_TURNER_LEFT, task1TurnerLeft.get());
result.put(PathType.ONE_TURNER_RIGHT, task1TurnerRight.get());
// maximum turn times
MaximumTurnTimes maxTurnTimes = new MaximumTurnTimes(task1TurnerLeft.get().getMaxTurnTime(), task1TurnerRight
.get().getMaxTurnTime());
// schedule opportunist tasks (which depend on 1-turner results)
FutureTask<Path> taskOpportunistLeft = new FutureTask<Path>(() -> simulator.getPath(PathType.OPPORTUNIST_LEFT, maxTurnTimes));
FutureTask<Path> taskOpportunistRight = new FutureTask<Path>(() -> simulator.getPath(PathType.OPPORTUNIST_RIGHT, maxTurnTimes));
executor.execute(taskOpportunistLeft);
executor.execute(taskOpportunistRight);
// collect opportunist results
result.put(PathType.OPPORTUNIST_LEFT, taskOpportunistLeft.get());
result.put(PathType.OPPORTUNIST_RIGHT, taskOpportunistRight.get());
// collect omniscient result (last, since usually slowest calculation)
result.put(PathType.OMNISCIENT, taskOmniscient.get());
// return combined result
return result;
}
public Map<PathType, Path> getAllPathsEvenTimed(SimulationParameters simuPars, long millisecondsStep)
throws InterruptedException, ExecutionException {
Map<PathType, Path> allTimedPaths = new HashMap<PathType, Path>();
Map<PathType, Path> allPaths = this.getAllPaths(simuPars);
for (Entry<PathType, Path> entry : allPaths.entrySet()) {
PathType pathType = entry.getKey();
Path pathValue = entry.getValue();
allTimedPaths.put(pathType, pathValue.getEvenTimedPath(millisecondsStep));
}
return allTimedPaths;
}
}
@@ -0,0 +1,8 @@
package com.sap.sailing.simulator;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
public interface LegIdentifier extends RegattaAndRaceIdentifier {
String getLegName();
int getLegNumber();
}
@@ -9,6 +9,10 @@ public interface Path {
List<TimedPositionWithSpeed> getPathPoints();
void setPathPoints(List<TimedPositionWithSpeed> pointsList);
public long getMaxTurnTime();
public void setMaxTurnTime(long maxTurnTime);
void setWindField(WindField wf);
@@ -3,6 +3,8 @@ package com.sap.sailing.simulator;
import java.util.List;
import java.util.Map;
import com.sap.sailing.simulator.impl.MaximumTurnTimes;
public interface SailingSimulator {
@@ -12,7 +14,7 @@ public interface SailingSimulator {
Path getLegGPSTrack(SimulatorUISelection selection);
Path getPath(PathType pathType);
Path getPath(PathType pathType, MaximumTurnTimes maxTurnTimes);
Map<String, Path> getAllPaths();
@@ -0,0 +1,91 @@
package com.sap.sailing.simulator;
import java.util.Date;
import java.util.Map;
import com.sap.sailing.domain.common.Position;
public class SimulationResults {
private Date startTime;
private long timeStep;
private long legDuration;
private Position startPosition;
private Position endPosition;
private Map<PathType, Path> paths;
private String notificationMessage;
public SimulationResults(){
this.startTime = null;
this.timeStep = 0;
this.legDuration = 0;
this.paths = null;
this.notificationMessage = "";
}
public SimulationResults(final Date startTime, final long timeStep, final long legDuration, final Position startPosition, final Position endPosition, final Map<PathType, Path> paths, final String notificationMessage) {
this.startTime = startTime;
this.timeStep = timeStep;
this.legDuration = legDuration;
this.startPosition = startPosition;
this.endPosition = endPosition;
this.paths = paths;
this.notificationMessage = notificationMessage;
}
public Date getStartTime() {
return this.startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public long getTimeStep() {
return this.timeStep;
}
public void setTimeStep(long timeStep) {
this.timeStep = timeStep;
}
public long getLegDuration() {
return this.legDuration;
}
public void setLegDuration(long legDuration) {
this.legDuration = legDuration;
}
public Position getStartPosition() {
return this.startPosition;
}
public void setStartPosition(Position startPosition) {
this.startPosition = startPosition;
}
public Position getEndPosition() {
return this.endPosition;
}
public void setEndPosition(Position endPosition) {
this.endPosition = endPosition;
}
public Map<PathType, Path> getPaths() {
return this.paths;
}
public void setPaths(final Map<PathType, Path> paths) {
this.paths = paths;
}
public String getNotificationMessage() {
return this.notificationMessage;
}
public void setNotificationMessage(final String notificationMessage) {
this.notificationMessage = notificationMessage;
}
}
@@ -1,12 +0,0 @@
package com.sap.sailing.simulator;
import java.util.Map;
public interface SimulationService {
Map<PathType, Path> getAllPaths(SimulationParameters simuPars);
Map<PathType, Path> getAllPathsEvenTimed(SimulationParameters simuPars, long millisecondsStep);
}
@@ -1,13 +0,0 @@
package com.sap.sailing.simulator;
import java.util.concurrent.Executor;
import com.sap.sailing.simulator.impl.SimulationServiceFactoryImpl;
public interface SimulationServiceFactory {
static SimulationServiceFactory INSTANCE = new SimulationServiceFactoryImpl();
SimulationService getService(Executor executor);
}
@@ -0,0 +1,58 @@
package com.sap.sailing.simulator.impl;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.simulator.LegIdentifier;
public class LegIdentifierImpl extends RegattaNameAndRaceName implements LegIdentifier {
private static final long serialVersionUID = 3599904513673776450L;
private String legName;
public LegIdentifierImpl(RegattaAndRaceIdentifier raceIdentifier, String legName) {
super(raceIdentifier.getRegattaName(), raceIdentifier.getRaceName());
this.legName = legName;
}
@Override
public String getLegName() {
return legName;
}
@Override
public int getLegNumber() {
return Integer.parseInt(legName);
}
@Override
public String toString() {
return getRegattaName()+"/"+getRaceName()+"/"+getLegName();
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((legName == null) ? 0 : legName.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
LegIdentifierImpl other = (LegIdentifierImpl) obj;
if (legName == null) {
if (other.legName != null)
return false;
} else if (!legName.equals(other.legName))
return false;
return true;
}
}
@@ -0,0 +1,11 @@
package com.sap.sailing.simulator.impl;
public class MaximumTurnTimes {
public long left;
public long right;
public MaximumTurnTimes(long left, long right) {
this.left = left;
this.right = right;
}
}
@@ -24,8 +24,7 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
int turns;
int maxLeft;
int maxRight;
long maxLeftTime;
long maxRightTime;
MaximumTurnTimes maxTurnTimes;
boolean startLeft;
boolean upwindLeg = false;
@@ -33,35 +32,34 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
simulationParameters = params;
}
public void setEvaluationParameters(int maxLeftVal, int maxRightVal, boolean startLeftVal) {
this.maxLeft = maxLeftVal;
this.maxRight = maxRightVal;
this.startLeft = startLeftVal;
public void setEvaluationParameters(int maxLeft, int maxRight, boolean startLeft) {
this.maxLeft = maxLeft;
this.maxRight = maxRight;
this.startLeft = startLeft;
}
public void setEvaluationParameters(long maxLeftTime, long maxRightTime, boolean startLeftVal) {
this.maxLeftTime = maxLeftTime;
this.maxRightTime = maxRightTime;
this.startLeft = startLeftVal;
public void setEvaluationParameters(MaximumTurnTimes maxTurnTimes, boolean startLeft) {
this.maxTurnTimes = maxTurnTimes;
this.startLeft = startLeft;
}
public int getTurns() {
return turns;
return turns;
}
@Override
public Path getPath() {
WindFieldGenerator wf = simulationParameters.getWindField();
PolarDiagram pd = simulationParameters.getBoatPolarDiagram();
Position start = simulationParameters.getCourse().get(0);
Position end = simulationParameters.getCourse().get(1);
// test downwind: exchange start and end
//Position start = simulationParameters.getCourse().get(1);
//Position end = simulationParameters.getCourse().get(0);
// Position start = simulationParameters.getCourse().get(1);
// Position end = simulationParameters.getCourse().get(0);
TimePoint startTime = wf.getStartTime();// new MillisecondsTimePoint(0);
List<TimedPositionWithSpeed> path = new ArrayList<TimedPositionWithSpeed>();
@@ -86,34 +84,34 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
logger.fine("wndStart speed:" + wndStart.getKnots() + " angle:" + wndStart.getBearing().getDegrees());
pd.setWind(wndStart);
Bearing bearStart = currentPosition.getBearingGreatCircle(end);
//SpeedWithBearing spdStart = pd.getSpeedAtBearing(bearStart);
// SpeedWithBearing spdStart = pd.getSpeedAtBearing(bearStart);
path.add(new TimedPositionWithSpeedImpl(startTime, start, wndStart));
long timeStep = wf.getTimeStep().asMillis()/2;
long timeStep = wf.getTimeStep().asMillis() / 2;
logger.info("Time step :" + timeStep);
// while there is more than 5% of the total distance to the finish
Bearing bearRCWind = wndStart.getBearing().getDifferenceTo(bearStart);
String legType = "downwind";
this.upwindLeg = false;
if ((Math.abs(bearRCWind.getDegrees()) > 90.0)&&(Math.abs(bearRCWind.getDegrees()) < 270.0)) {
legType = "upwind";
if ((Math.abs(bearRCWind.getDegrees()) > 90.0) && (Math.abs(bearRCWind.getDegrees()) < 270.0)) {
legType = "upwind";
this.upwindLeg = true;
}
int timeStepScale = 1;
if (!this.upwindLeg) {
timeStepScale = 2;
timeStep = timeStep / timeStepScale;
turnloss = turnloss / timeStepScale;
turnloss = turnloss / timeStepScale;
}
if ((maxLeftTime > 0)||(maxRightTime > 0)) {
this.maxLeft = (int)Math.floor((double)maxLeftTime / (double)timeStep);
this.maxRight = (int)Math.floor((double)maxRightTime / (double)timeStep);
if ((maxTurnTimes.left > 0) || (maxTurnTimes.right > 0)) {
this.maxLeft = (int) Math.floor((double) maxTurnTimes.left / (double) timeStep);
this.maxRight = (int) Math.floor((double) maxTurnTimes.right / (double) timeStep);
}
logger.info("Leg Direction: "+legType);
logger.info("Leg Direction: " + legType);
//
// StrategicPhase: start & intermediate course until close to target
@@ -121,7 +119,9 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
turns = 0;
SpeedWithBearing slft = null;
SpeedWithBearing srght = null;
while ((currentHeight > 0)&&(currentPosition.getDistance(end).compareTo(start.getDistance(end).scale(fracFinishPhase)) > 0)&&(path.size()<500)) {
while ((currentHeight > 0)
&& (currentPosition.getDistance(end).compareTo(start.getDistance(end).scale(fracFinishPhase)) > 0)
&& (path.size() < 500)) {
// TimePoint nextTime = new MillisecondsTimePoint(currentTime.asMillis() + 30000);
@@ -137,19 +137,19 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
Bearing wLft;
Bearing wRght;
if (this.upwindLeg) {
wLft = pd.optimalDirectionsUpwind()[0];
wRght = pd.optimalDirectionsUpwind()[1];
wLft = pd.optimalDirectionsUpwind()[0];
wRght = pd.optimalDirectionsUpwind()[1];
} else {
wLft = pd.optimalDirectionsDownwind()[0];
wRght = pd.optimalDirectionsDownwind()[1];
wLft = pd.optimalDirectionsDownwind()[0];
wRght = pd.optimalDirectionsDownwind()[1];
}
// Bearing wDirect = currentPosition.getBearingGreatCircle(end);
// SpeedWithBearing sWDirect = pd.getSpeedAtBearing(wDirect);
SpeedWithBearing sWLft = pd.getSpeedAtBearing(wLft);
SpeedWithBearing sWRght = pd.getSpeedAtBearing(wRght);
logger.fine("left boat speed:" + sWLft.getKnots() + " angle:" + sWLft.getBearing().getDegrees() + " right boat speed:"
+ sWRght.getKnots() + " angle:" + sWRght.getBearing().getDegrees());
logger.fine("left boat speed:" + sWLft.getKnots() + " angle:" + sWLft.getBearing().getDegrees()
+ " right boat speed:" + sWRght.getKnots() + " angle:" + sWRght.getBearing().getDegrees());
TimePoint wTime = new MillisecondsTimePoint(currentTime.asMillis() + windpred);
// Position pWDirect = sWDirect.travelTo(currentPosition, currentTime, wTime);
@@ -170,12 +170,12 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
Wind lWind = wf.getWind(new TimedPositionWithSpeedImpl(currentTime, pWLft, null));
logger.fine("lWind speed:" + lWind.getKnots() + " angle:" + lWind.getBearing().getDegrees());
// System.out.println("Left WindBear: " + (lWind.getBearing().getDegrees() - bearStart.getDegrees()));
pd.setWind(lWind);
pd.setWind(lWind);
Bearing lft;
if (this.upwindLeg) {
lft = pd.optimalDirectionsUpwind()[0];
lft = pd.optimalDirectionsUpwind()[0];
} else {
lft = pd.optimalDirectionsDownwind()[0];
lft = pd.optimalDirectionsDownwind()[0];
}
slft = pd.getSpeedAtBearing(lft);
@@ -185,17 +185,17 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
pd.setWind(rWind);
Bearing rght;
if (this.upwindLeg) {
rght = pd.optimalDirectionsUpwind()[1];
rght = pd.optimalDirectionsUpwind()[1];
} else {
rght = pd.optimalDirectionsDownwind()[1];
rght = pd.optimalDirectionsDownwind()[1];
}
srght = pd.getSpeedAtBearing(rght);
// System.out.println("Bearings : " + (lft.getDegrees() - bearStart.getDegrees()) + " "
// + (rght.getDegrees() - bearStart.getDegrees()));
logger.fine("left boat speed:" + slft.getKnots() + " angle:" + slft.getBearing().getDegrees() + " right boat speed:"
+ srght.getKnots() + " angle:" + srght.getBearing().getDegrees());
logger.fine("left boat speed:" + slft.getKnots() + " angle:" + slft.getBearing().getDegrees()
+ " right boat speed:" + srght.getKnots() + " angle:" + srght.getBearing().getDegrees());
/*
* if (prevDirection == 0) { directTime = new MillisecondsTimePoint(nextTimeVal); leftTime = new
@@ -235,7 +235,7 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
if (prevDirection == -1) {
if (startLeft) {
allRight = false;
allRight = false;
path.add(new TimedPositionWithSpeedImpl(nextTime, plft, lWind));
currentPosition = plft;
if (prevDirection == 2) {
@@ -246,7 +246,7 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
}
prevDirection = 1;
} else {
allLeft = false;
allLeft = false;
path.add(new TimedPositionWithSpeedImpl(nextTime, prght, rWind));
currentPosition = prght;
if (prevDirection == 1) {
@@ -260,7 +260,8 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
} else {
// System.out.println("Distance Left - Right: "+lDistCM+" - "+ rDistCM);
if (((lDistCM <= rDistCM) && (!allLeft || (stepsLeft < maxLeft))) || (allRight && (stepsRight >= maxRight))) {
if (((lDistCM <= rDistCM) && (!allLeft || (stepsLeft < maxLeft)))
|| (allRight && (stepsRight >= maxRight))) {
path.add(new TimedPositionWithSpeedImpl(nextTime, plft, lWind));
currentPosition = plft;
if (prevDirection == 2) {
@@ -287,7 +288,7 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
currentTime = nextTime;
Position posHeight = currentPosition.projectToLineThrough(start, bearStart);
currentHeight = start.getDistance(end).getMeters() - posHeight.getDistance(start).getMeters();
//System.out.println("Height to Target: "+height);
// System.out.println("Height to Target: "+height);
}
//
@@ -304,15 +305,17 @@ public class PathGeneratorOpportunistEuclidian extends PathGeneratorBase {
rightGoingTime = currentTime;
}
gen1Turner.setEvaluationParameters(true, currentPosition, end, leftGoingTime, timeStep / (5 * 3), 100, 0.1, this.upwindLeg);
gen1Turner.setEvaluationParameters(true, currentPosition, end, leftGoingTime, timeStep / (5 * 3), 100, 0.1,
this.upwindLeg);
Path leftPath = gen1Turner.getPath();
gen1Turner.setEvaluationParameters(false, currentPosition, end, rightGoingTime, timeStep / (5 * 3), 100, 0.1, this.upwindLeg);
gen1Turner.setEvaluationParameters(false, currentPosition, end, rightGoingTime, timeStep / (5 * 3), 100, 0.1,
this.upwindLeg);
Path rightPath = gen1Turner.getPath();
if ((leftPath.getPathPoints() != null) && (rightPath.getPathPoints() != null)) {
if (leftPath.getPathPoints().get(leftPath.getPathPoints().size() - 1).getTimePoint().asMillis() <= rightPath.getPathPoints()
.get(rightPath.getPathPoints().size() - 1).getTimePoint().asMillis()) {
if (leftPath.getPathPoints().get(leftPath.getPathPoints().size() - 1).getTimePoint().asMillis() <= rightPath
.getPathPoints().get(rightPath.getPathPoints().size() - 1).getTimePoint().asMillis()) {
path.addAll(leftPath.getPathPoints());
} else {
path.addAll(rightPath.getPathPoints());
@@ -739,8 +739,16 @@ public class PathGeneratorTreeGrow extends PathGeneratorBase {
// add final position (rescaled before to end on height of target)
path.add(new TimedPositionWithSpeedImpl(bestCand.pos.getTimePoint(), bestCand.pos.getPosition(), null));
return new PathImpl(path, wf);
// maximum turn time for one-turner simulation, otherwise zero
long maxTurnTime = 0;
if (this.maxTurns == 1) {
int turnMiddle = 1000;
if (bestCand != null) {
turnMiddle = bestCand.getIndexOfTurnRL();
maxTurnTime = turnMiddle * this.usedTimeStep;
}
}
return new PathImpl(path, wf, maxTurnTime);
}
}
@@ -27,15 +27,21 @@ public class PathImpl implements Path, Serializable {
private static final long serialVersionUID = -6354445155884413937L;
private List<TimedPositionWithSpeed> pathPoints;
private WindField windField;
private long maxTurnTime;
private static final double TRESHOLD_DEGREES = 25.0;
private static final double THRESHOLD_DISTANCE_METERS = 15.0;
public PathImpl(List<TimedPositionWithSpeed> pointsList, WindField wf) {
this.pathPoints = pointsList;
this.windField = wf;
this.maxTurnTime = 0;
}
public PathImpl(List<TimedPositionWithSpeed> pointsList, WindField wf, long maxTurnTime) {
this.pathPoints = pointsList;
this.windField = wf;
this.maxTurnTime = maxTurnTime;
}
@Override
@@ -48,6 +54,16 @@ public class PathImpl implements Path, Serializable {
this.pathPoints = pointsList;
}
@Override
public long getMaxTurnTime() {
return this.maxTurnTime;
}
@Override
public void setMaxTurnTime(long maxTurnTime) {
this.maxTurnTime = maxTurnTime;
}
@Override
public Path getEvenTimedPath(long timestep) {
return new PathImpl(this.getEvenTimedPathAsList(timestep), this.windField);
@@ -65,9 +65,38 @@ public class SailingSimulatorImpl implements SailingSimulator {
}
@Override
public Path getPath(PathType pathType) {
// TODO: de-scramble implementation of getAllPaths() to focus on just one path fpr multi-threaded execution
return null;
public Path getPath(PathType pathType, MaximumTurnTimes maxTurnTimes) {
PathGeneratorTreeGrow genTreeGrow;
PathGeneratorOpportunistEuclidian genOpportunistic;
Path path = null;
switch (pathType) {
case OMNISCIENT:
genTreeGrow = new PathGeneratorTreeGrow(this.simulationParameters); // instantiate heuristic searcher
genTreeGrow.setEvaluationParameters(null, 0, null); // allow for arbitrary many turns
path = genTreeGrow.getPath();
case ONE_TURNER_LEFT:
genTreeGrow = new PathGeneratorTreeGrow(this.simulationParameters); // instantiate heuristic searcher
genTreeGrow.setEvaluationParameters("L", 1, null); // start left and limit to one turn
path = genTreeGrow.getPath();
case ONE_TURNER_RIGHT:
genTreeGrow = new PathGeneratorTreeGrow(this.simulationParameters); // instantiate heuristic searcher
genTreeGrow.setEvaluationParameters("R", 1, null); // start right and limit to one turn
path = genTreeGrow.getPath();
case OPPORTUNIST_LEFT:
genOpportunistic = new PathGeneratorOpportunistEuclidian(this.simulationParameters);
genOpportunistic.setEvaluationParameters(maxTurnTimes, true);
path = genOpportunistic.getPath();
case OPPORTUNIST_RIGHT:
genOpportunistic = new PathGeneratorOpportunistEuclidian(this.simulationParameters);
genOpportunistic.setEvaluationParameters(maxTurnTimes, false);
path = genOpportunistic.getPath();
}
return path;
}
@Override
@@ -122,16 +151,17 @@ public class SailingSimulatorImpl implements SailingSimulator {
// get instance of heuristic searcher
PathGeneratorTreeGrow genTreeGrow = new PathGeneratorTreeGrow(this.simulationParameters);
MaximumTurnTimes maxTurnTimes = new MaximumTurnTimes(1000000000, 1000000000);
// search best left-starting 1-turner
genTreeGrow.setEvaluationParameters("L", 1, null);
Path leftPath = genTreeGrow.getPath();
PathCandidate leftBestCand = genTreeGrow.getBestCand();
int left1TurnMiddle = 1000;
long left1TurnMidtime = 1000000000;
long left1TurnTimestep = genTreeGrow.getUsedTimeStep();
if (leftBestCand != null) {
left1TurnMiddle = leftBestCand.getIndexOfTurnLR();
left1TurnMidtime = left1TurnMiddle * left1TurnTimestep;
maxTurnTimes.left = left1TurnMiddle * left1TurnTimestep;
}
// search best right-starting 1-turner
@@ -139,11 +169,10 @@ public class SailingSimulatorImpl implements SailingSimulator {
Path rightPath = genTreeGrow.getPath();
PathCandidate rightBestCand = genTreeGrow.getBestCand();
int right1TurnMiddle = 1000;
long right1TurnMidtime = 1000000000;
long right1TurnTimestep = genTreeGrow.getUsedTimeStep();
if (rightBestCand != null) {
right1TurnMiddle = rightBestCand.getIndexOfTurnRL();
right1TurnMidtime = right1TurnMiddle * right1TurnTimestep;
maxTurnTimes.right = right1TurnMiddle * right1TurnTimestep;
}
Path optPath = null;
@@ -162,14 +191,14 @@ public class SailingSimulatorImpl implements SailingSimulator {
// PathGeneratorOpportunistVMG genOpportunistic = new PathGeneratorOpportunistVMG(simulationParameters);
// left-starting opportunist
genOpportunistic.setEvaluationParameters(left1TurnMidtime, right1TurnMidtime, true);
genOpportunistic.setEvaluationParameters(maxTurnTimes, true);
oppPathL = genOpportunistic.getPath();
if (genOpportunistic.getTurns() == 1) {
oppPathL = leftPath;
}
// right-starting opportunist
genOpportunistic.setEvaluationParameters(left1TurnMidtime, right1TurnMidtime, false);
genOpportunistic.setEvaluationParameters(maxTurnTimes, false);
oppPathR = genOpportunistic.getPath();
if (genOpportunistic.getTurns() == 1) {
oppPathR = rightPath;
@@ -1,14 +0,0 @@
package com.sap.sailing.simulator.impl;
import java.util.concurrent.Executor;
import com.sap.sailing.simulator.SimulationService;
import com.sap.sailing.simulator.SimulationServiceFactory;
public class SimulationServiceFactoryImpl implements SimulationServiceFactory {
public SimulationService getService(Executor executor) {
return new SimulationServiceImpl(executor);
}
}
@@ -1,108 +0,0 @@
package com.sap.sailing.simulator.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
import com.sap.sailing.simulator.Path;
import com.sap.sailing.simulator.PathType;
import com.sap.sailing.simulator.SailingSimulator;
import com.sap.sailing.simulator.SimulationParameters;
import com.sap.sailing.simulator.SimulationService;
public class SimulationServiceImpl implements SimulationService {
private Executor executor;
private SailingSimulator simulator;
public SimulationServiceImpl(Executor executor) {
this.executor = executor;
// TODO: add smart-future-cache for simulation
}
public Map<PathType, Path> getAllPaths(SimulationParameters simuPars) {
// TODO: check smart-future-cache
this.simulator = new SailingSimulatorImpl(simuPars);
Map<PathType, Path> result = new HashMap<PathType, Path>();
// schedule omniscient task
FutureTask<Path> taskOmniscient = new FutureTask<Path>(() -> simulator.getPath(PathType.OMNISCIENT));
executor.execute(taskOmniscient);
// schedule 1-turner tasks
FutureTask<Path> task1TurnerLeft = new FutureTask<Path>(() -> simulator.getPath(PathType.ONE_TURNER_LEFT));
FutureTask<Path> task1TurnerRight = new FutureTask<Path>(() -> simulator.getPath(PathType.ONE_TURNER_RIGHT));
executor.execute(task1TurnerLeft);
executor.execute(task1TurnerRight);
// collect 1-turner results
try {
result.put(PathType.ONE_TURNER_LEFT, task1TurnerLeft.get());
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
try {
result.put(PathType.ONE_TURNER_RIGHT, task1TurnerRight.get());
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
// schedule opportunist tasks (which depend on 1-turner results)
FutureTask<Path> taskOpportunistLeft = new FutureTask<Path>(() -> simulator.getPath(PathType.OPPORTUNIST_LEFT));
FutureTask<Path> taskOpportunistRight = new FutureTask<Path>(
() -> simulator.getPath(PathType.OPPORTUNIST_RIGHT));
executor.execute(taskOpportunistLeft);
executor.execute(taskOpportunistRight);
// collect opportunist results
try {
result.put(PathType.OPPORTUNIST_LEFT, taskOpportunistLeft.get());
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
try {
result.put(PathType.OPPORTUNIST_RIGHT, taskOpportunistRight.get());
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
// collect omniscient result (last, since usually slowest calculation)
try {
result.put(PathType.OMNISCIENT, taskOmniscient.get());
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
// TODO: update smart-future-cache
// return combined result
return result;
}
@Override
public Map<PathType, Path> getAllPathsEvenTimed(SimulationParameters simuPars, long millisecondsStep) {
Map<PathType, Path> allTimedPaths = new HashMap<PathType, Path>();
Map<PathType, Path> allPaths = this.getAllPaths(simuPars);
for (Entry<PathType, Path> entry : allPaths.entrySet()) {
PathType pathType = entry.getKey();
Path pathValue = entry.getValue();
allTimedPaths.put(pathType, pathValue.getEvenTimedPath(millisecondsStep));
}
return allTimedPaths;
}
}