Merge remote-tracking branch 'server/master'

This commit is contained in:
Axel Uhl committed 2015-07-20 18:09:05 +02:00
commit c81ca32c8c
44 files changed
+406 -246

No files matched your search

@@ -7,10 +7,6 @@ import com.sap.sse.common.Util.Pair;
public interface PolarSheetsXYDiagramData extends Serializable {
List<Pair<Double, Double>> getPointsForAverageSpeedMovingAverage(Tack tack, LegType legType);
List<Pair<Double, Double>> getPointsForAverageConfidence(Tack tack, LegType legType);
List<Pair<Double, Double>> getPointsForAverageSpeedRegression(Tack tack, LegType legType);
}
@@ -15,29 +15,11 @@ public class PolarSheetsXYDiagramDataImpl implements PolarSheetsXYDiagramData {
PolarSheetsXYDiagramDataImpl() {
}
private Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> pointsForAverageSpeedMovingAverage;
private Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> pointsForAverageSpeedRegression;
private Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> pointsForAverageConfidence;
public PolarSheetsXYDiagramDataImpl(
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> movingAverageSpeedDataLists,
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> regressionSpeedDataLists,
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> averageConfidenceDataLists) {
pointsForAverageSpeedMovingAverage = movingAverageSpeedDataLists;
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> regressionSpeedDataLists) {
pointsForAverageSpeedRegression = regressionSpeedDataLists;
pointsForAverageConfidence = averageConfidenceDataLists;
}
@Override
public List<Pair<Double, Double>> getPointsForAverageSpeedMovingAverage(Tack tack, LegType legType) {
return pointsForAverageSpeedMovingAverage.get(new Pair<LegType, Tack>(legType, tack));
}
@Override
public List<Pair<Double, Double>> getPointsForAverageConfidence(Tack tack, LegType legType) {
return pointsForAverageConfidence.get(new Pair<LegType, Tack>(legType, tack));
}
@Override
@@ -8,6 +8,7 @@ import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.common.Bearing;
@@ -51,36 +52,6 @@ public interface PolarDataService {
SpeedWithConfidence<Void> getSpeed(BoatClass boatClass, Speed windSpeed, Bearing trueWindAngle)
throws NotEnoughDataHasBeenAddedException;
/**
*
* @param boatClass
* @param windSpeed
* @param legType
* Should be {@link LegType#UPWIND} or {@link LegType#DOWNWIND}, there is no information for other
* courses yet. Use getSpeed for the desired angle to get rawer information on other courses for now.
* @param tack
* Polar data can vary depending on the tack the boat is on.
* @param useRegressionForSpeed TODO
* @return The estimated average speed of a boat for the supplied parameters with the estimated average bearing to
* the true wind and a confidence which consists of the confidences of the wind speed, and boat speed sources (50%)
* and a confidence calculated using the amount of underlying fixes (50%). 0 <= confidence < 1<br/>
* A value with zero confidence doesn't have any significance!<br/>
* <br/>
*
* The bearing is somewhere between -179 to +180<br/>
* <br/>
*
* Get the speed using returnValue.getObject()<br/>
* <br/>
*
* Returns null if the leg type is not up or downwind.
*
* @throws NotEnoughDataHasBeenAddedException
* If there is not enough data to supply a value with some kind of significance.
*/
SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
LegType legType, Tack tack, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException;
/**
* Generates a polar sheet for given races and settings using the provided executor for the worker threads. This
@@ -242,5 +213,9 @@ public interface PolarDataService {
*/
void unregisterListener(BoatClass boatClass, PolarsChangedListener listener);
void registerDomainFactory(DomainFactory domainFactory);
void unregisterDomainFactory(DomainFactory domainFactory);
}
@@ -4,12 +4,9 @@ import java.util.List;
import org.moxieapps.gwt.highcharts.client.AxisTitle;
import org.moxieapps.gwt.highcharts.client.Chart;
import org.moxieapps.gwt.highcharts.client.PlotLine;
import org.moxieapps.gwt.highcharts.client.Point;
import org.moxieapps.gwt.highcharts.client.Series;
import org.moxieapps.gwt.highcharts.client.Series.Type;
import org.moxieapps.gwt.highcharts.client.plotOptions.Marker;
import org.moxieapps.gwt.highcharts.client.plotOptions.SplinePlotOptions;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -58,33 +55,14 @@ public class PolarSheetsXYDiagramPopupPanel extends DialogBox {
}
private void addSpeedAndConfidenceSeriesForTackAndLegType(PolarSheetsXYDiagramData result, Tack tack, LegType legType, boolean showByDefault) {
Point[] pointsForUpwindStarboardAverageSpeedMovingAverage = toPointArray(result.getPointsForAverageSpeedMovingAverage(tack, legType));
Series speedSeriesMovingAverage = chart.createSeries();
speedSeriesMovingAverage.setName(tack + " " + legType + " Speed - MovingAverage");
speedSeriesMovingAverage.setPoints(pointsForUpwindStarboardAverageSpeedMovingAverage);
chart.addSeries(speedSeriesMovingAverage, false, false);
Point[] pointsForUpwindStarboardAverageSpeedRegression = toPointArray(result.getPointsForAverageSpeedRegression(tack, legType));
Series speedSeriesRegression = chart.createSeries();
speedSeriesRegression.setName(tack + " " + legType + " Speed - Regression");
speedSeriesRegression.setPoints(pointsForUpwindStarboardAverageSpeedRegression);
chart.addSeries(speedSeriesRegression, false, false);
Point[] pointsForUpwindStarboardAverageConfidence = toPointArray(result.getPointsForAverageConfidence(tack, legType));
Series confidenceSeries = chart
.createSeries()
.setYAxis(1)
.setType(Series.Type.SPLINE)
.setPlotOptions(
new SplinePlotOptions().setColor("#AA4643").setMarker(new Marker().setEnabled(false))
.setDashStyle(PlotLine.DashStyle.SHORT_DOT));
confidenceSeries.setName(tack + " " + legType + " Confidence");
confidenceSeries.setPoints(pointsForUpwindStarboardAverageConfidence);
chart.addSeries(confidenceSeries, false, false);
if (!showByDefault) {
speedSeriesRegression.setVisible(false, false);
confidenceSeries.setVisible(false, false);
}
}
@@ -61,10 +61,10 @@ import com.sap.sailing.domain.abstractlog.AbstractLog;
import com.sap.sailing.domain.abstractlog.AbstractLogEvent;
import com.sap.sailing.domain.abstractlog.MultiLogAnalyzer;
import com.sap.sailing.domain.abstractlog.impl.AllEventsOfTypeFinder;
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogEventFactory;
import com.sap.sailing.domain.abstractlog.race.RaceLogFixedMarkPassingEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFlagEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogSuppressedMarkPassingsEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.AbortingFlagFinder;
@@ -5585,45 +5585,20 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
@Override
public PolarSheetsXYDiagramData createXYDiagramForBoatClass(String boatClassName) {
BoatClass boatClass = getService().getBaseDomainFactory().getOrCreateBoatClass(boatClassName);
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> movingAverageSpeedDataLists = new HashMap<>();
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> regressionSpeedDataLists = new HashMap<>();
Map<Pair<LegType, Tack>, List<Pair<Double, Double>>> averageConfidenceDataLists = new HashMap<>();
for (LegType legType : new LegType[] { LegType.UPWIND, LegType.DOWNWIND }) {
for (Tack tack : new Tack[] { Tack.PORT, Tack.STARBOARD }) {
movingAverageSpeedDataLists.put(new Pair<LegType, Tack>(legType, tack),
new ArrayList<Pair<Double, Double>>());
regressionSpeedDataLists.put(new Pair<LegType, Tack>(legType, tack),
new ArrayList<Pair<Double, Double>>());
averageConfidenceDataLists.put(new Pair<LegType, Tack>(legType, tack),
new ArrayList<Pair<Double, Double>>());
}
}
for (double windInKnots = 0.1; windInKnots < 30; windInKnots = windInKnots + 0.1) {
for (LegType legType : new LegType[] { LegType.UPWIND, LegType.DOWNWIND }) {
for (Tack tack : new Tack[] { Tack.PORT, Tack.STARBOARD }) {
try {
SpeedWithBearingWithConfidence<Void> averageUpwindStarboardMovingAverage = getService()
.getPolarDataService().getAverageSpeedWithBearing(boatClass,
new KnotSpeedImpl(windInKnots), legType, tack, false);
movingAverageSpeedDataLists.get(new Pair<LegType, Tack>(legType, tack)).add(
new Pair<Double, Double>(windInKnots, averageUpwindStarboardMovingAverage.getObject()
.getKnots()));
averageConfidenceDataLists.get(new Pair<LegType, Tack>(legType, tack)).add(
new Pair<Double, Double>(windInKnots, averageUpwindStarboardMovingAverage
.getConfidence()));
} catch (NotEnoughDataHasBeenAddedException e) {
// Do not add a point to the result
}
try {
SpeedWithBearingWithConfidence<Void> averageUpwindStarboardRegression = getService()
.getPolarDataService().getAverageSpeedWithBearing(boatClass,
new KnotSpeedImpl(windInKnots), legType, tack, true);
new KnotSpeedImpl(windInKnots), legType, tack);
regressionSpeedDataLists.get(new Pair<LegType, Tack>(legType, tack)).add(
new Pair<Double, Double>(windInKnots, averageUpwindStarboardRegression.getObject()
@@ -5635,8 +5610,7 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
}
PolarSheetsXYDiagramData data = new PolarSheetsXYDiagramDataImpl(movingAverageSpeedDataLists,
regressionSpeedDataLists, averageConfidenceDataLists);
PolarSheetsXYDiagramData data = new PolarSheetsXYDiagramDataImpl(regressionSpeedDataLists);
return data;
}
@@ -49,10 +49,14 @@ import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.WindWithConfidence;
import com.sap.sailing.domain.tracking.impl.DynamicGPSFixMovingTrackImpl;
import com.sap.sailing.domain.tracking.impl.WindWithConfidenceImpl;
import com.sap.sailing.polars.mining.BearingClusterGroup;
import com.sap.sailing.polars.mining.CubicRegressionPerCourseProcessor;
import com.sap.sailing.polars.mining.PolarDataMiner;
import com.sap.sailing.polars.mining.SpeedRegressionPerAngleClusterProcessor;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.datamining.data.ClusterGroup;
public class PolarDataMinerTest {
@@ -74,11 +78,19 @@ public class PolarDataMinerTest {
false, 3);
}
private ClusterGroup<Bearing> createAngleClusterGroup() {
return new BearingClusterGroup(0, 180, 5);
}
@Ignore
@Test
public void testGrouping() throws InterruptedException, TimeoutException, NoSuchMethodException,
NotEnoughDataHasBeenAddedException {
PolarDataMiner miner = new PolarDataMiner(createTestPolarSettings());
PolarSheetGenerationSettings settings = createTestPolarSettings();
ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup();
PolarDataMiner miner = new PolarDataMiner(settings,
new CubicRegressionPerCourseProcessor(),
new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup), angleClusterGroup);
BoatClass mockedBoatClass = mock(BoatClass.class);
@@ -19,7 +19,9 @@ Require-Bundle:
com.sap.sse,
com.sap.sse.shared.android,
org.apache.commons.math;bundle-version="2.1.0",
org.eclipse.osgi
org.eclipse.osgi,
com.sap.sse.replication;bundle-version="1.0.0",
com.sap.sse.operationaltransformation;bundle-version="1.0.0"
Import-Package:
com.sap.sailing.util,
com.sap.sse.common
@@ -0,0 +1,8 @@
package com.sap.sailing.polars;
import com.sap.sailing.polars.impl.PolarDataServiceImpl;
import com.sap.sse.replication.OperationWithResult;
public interface PolarDataOperation<T> extends OperationWithResult<PolarDataServiceImpl, T>{
}
@@ -14,6 +14,8 @@ import com.sap.sse.datamining.impl.data.FixClusterGroup;
public class SpeedClusterGroup extends FixClusterGroup<Speed> {
private static final long serialVersionUID = -3428022721991223921L;
/**
* A {@link SpeedClusterGroup} lets the user set the level mids for all its clusters. The Boundaries will
* automatically be determined. They are in the middle between each level mid but only if the distance between level
@@ -1,6 +1,8 @@
package com.sap.sailing.polars.impl;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.logging.Logger;
@@ -9,6 +11,7 @@ import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sse.replication.Replicable;
public class Activator implements BundleActivator {
@@ -19,7 +22,11 @@ public class Activator implements BundleActivator {
@Override
public void start(BundleContext context) throws Exception {
logger.info("Registering PolarDataService");
registrations.add(context.registerService(PolarDataService.class, new PolarDataServiceImpl(), null));
PolarDataServiceImpl service = new PolarDataServiceImpl();
registrations.add(context.registerService(PolarDataService.class, service, null));
final Dictionary<String, String> replicableServiceProperties = new Hashtable<>();
replicableServiceProperties.put(Replicable.OSGi_Service_Registry_ID_Property_Name, service.getId().toString());
registrations.add(context.registerService(Replicable.class.getName(), service, replicableServiceProperties));
}
@Override
@@ -1,13 +1,23 @@
package com.sap.sailing.polars.impl;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
import com.sap.sailing.domain.base.SpeedWithConfidence;
import com.sap.sailing.domain.base.impl.SpeedWithBearingWithConfidenceImpl;
@@ -22,17 +32,28 @@ import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
import com.sap.sailing.domain.common.confidence.impl.BearingWithConfidenceImpl;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarDataService;
import com.sap.sailing.domain.polars.PolarsChangedListener;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.polars.PolarDataOperation;
import com.sap.sailing.polars.aggregation.PolarFixAggregator;
import com.sap.sailing.polars.aggregation.SimplePolarFixRaceInterval;
import com.sap.sailing.polars.data.PolarFix;
import com.sap.sailing.polars.generation.PolarSheetGenerator;
import com.sap.sailing.polars.mining.BearingClusterGroup;
import com.sap.sailing.polars.mining.CubicRegressionPerCourseProcessor;
import com.sap.sailing.polars.mining.PolarDataMiner;
import com.sap.sailing.polars.mining.SpeedRegressionPerAngleClusterProcessor;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.datamining.data.ClusterGroup;
import com.sap.sse.replication.OperationExecutionListener;
import com.sap.sse.replication.OperationWithResult;
import com.sap.sse.replication.ReplicationMasterDescriptor;
import com.sap.sse.replication.impl.OperationWithResultWithIdWrapper;
import com.sap.sse.replication.impl.ReplicableWithObjectInputStream;
import com.sap.sse.util.SmartFutureCache;
/**
@@ -43,16 +64,48 @@ import com.sap.sse.util.SmartFutureCache;
* @author Frederik Petersen (D054528)
*
*/
public class PolarDataServiceImpl implements PolarDataService {
public class PolarDataServiceImpl implements PolarDataService, ReplicableWithObjectInputStream<PolarDataServiceImpl, PolarDataOperation<?>>{
private final PolarDataMiner polarDataMiner;
private static final Logger logger = Logger.getLogger(PolarDataServiceImpl.class.getSimpleName());
private PolarDataMiner polarDataMiner;
private final ConcurrentHashMap<OperationExecutionListener<PolarDataServiceImpl>, OperationExecutionListener<PolarDataServiceImpl>> operationExecutionListeners;
/**
* The master from which this replicable is currently replicating, or <code>null</code> if this replicable is not
* currently replicated from any master.
*/
private ReplicationMasterDescriptor replicatingFromMaster;
private final Set<OperationWithResult<PolarDataServiceImpl, ?>> operationsSentToMasterForReplication;
private ThreadLocal<Boolean> currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster = ThreadLocal
.withInitial(() -> false);
private DomainFactory domainFactory;
public PolarDataServiceImpl() {
this.polarDataMiner = new PolarDataMiner();
PolarSheetGenerationSettings settings = PolarSheetGenerationSettingsImpl.createBackendPolarSettings();
ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup();
CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor = new CubicRegressionPerCourseProcessor();
SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor = new SpeedRegressionPerAngleClusterProcessor(
angleClusterGroup);
this.polarDataMiner = new PolarDataMiner(settings, cubicRegressionPerCourseProcessor,
speedRegressionPerAngleClusterProcessor, angleClusterGroup);
this.operationsSentToMasterForReplication = new HashSet<>();
this.operationExecutionListeners = new ConcurrentHashMap<>();
}
private ClusterGroup<Bearing> createAngleClusterGroup() {
return new BearingClusterGroup(0, 180, 5);
}
@Override
public SpeedWithConfidence<Void> getSpeed(BoatClass boatClass, Speed windSpeed, Bearing trueWindAngle) throws NotEnoughDataHasBeenAddedException {
if (polarDataMiner == null) {
throw new NotEnoughDataHasBeenAddedException("Polar Data Miner is currently unavailable. Maybe we are in the process of replication initial load?");
}
return polarDataMiner.estimateBoatSpeed(boatClass, windSpeed, trueWindAngle);
}
@@ -64,9 +117,12 @@ public class PolarDataServiceImpl implements PolarDataService {
@Override
public SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
LegType legType, Tack tack, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException {
LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException {
if (polarDataMiner == null) {
throw new NotEnoughDataHasBeenAddedException("Polar Data Miner is currently unavailable. Maybe we are in the process of replication initial load?");
}
SpeedWithBearingWithConfidence<Void> averageSpeedAndCourseOverGround = polarDataMiner
.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, useRegressionForSpeed);
.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
if (tack == Tack.PORT) {
//Negative twa
DegreeBearingImpl bearing = new DegreeBearingImpl(-averageSpeedAndCourseOverGround.getObject().getBearing()
@@ -185,19 +241,16 @@ public class PolarDataServiceImpl implements PolarDataService {
if (boatClass == null || windSpeed == null) {
throw new IllegalArgumentException("Boatclass and windspeed cannot be null.");
}
SpeedWithBearingWithConfidence<Void> speed = polarDataMiner.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType, true);
if (polarDataMiner == null) {
throw new NotEnoughDataHasBeenAddedException("Polar Data Miner is currently unavailable. Maybe we are in the process of replication initial load?");
}
SpeedWithBearingWithConfidence<Void> speed = polarDataMiner.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
Bearing bearing = new DegreeBearingImpl(speed.getObject().getBearing().getDegrees() * 2);
BearingWithConfidence<Void> bearingWithConfidence = new BearingWithConfidenceImpl<Void>(bearing, speed.getConfidence(),
null);
return bearingWithConfidence;
}
@Override
public SpeedWithBearingWithConfidence<Void> getAverageSpeedWithBearing(BoatClass boatClass, Speed windSpeed,
LegType legType, Tack tack) throws NotEnoughDataHasBeenAddedException {
return getAverageSpeedWithBearing(boatClass, windSpeed, legType, tack, true);
}
@Override
public void insertExistingFixes(TrackedRace trackedRace) {
for (Competitor competitor : trackedRace.getRace().getCompetitors()) {
@@ -217,4 +270,113 @@ public class PolarDataServiceImpl implements PolarDataService {
polarDataMiner.unregisterListener(boatClass, listener);
}
@Override
public void addOperationExecutionListener(OperationExecutionListener<PolarDataServiceImpl> listener) {
operationExecutionListeners.put(listener, listener);
}
@Override
public void removeOperationExecutionListener(OperationExecutionListener<PolarDataServiceImpl> listener) {
operationExecutionListeners.remove(listener);
}
@Override
public void clearReplicaState() throws MalformedURLException, IOException, InterruptedException {
polarDataMiner = null;
}
@Override
public boolean isCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster() {
return currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster.get();
}
@Override
public void setCurrentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster(boolean b) {
currentlyFillingFromInitialLoadOrApplyingOperationReceivedFromMaster.set(b);
}
@Override
public Serializable getId() {
return getClass().getName();
}
@Override
public ObjectInputStream createObjectInputStreamResolvingAgainstCache(InputStream is) throws IOException {
ObjectInputStream ois;
if (domainFactory != null) {
ois = domainFactory.createObjectInputStreamResolvingAgainstThisFactory(is);
} else {
// TODO ensure that domainfactory is set here. Otherwise there can be issues with duplicate domain objects
logger.warning("PolarDataService didn't have a domain factory attached. Replication to this service could fail.");
ois = new ObjectInputStream(is);
}
return ois;
}
@Override
public void initiallyFillFromInternal(ObjectInputStream is) throws IOException, ClassNotFoundException,
InterruptedException {
PolarSheetGenerationSettings backendPolarSettings = (PolarSheetGenerationSettings) is.readObject();
CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor = (CubicRegressionPerCourseProcessor) is.readObject();
SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor = (SpeedRegressionPerAngleClusterProcessor) is.readObject();
polarDataMiner = new PolarDataMiner(backendPolarSettings,
cubicRegressionPerCourseProcessor, speedRegressionPerAngleClusterProcessor,
speedRegressionPerAngleClusterProcessor.getAngleCluster());
}
@Override
public void serializeForInitialReplicationInternal(ObjectOutputStream objectOutputStream) throws IOException {
objectOutputStream.writeObject(polarDataMiner.getPolarSheetGenerationSettings());
//objectOutputStream.writeObject(polarDataMiner.getMovingAverageProcessor());
objectOutputStream.writeObject(polarDataMiner.getCubicRegressionPerCourseProcessor());
objectOutputStream.writeObject(polarDataMiner.getSpeedRegressionPerAngleClusterProcessor());
}
@Override
public Iterable<OperationExecutionListener<PolarDataServiceImpl>> getOperationExecutionListeners() {
return operationExecutionListeners.keySet();
}
@Override
public ReplicationMasterDescriptor getMasterDescriptor() {
return replicatingFromMaster;
}
@Override
public void startedReplicatingFrom(ReplicationMasterDescriptor master) {
this.replicatingFromMaster = master;
}
@Override
public void stoppedReplicatingFrom(ReplicationMasterDescriptor master) {
this.replicatingFromMaster = null;
}
@Override
public boolean hasSentOperationToMaster(OperationWithResult<PolarDataServiceImpl, ?> operation) {
return this.operationsSentToMasterForReplication.contains(operation);
}
@Override
public void addOperationSentToMasterForReplication(
OperationWithResultWithIdWrapper<PolarDataServiceImpl, ?> operation) {
this.operationsSentToMasterForReplication.add(operation);
}
@Override
public void registerDomainFactory(DomainFactory domainFactory) {
this.domainFactory = domainFactory;
}
@Override
public void unregisterDomainFactory(DomainFactory domainFactory) {
if (this.domainFactory == domainFactory) {
this.domainFactory = null;
}
}
}
@@ -1,5 +1,6 @@
package com.sap.sailing.polars.mining;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
@@ -24,8 +25,9 @@ import com.sap.sailing.polars.regression.impl.IncrementalAnyOrderLeastSquaresImp
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util.Pair;
public class AngleAndSpeedRegression {
public class AngleAndSpeedRegression implements Serializable {
private static final long serialVersionUID = 6343595388753945979L;
private final IncrementalLeastSquares speedRegression = new IncrementalAnyOrderLeastSquaresImpl(3, false);
private final IncrementalLeastSquares angleRegression = new IncrementalAnyOrderLeastSquaresImpl(3);
@@ -1,7 +1,10 @@
package com.sap.sailing.polars.mining;
import java.io.Serializable;
public class AverageAngleContainer {
public class AverageAngleContainer implements Serializable {
private static final long serialVersionUID = -6370647955050312847L;
private int dataCount = 0;
private double angleSumDeg = 0.0;
private double averageAngleDeg = 0.0;
@@ -1,5 +1,6 @@
package com.sap.sailing.polars.mining;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
@@ -18,6 +19,8 @@ import com.sap.sse.i18n.ResourceBundleStringMessages;
public class BearingClusterGroup extends FixClusterGroup<Bearing>{
private static final long serialVersionUID = -3810975212669767738L;
public BearingClusterGroup(int startAngle, int endAngle, int clusterSize) {
super("", createClusters(startAngle, endAngle, clusterSize));
}
@@ -35,13 +38,7 @@ public class BearingClusterGroup extends FixClusterGroup<Bearing>{
private static ClusterBoundary<Bearing> createBoundary(double angleInDeg, ComparisonStrategy strategy) {
Bearing angle = new DegreeBearingImpl(angleInDeg);
Comparator<Bearing> comparator = new Comparator<Bearing>() {
@Override
public int compare(Bearing arg0, Bearing arg1) {
return new Double(arg0.getDegrees()).compareTo(new Double(arg1.getDegrees()));
}
};
Comparator<Bearing> comparator = new BearingComparator();
return new ComparatorClusterBoundary<Bearing>(angle, strategy, comparator);
}
@@ -50,5 +47,15 @@ public class BearingClusterGroup extends FixClusterGroup<Bearing>{
return "";
}
private static class BearingComparator implements Comparator<Bearing>, Serializable {
private static final long serialVersionUID = 8166601046140275541L;
@Override
public int compare(Bearing arg0, Bearing arg1) {
return new Double(arg0.getDegrees()).compareTo(new Double(arg1.getDegrees()));
}
};
}
@@ -1,5 +1,6 @@
package com.sap.sailing.polars.mining;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -22,17 +23,19 @@ import com.sap.sse.datamining.factories.GroupKeyFactory;
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
import com.sap.sse.datamining.shared.GroupKey;
public class CubicRegressionPerCourseProcessor implements Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void> {
public class CubicRegressionPerCourseProcessor implements
Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void>, Serializable {
private static final long serialVersionUID = 3059764273262382648L;
private static final Logger logger = Logger.getLogger(CubicRegressionPerCourseProcessor.class.getName());
private final Map<GroupKey, AngleAndSpeedRegression> regressions = new HashMap<>();
private ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners;
public CubicRegressionPerCourseProcessor(ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners) {
this.listeners = listeners;
}
/**
* FIXME Make sure replication and listeners interact correctly
*/
private transient ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners;
@Override
public boolean canProcessElements() {
@@ -146,6 +149,10 @@ public class CubicRegressionPerCourseProcessor implements Processor<GroupedDataE
throw new RuntimeException("Polar Data Miner failed.", failure);
}
public void setListeners(ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners) {
this.listeners = listeners;
}
@Override
public Class<GroupedDataEntry<GPSFixMovingWithPolarContext>> getInputType() {
@@ -187,4 +194,6 @@ public class CubicRegressionPerCourseProcessor implements Processor<GroupedDataE
return null;
}
}
@@ -10,7 +10,6 @@ import com.sap.sailing.domain.common.Bearing;
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.common.Speed;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.confidence.BearingWithConfidence;
@@ -28,12 +27,11 @@ import com.sap.sse.common.Util.Pair;
import com.sap.sse.datamining.data.Cluster;
import com.sap.sse.datamining.data.ClusterGroup;
public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKey, AngleClusterPolarClusterKey {
public class GPSFixMovingWithPolarContext implements LegTypePolarClusterKey, AngleClusterPolarClusterKey {
private final GPSFixMoving fix;
private final TrackedRace race;
private final Competitor competitor;
private final ClusterGroup<Speed> windSpeedClusterGroup;
private final Set<WindSource> windSourcesToExcludeForSpeed;
private final ClusterGroup<Bearing> angleClusterGroup;
private final BearingWithConfidence<Void> absTrueWindAngle;
@@ -42,11 +40,10 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
private LegType legType;
public GPSFixMovingWithPolarContext(GPSFixMoving fix, TrackedRace race, Competitor competitor,
ClusterGroup<Speed> windSpeedClusterGroup, ClusterGroup<Bearing> angleClusterGroup) {
ClusterGroup<Bearing> angleClusterGroup) {
this.fix = fix;
this.race = race;
this.competitor = competitor;
this.windSpeedClusterGroup = windSpeedClusterGroup;
this.angleClusterGroup = angleClusterGroup;
this.windSourcesToExcludeForSpeed = collectWindSourcesToIgnoreForSpeed();
this.absTrueWindAngle = computeTrueWindAngleAbsolute();
@@ -89,12 +86,6 @@ public class GPSFixMovingWithPolarContext implements MovingAveragePolarClusterKe
return result;
}
@Override
public Cluster<Speed> getWindSpeedCluster() {
final WindWithConfidence<Pair<Position, TimePoint>> windWithConfidence = getWind();
return windWithConfidence == null ? null : windSpeedClusterGroup.getClusterFor(windWithConfidence.getObject());
}
public WindWithConfidence<Pair<Position, TimePoint>> getWind() {
return wind;
}
@@ -1,6 +1,6 @@
package com.sap.sailing.polars.mining;
import java.util.Set;
import java.io.Serializable;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.SpeedWithBearingWithConfidence;
@@ -8,11 +8,11 @@ import com.sap.sailing.domain.common.LegType;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sse.datamining.components.Processor;
import com.sap.sse.datamining.data.ClusterGroup;
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
public interface MovingAverageProcessor extends Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void>{
public interface MovingAverageProcessor extends Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void>, Serializable {
SpeedWithBearingWithConfidence<Void> getAverageSpeedAndCourseOverGround(BoatClass boatClass,
Speed windSpeed, LegType legType) throws NotEnoughDataHasBeenAddedException;
Set<BoatClass> getAvailableBoatClasses();
ClusterGroup<Speed> getSpeedCluster();
}
@@ -1,9 +1,7 @@
package com.sap.sailing.polars.mining;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.BoatClass;
@@ -33,6 +31,8 @@ import com.sap.sse.datamining.shared.GroupKey;
public class MovingAverageProcessorImpl implements MovingAverageProcessor {
private static final long serialVersionUID = 9016357546663534562L;
private static final Logger logger = Logger.getLogger(MovingAverageProcessorImpl.class.getName());
private final Map<GroupKey, MovingAverageBoatSpeedEstimator> boatSpeedEstimators = new HashMap<>();
@@ -41,10 +41,6 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor {
private final ClusterGroup<Speed> speedClusterGroup;
private final Set<BoatClass> availableBoatClasses = new HashSet<>();
public MovingAverageProcessorImpl(ClusterGroup<Speed> speedClusterGroup) {
this.speedClusterGroup = speedClusterGroup;
}
@@ -79,7 +75,6 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor {
BearingWithConfidence<Void> angleToTheWind = fix.getAbsoluteAngleToTheWind();
WindWithConfidence<Pair<Position, TimePoint>> windSpeed = fix.getWind();
SpeedWithBearingWithConfidence<TimePoint> boatSpeedWithConfidence = fix.getBoatSpeed();
availableBoatClasses.add(element.getDataEntry().getBoatClass());
WindWithConfidence<Pair<Position, TimePoint>> windWithConfidenceForSpeed = windSpeed;
double confidenceForWindSpeed = windWithConfidenceForSpeed.getConfidence();
double confidenceForWindBearing = angleToTheWind.getConfidence();
@@ -158,10 +153,6 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor {
throw new RuntimeException("Polar Data Miner failed.", failure);
}
public Set<BoatClass> getAvailableBoatClasses() {
return availableBoatClasses;
}
@Override
public Class<GroupedDataEntry<GPSFixMovingWithPolarContext>> getInputType() {
// TODO Auto-generated method stub
@@ -218,4 +209,9 @@ public class MovingAverageProcessorImpl implements MovingAverageProcessor {
return compoundKey;
}
@Override
public ClusterGroup<Speed> getSpeedCluster() {
return speedClusterGroup;
}
}
@@ -36,10 +36,8 @@ import com.sap.sailing.domain.common.TrackedRaceStatusEnum;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedImpl;
import com.sap.sailing.domain.common.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.common.impl.PolarSheetGenerationSettingsImpl;
import com.sap.sailing.domain.common.impl.PolarSheetsDataImpl;
import com.sap.sailing.domain.common.impl.PolarSheetsHistogramDataImpl;
import com.sap.sailing.domain.common.impl.WindSpeedSteppingWithMaxDistance;
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
import com.sap.sailing.domain.polars.PolarsChangedListener;
@@ -61,7 +59,6 @@ public class PolarDataMiner {
private static final int EXECUTOR_QUEUE_SIZE = 100;
private static final int THREAD_POOL_SIZE = Math.max((int) (Runtime.getRuntime().availableProcessors() * (3.0/4.0)), 3);
private final ThreadPoolExecutor executor = createExecutor();
private final PolarSheetGenerationSettings backendPolarSheetGenerationSettings;
private final Map<TrackedRace, Set<GPSFixMovingWithOriginInfo>> fixesForRacesWhichAreStillLoading = new HashMap<>();
private final Queue<GPSFixMovingWithOriginInfo> fixQueue = new ConcurrentLinkedQueue<GPSFixMovingWithOriginInfo>();
@@ -70,6 +67,19 @@ public class PolarDataMiner {
private final ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners = new ConcurrentHashMap<>();
private ParallelFilteringProcessor<GPSFixMovingWithOriginInfo> preFilteringProcessor;
private final PolarSheetGenerationSettings backendPolarSheetGenerationSettings;
/**
* This processor uses two cubic regressions angle to the true wind over windspeed and boatspeed over windspeed for each
* course (legtype tack combination)
*/
private final CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor;
private final SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor;
private final ClusterGroup<Bearing> angleClusterGroup;
private ThreadPoolExecutor createExecutor() {
return new ThreadPoolExecutor(THREAD_POOL_SIZE, THREAD_POOL_SIZE, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(EXECUTOR_QUEUE_SIZE), new RejectedExecutionHandler() {
@@ -92,28 +102,16 @@ public class PolarDataMiner {
};
}
/**
* This processor keeps track of the moving average of the speed values and the average angle for each course (legtype tack combination)
*/
private MovingAverageProcessor movingAverageProcessor;
/**
* This processor uses two cubic regressions angle to the true wind over windspeed and boatspeed over windspeed for each
* course (legtype tack combination)
*/
private CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor;
private SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor;
private ParallelFilteringProcessor<GPSFixMovingWithOriginInfo> preFilteringProcessor;
public PolarDataMiner() {
this(PolarSheetGenerationSettingsImpl.createBackendPolarSettings());
}
public PolarDataMiner(PolarSheetGenerationSettings backendPolarSettings) {
public PolarDataMiner(PolarSheetGenerationSettings backendPolarSettings,
CubicRegressionPerCourseProcessor cubicRegressionPerCourseProcessor,
SpeedRegressionPerAngleClusterProcessor speedRegressionPerAngleClusterProcessor,
ClusterGroup<Bearing> angleClusterGroup) {
cubicRegressionPerCourseProcessor.setListeners(listeners);
speedRegressionPerAngleClusterProcessor.setListeners(listeners);
backendPolarSheetGenerationSettings = backendPolarSettings;
this.cubicRegressionPerCourseProcessor = cubicRegressionPerCourseProcessor;
this.speedRegressionPerAngleClusterProcessor = speedRegressionPerAngleClusterProcessor;
this.angleClusterGroup = angleClusterGroup;
try {
setUpWorkflow();
} catch (ClassCastException | NoSuchMethodException | SecurityException e) {
@@ -124,23 +122,6 @@ public class PolarDataMiner {
private void setUpWorkflow() throws ClassCastException, NoSuchMethodException,
SecurityException {
WindSpeedSteppingWithMaxDistance stepping = backendPolarSheetGenerationSettings.getWindSpeedStepping();
final ClusterGroup<Speed> speedClusterGroup = SpeedClusterGroupFromWindSteppingCreator
.createSpeedClusterGroupFrom(stepping);
movingAverageProcessor = new MovingAverageProcessorImpl(speedClusterGroup);
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> movingAverageGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
movingAverageGrouperResultReceivers.add(movingAverageProcessor);
Collection<ParameterizedFunction<?>> parameterizedDimensions = new ArrayList<>();
for (Function<?> function : PolarDataDimensionCollectionFactory.getMovingAverageClusterKeyDimensions()) {
parameterizedDimensions.add(new SimpleParameterizedFunction<>(function, ParameterProvider.NULL));
}
Processor<GPSFixMovingWithPolarContext, GroupedDataEntry<GPSFixMovingWithPolarContext>> movingAverageGroupingProcessor = new ParallelMultiDimensionsValueNestingGroupingProcessor<GPSFixMovingWithPolarContext>(
GPSFixMovingWithPolarContext.class, executor, movingAverageGrouperResultReceivers, parameterizedDimensions);
cubicRegressionPerCourseProcessor = new CubicRegressionPerCourseProcessor(listeners);
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerCourseGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
regressionPerCourseGrouperResultReceivers.add(cubicRegressionPerCourseProcessor);
@@ -151,8 +132,6 @@ public class PolarDataMiner {
Processor<GPSFixMovingWithPolarContext, GroupedDataEntry<GPSFixMovingWithPolarContext>> cubicRegressionPerCourseGroupingProcessor = new ParallelMultiDimensionsValueNestingGroupingProcessor<GPSFixMovingWithPolarContext>(
GPSFixMovingWithPolarContext.class, executor, regressionPerCourseGrouperResultReceivers, parameterizedDimensionsForCubicRegression);
ClusterGroup<Bearing> angleClusterGroup = createAngleClusterGroup();
speedRegressionPerAngleClusterProcessor = new SpeedRegressionPerAngleClusterProcessor(angleClusterGroup, listeners);
Collection<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>> regressionPerAngleClusterGrouperResultReceivers = new ArrayList<Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, ?>>();
regressionPerAngleClusterGrouperResultReceivers.add(speedRegressionPerAngleClusterProcessor);
@@ -166,7 +145,6 @@ public class PolarDataMiner {
Collection<Processor<GPSFixMovingWithPolarContext, ?>> filteringResultReceivers = new ArrayList<>();
filteringResultReceivers.add(movingAverageGroupingProcessor);
filteringResultReceivers.add(cubicRegressionPerCourseGroupingProcessor);
filteringResultReceivers.add(regressionPerAngleClusterGroupingProcessor);
@@ -185,7 +163,7 @@ public class PolarDataMiner {
protected GPSFixMovingWithPolarContext enrich(GPSFixMovingWithOriginInfo element) {
GPSFixMovingWithPolarContext result = null;
result = new GPSFixMovingWithPolarContext(element.getFix(), element.getTrackedRace(),
element.getCompetitor(), speedClusterGroup, angleClusterGroup);
element.getCompetitor(), angleClusterGroup);
return result;
}
};
@@ -216,10 +194,6 @@ public class PolarDataMiner {
}
private ClusterGroup<Bearing> createAngleClusterGroup() {
return new BearingClusterGroup(0, 180, 5);
}
public void addFix(GPSFixMoving fix, Competitor competitor, TrackedRace trackedRace) {
GPSFixMovingWithOriginInfo fixWithOriginInfo = new GPSFixMovingWithOriginInfo(fix, trackedRace, competitor);
if (trackedRace.getStatus().getStatus() == TrackedRaceStatusEnum.LOADING) {
@@ -387,7 +361,7 @@ public class PolarDataMiner {
}
public Set<BoatClass> getAvailableBoatClasses() {
return movingAverageProcessor.getAvailableBoatClasses();
return speedRegressionPerAngleClusterProcessor.getAvailableBoatClasses();
}
public int[] getDataCountsForWindSpeed(BoatClass boatClass, Speed windSpeed, int startAngleInclusive, int endAngleExclusive) {
@@ -403,13 +377,9 @@ public class PolarDataMiner {
}
public SpeedWithBearingWithConfidence<Void> getAverageSpeedAndCourseOverGround(BoatClass boatClass,
Speed windSpeed, LegType legType, boolean useRegressionForSpeed) throws NotEnoughDataHasBeenAddedException {
Speed windSpeed, LegType legType) throws NotEnoughDataHasBeenAddedException {
SpeedWithBearingWithConfidence<Void> averageSpeedAndCourseOverGround = null;
if (useRegressionForSpeed) {
averageSpeedAndCourseOverGround = cubicRegressionPerCourseProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
} else {
averageSpeedAndCourseOverGround = movingAverageProcessor.getAverageSpeedAndCourseOverGround(boatClass, windSpeed, legType);
}
return averageSpeedAndCourseOverGround;
}
@@ -458,4 +428,16 @@ public class PolarDataMiner {
listenersForBoatClass.remove(listener);
}
}
public CubicRegressionPerCourseProcessor getCubicRegressionPerCourseProcessor() {
return cubicRegressionPerCourseProcessor;
}
public SpeedRegressionPerAngleClusterProcessor getSpeedRegressionPerAngleClusterProcessor() {
return speedRegressionPerAngleClusterProcessor;
}
public PolarSheetGenerationSettings getPolarSheetGenerationSettings() {
return backendPolarSheetGenerationSettings;
}
}
@@ -1,6 +1,8 @@
package com.sap.sailing.polars.mining;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -27,7 +29,10 @@ import com.sap.sse.datamining.factories.GroupKeyFactory;
import com.sap.sse.datamining.impl.components.GroupedDataEntry;
import com.sap.sse.datamining.shared.GroupKey;
public class SpeedRegressionPerAngleClusterProcessor implements Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void>{
public class SpeedRegressionPerAngleClusterProcessor implements
Processor<GroupedDataEntry<GPSFixMovingWithPolarContext>, Void>, Serializable {
private static final long serialVersionUID = 3279917556091599077L;
private static final Logger logger = Logger.getLogger(CubicRegressionPerCourseProcessor.class.getName());
@@ -37,11 +42,15 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor<Groupe
private final ClusterGroup<Bearing> angleClusterGroup;
private final ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners;
/**
* FIXME make sure listeners and replication interact correctly
*/
private transient ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners;
public SpeedRegressionPerAngleClusterProcessor(ClusterGroup<Bearing> angleClusterGroup, ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners) {
private final Set<BoatClass> availableBoatClasses = new HashSet<BoatClass>();
public SpeedRegressionPerAngleClusterProcessor(ClusterGroup<Bearing> angleClusterGroup) {
this.angleClusterGroup = angleClusterGroup;
this.listeners = listeners;
}
@Override
@@ -70,6 +79,7 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor<Groupe
}
GPSFixMovingWithPolarContext fix = element.getDataEntry();
regression.addData(fix.getWind().getObject().getKnots(), fix.getBoatSpeed().getObject().getKnots());
availableBoatClasses.add(boatClass);
Set<PolarsChangedListener> listenersForBoatClass = listeners.get(fix.getBoatClass());
if (listenersForBoatClass != null) {
for (PolarsChangedListener listener : listenersForBoatClass) {
@@ -155,6 +165,14 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor<Groupe
return polynomialFunction;
}
public void setListeners(ConcurrentHashMap<BoatClass, Set<PolarsChangedListener>> listeners) {
this.listeners = listeners;
}
Set<BoatClass> getAvailableBoatClasses() {
return availableBoatClasses;
}
@Override
public Class<GroupedDataEntry<GPSFixMovingWithPolarContext>> getInputType() {
// TODO Auto-generated method stub
@@ -195,4 +213,8 @@ public class SpeedRegressionPerAngleClusterProcessor implements Processor<Groupe
return null;
}
public ClusterGroup<Bearing> getAngleCluster() {
return angleClusterGroup;
}
}
@@ -1,10 +1,13 @@
package com.sap.sailing.polars.mining;
import java.io.Serializable;
import com.sap.sailing.domain.common.Speed;
import com.sap.sailing.domain.common.WindSpeedStepping;
public class WindSpeedLevel {
public class WindSpeedLevel implements Serializable {
private static final long serialVersionUID = -4498750034316806342L;
private final int level;
private final WindSpeedStepping stepping;
@@ -1,5 +1,7 @@
package com.sap.sailing.polars.regression;
import java.io.Serializable;
import org.apache.commons.math.analysis.polynomials.PolynomialFunction;
import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
@@ -10,7 +12,7 @@ import com.sap.sailing.domain.polars.NotEnoughDataHasBeenAddedException;
* @author Frederik Petersen (D054528)
*
*/
public interface IncrementalLeastSquares {
public interface IncrementalLeastSquares extends Serializable {
/**
* Adds data to the least squares regression. This only updates the internal matrix and vector and will not trigger the
@@ -1,5 +1,6 @@
package com.sap.sailing.polars.regression.impl;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
@@ -29,6 +30,8 @@ import com.sap.sse.concurrent.NamedReentrantReadWriteLock;
*/
public class IncrementalAnyOrderLeastSquaresImpl implements IncrementalLeastSquares {
private static final long serialVersionUID = -5282614133220702724L;
private class NaNCheckerVisitor implements RealMatrixPreservingVisitor {
private boolean hasNaNEntry = false;
@@ -64,10 +67,10 @@ public class IncrementalAnyOrderLeastSquaresImpl implements IncrementalLeastSqua
private AtomicBoolean functionNeedsUpdate = new AtomicBoolean(true);
private final NamedReentrantReadWriteLock lock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresLock",
private transient NamedReentrantReadWriteLock lock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresLock",
false);
private final NamedReentrantReadWriteLock cacheLock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresCacheLock",
private transient NamedReentrantReadWriteLock cacheLock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresCacheLock",
true);
private PolynomialFunction cachedFunction;
@@ -297,6 +300,15 @@ public class IncrementalAnyOrderLeastSquaresImpl implements IncrementalLeastSqua
}
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
lock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresLock",
false);
cacheLock = new NamedReentrantReadWriteLock("IncrementalLeastSquaresCacheLock",
true);
}
@Override
public long getNumberOfAddedPoints() {
return numberOfPointsAdded.get();
@@ -122,7 +122,7 @@ public class PolarResource extends AbstractSailingServerResource {
try {
PolarDataService service = getService().getPolarDataService();
SpeedWithBearingWithConfidence<Void> speedWithBearing = service.getAverageSpeedWithBearing(boatClass,
windSpeed, legType, tack, true);
windSpeed, legType, tack);
String resultString = "Speed: " + speedWithBearing.getObject().getKnots() + "kn; Angle: "
+ speedWithBearing.getObject().getBearing().getDegrees() + "°; Confidence: "
+ speedWithBearing.getConfidence();
@@ -19,7 +19,7 @@
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-os ${target.os} -ws ${target.ws} -arch ${target.arch} -nl ${target.nl} -consoleLog -console -clean"/>
<stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.pde.ui.workbenchClasspathProvider"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djetty.port=8889 -Dreplication.exchangeName=sapsailinganalytics-replica -Declipse.ignoreApp=true -Dosgi.noShutdown=true&#13;&#10;-Dexpedition.udp.port=2011 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -XX:+UseMembar -Dmongo.dbName=replica -Dreplicate.on.start=com.sap.sailing.server.impl.RacingEventServiceImpl,com.sap.sse.security.impl.SecurityServiceImpl,com.sap.sse.filestorage.impl.FileStorageManagementServiceImpl,com.sap.sse.mail.impl.MailServiceImpl -Dreplicate.master.queue.host=127.0.0.1 -Dreplicate.master.queue.port=5672 -Dreplicate.master.servlet.port=8888 -Dreplicate.master.servlet.host=127.0.0.1 -Dreplicate.master.exchange.name=sapsailinganalytics"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djetty.port=8889 -Dreplication.exchangeName=sapsailinganalytics-replica -Declipse.ignoreApp=true -Dosgi.noShutdown=true&#13;&#10;-Dexpedition.udp.port=2011 -Xmx6000m -XX:+UseG1GC -Djetty.home=${project_loc:com.sap.sailing.server}/../target/configuration/jetty -Djava.util.logging.config.file=${project_loc:com.sap.sailing.server}/../target/configuration/logging_debug.properties -XX:+UseMembar -Dmongo.dbName=replica -Dreplicate.on.start=com.sap.sailing.server.impl.RacingEventServiceImpl,com.sap.sse.security.impl.SecurityServiceImpl,com.sap.sse.filestorage.impl.FileStorageManagementServiceImpl,com.sap.sse.mail.impl.MailServiceImpl,com.sap.sailing.polars.impl.PolarDataServiceImpl -Dreplicate.master.queue.host=127.0.0.1 -Dreplicate.master.queue.port=5672 -Dreplicate.master.servlet.port=8888 -Dreplicate.master.servlet.host=127.0.0.1 -Dreplicate.master.exchange.name=sapsailinganalytics"/>
<stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${workspace_loc}"/>
<stringAttribute key="pde.version" value="3.3"/>
<booleanAttribute key="show_selected_only" value="false"/>
@@ -3241,6 +3241,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
public void setPolarDataService(PolarDataService service) {
if (this.polarDataService == null) {
polarDataService = service;
polarDataService.registerDomainFactory(baseDomainFactory);
setPolarDataServiceOnAllTrackedRaces(service);
}
}
@@ -3266,6 +3267,7 @@ public class RacingEventServiceImpl implements RacingEventService, ClearStateTes
public void unsetPolarDataService(PolarDataService service) {
if (polarDataService == service) {
polarDataService.unregisterDomainFactory(baseDomainFactory);
polarDataService = null;
setPolarDataService(null);
}
@@ -132,7 +132,8 @@ public class PathImpl implements Path, Serializable {
if ((this.pathPoints.get(idx).getTimePoint().asMillis() >= nextTimePoint.asMillis())||(idx == this.pathPoints.size()-1)) {
if (idx == this.pathPoints.size()-1) {
// for the last step, next-time-point needs to be aligned to the time-range of the course
if (nextTimePoint.after(endTime)) {
nextTimePoint = endTime;
}
@@ -57,9 +57,9 @@ public class PolarDiagramGPS extends PolarDiagramBase {
for (int i = 0; i < windSpeeds.size(); i++) {
try {
beatPort = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i), LegType.UPWIND,
Tack.PORT, true).getObject();
Tack.PORT).getObject();
beatStar = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i), LegType.UPWIND,
Tack.STARBOARD, true).getObject();
Tack.STARBOARD).getObject();
} catch (NotEnoughDataHasBeenAddedException e) {
beatPort = null;
beatStar = null;
@@ -86,9 +86,9 @@ public class PolarDiagramGPS extends PolarDiagramBase {
for (int i = 0; i < windSpeeds.size(); i++) {
try {
jibePort = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i),
LegType.DOWNWIND, Tack.PORT, true).getObject();
LegType.DOWNWIND, Tack.PORT).getObject();
jibeStar = this.polarData.getAverageSpeedWithBearing(this.boatClass, windSpeeds.get(i),
LegType.DOWNWIND, Tack.STARBOARD, true).getObject();
LegType.DOWNWIND, Tack.STARBOARD).getObject();
} catch (NotEnoughDataHasBeenAddedException e) {
jibePort = null;
jibeStar = null;
@@ -146,13 +146,13 @@ public class PolarDiagramGPSDirect implements PolarDiagram, Serializable {
try {
if (beatPort == null) {
SpeedWithBearing beatPortRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
LegType.UPWIND, Tack.PORT, true).getObject();
LegType.UPWIND, Tack.PORT).getObject();
beatPort = new KnotSpeedWithBearingImpl(beatPortRelative.getKnots(), this.wind.getBearing().reverse()
.add(beatPortRelative.getBearing()));
}
if (beatStar == null) {
SpeedWithBearing beatStarRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
LegType.UPWIND, Tack.STARBOARD, true).getObject();
LegType.UPWIND, Tack.STARBOARD).getObject();
beatStar = new KnotSpeedWithBearingImpl(beatStarRelative.getKnots(), this.wind.getBearing().reverse()
.add(beatStarRelative.getBearing()));
}
@@ -175,13 +175,13 @@ public class PolarDiagramGPSDirect implements PolarDiagram, Serializable {
try {
if (jibePort == null) {
SpeedWithBearing jibePortRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
LegType.DOWNWIND, Tack.PORT, true).getObject();
LegType.DOWNWIND, Tack.PORT).getObject();
jibePort = new KnotSpeedWithBearingImpl(jibePortRelative.getKnots(), this.wind.getBearing().reverse()
.add(jibePortRelative.getBearing()));
}
if (jibeStar == null) {
SpeedWithBearing jibeStarRelative = this.polarData.getAverageSpeedWithBearing(this.boatClass, wind,
LegType.DOWNWIND, Tack.STARBOARD, true).getObject();
LegType.DOWNWIND, Tack.STARBOARD).getObject();
jibeStar = new KnotSpeedWithBearingImpl(jibeStarRelative.getKnots(), this.wind.getBearing().reverse()
.add(jibeStarRelative.getBearing()));
}
@@ -1,5 +1,7 @@
package com.sap.sse.datamining.test.util.components;
import java.io.Serializable;
import com.sap.sse.datamining.shared.annotations.Dimension;
/*
@@ -7,8 +9,9 @@ import com.sap.sse.datamining.shared.annotations.Dimension;
* The tests will fail, because they are reflected via constant strings.
*/
public class Number {
public class Number implements Serializable {
private static final long serialVersionUID = 1L;
private int value;
public Number(int value) {
@@ -1,5 +1,6 @@
package com.sap.sse.datamining.data;
import java.io.Serializable;
import java.util.Locale;
import com.sap.sse.i18n.ResourceBundleStringMessages;
@@ -16,7 +17,7 @@ import com.sap.sse.i18n.ResourceBundleStringMessages;
* @see ClusterBoundary
* @see ClusterGroup
*/
public interface Cluster<ElementType> {
public interface Cluster<ElementType> extends Serializable {
public String getAsLocalizedString(Locale locale, ResourceBundleStringMessages stringMessages);
@@ -1,5 +1,7 @@
package com.sap.sse.datamining.data;
import java.io.Serializable;
import com.sap.sse.datamining.impl.data.ComparisonStrategy;
/**
@@ -11,7 +13,7 @@ import com.sap.sse.datamining.impl.data.ComparisonStrategy;
*
* @see Cluster
*/
public interface ClusterBoundary<ElementType> {
public interface ClusterBoundary<ElementType> extends Serializable {
public boolean contains(ElementType value);
@@ -1,5 +1,6 @@
package com.sap.sse.datamining.data;
import java.io.Serializable;
import java.util.Locale;
import com.sap.sse.i18n.ResourceBundleStringMessages;
@@ -14,7 +15,7 @@ import com.sap.sse.i18n.ResourceBundleStringMessages;
*
* @see Cluster
*/
public interface ClusterGroup<ElementType> {
public interface ClusterGroup<ElementType extends Serializable> extends Serializable {
public String getLocalizedName(Locale locale, ResourceBundleStringMessages stringMessages);
@@ -1,11 +1,12 @@
package com.sap.sse.datamining.data;
import java.io.Serializable;
import java.util.Collection;
public interface ClusterGroupRepository {
public void add(ClusterGroup<?> clusterGroup);
public <DataType> Collection<ClusterGroup<DataType>> getClusterGroupsFor(Class<DataType> type);
public <DataType extends Serializable> Collection<ClusterGroup<DataType>> getClusterGroupsFor(Class<DataType> type);
}
@@ -10,6 +10,7 @@ import com.sap.sse.i18n.ResourceBundleStringMessages;
public abstract class AbstractCluster<ElementType> implements Cluster<ElementType> {
private static final long serialVersionUID = 1606840566021644768L;
private final String messageKey;
private Collection<ClusterBoundary<ElementType>> boundaries;
@@ -1,9 +1,12 @@
package com.sap.sse.datamining.impl.data;
import java.io.Serializable;
import com.sap.sse.datamining.data.ClusterBoundary;
public abstract class AbstractClusterBoundary<ElementType> implements ClusterBoundary<ElementType> {
public abstract class AbstractClusterBoundary<ElementType extends Serializable> implements ClusterBoundary<ElementType> {
private static final long serialVersionUID = 513488430319010656L;
private final ElementType boundaryValue;
private final ComparisonStrategy strategy;
@@ -8,6 +8,8 @@ import com.sap.sse.datamining.data.ClusterBoundary;
public class ClusterWithLowerAndUpperBoundaries<ElementType> extends AbstractCluster<ElementType> {
private static final long serialVersionUID = -845964568416163995L;
/**
* A {@link Cluster} with a lower and an upper boundary. This <code>Cluster</code> contains
* all elements, that are contained by the given <code>lowerBound</code> <b>and</b> the given
@@ -7,6 +7,7 @@ import com.sap.sse.datamining.data.ClusterBoundary;
public class ClusterWithSingleBoundary<ElementType> extends AbstractCluster<ElementType> {
private static final long serialVersionUID = -3188802475809553490L;
private static final char INFINITE = '\u221e';
/**
@@ -1,6 +1,10 @@
package com.sap.sse.datamining.impl.data;
public class ComparableClusterBoundary<ElementType extends Comparable<ElementType>> extends AbstractClusterBoundary<ElementType> {
import java.io.Serializable;
public class ComparableClusterBoundary<ElementType extends Comparable<ElementType> & Serializable> extends AbstractClusterBoundary<ElementType> {
private static final long serialVersionUID = -930603995272128901L;
public ComparableClusterBoundary(ElementType boundaryValue, ComparisonStrategy strategy) {
super(boundaryValue, strategy);
@@ -1,9 +1,11 @@
package com.sap.sse.datamining.impl.data;
import java.io.Serializable;
import java.util.Comparator;
public class ComparatorClusterBoundary<ElementType> extends AbstractClusterBoundary<ElementType> {
public class ComparatorClusterBoundary<ElementType extends Serializable> extends AbstractClusterBoundary<ElementType> {
private static final long serialVersionUID = -8177984229875233720L;
private final Comparator<? super ElementType> comparator;
public ComparatorClusterBoundary(ElementType boundaryValue, ComparisonStrategy strategy,
@@ -1,5 +1,6 @@
package com.sap.sse.datamining.impl.data;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
@@ -24,7 +25,7 @@ public class CompoundClusterGroupRepository implements ClusterGroupRepository {
}
@Override
public <T> Collection<ClusterGroup<T>> getClusterGroupsFor(Class<T> type) {
public <T extends Serializable> Collection<ClusterGroup<T>> getClusterGroupsFor(Class<T> type) {
Collection<ClusterGroup<T>> allClusterGroups = new HashSet<>();
for (ClusterGroupRepository clusterGroupRepository : repositories) {
allClusterGroups.addAll(clusterGroupRepository.getClusterGroupsFor(type));
@@ -1,17 +1,20 @@
package com.sap.sse.datamining.impl.data;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import com.sap.sse.datamining.data.Cluster;
import com.sap.sse.datamining.data.ClusterGroup;
import com.sap.sse.i18n.ResourceBundleStringMessages;
public class FixClusterGroup<ElementType> implements ClusterGroup<ElementType> {
public class FixClusterGroup<ElementType extends Serializable> implements ClusterGroup<ElementType> {
private static final long serialVersionUID = 2632796094234887943L;
private final String messageKey;
private final Collection<Cluster<ElementType>> clusters;
private final Set<Cluster<ElementType>> clusters;
public FixClusterGroup(String messageKey, Collection<Cluster<ElementType>> clusters) {
this.messageKey = messageKey;
@@ -1,5 +1,6 @@
package com.sap.sse.datamining.impl.data;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -30,7 +31,7 @@ public class SimpleClusterGroupRepository implements ClusterGroupRepository {
@SuppressWarnings("unchecked") // Necessary because you can't use instanceof with generics
@Override
public <T> Collection<ClusterGroup<T>> getClusterGroupsFor(Class<T> type) {
public <T extends Serializable> Collection<ClusterGroup<T>> getClusterGroupsFor(Class<T> type) {
Collection<ClusterGroup<T>> specificClusterGroups = new HashSet<>();
if (clusterGroupsMappedByType.containsKey(type)) {
for (ClusterGroup<?> clusterGroup : clusterGroupsMappedByType.get(type)) {
@@ -2,6 +2,7 @@ package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo;
import android.app.FragmentTransaction;
import android.support.annotation.IdRes;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment;
@@ -21,6 +22,9 @@ public class BaseFragment extends RaceFragment {
} else {
fragment.getArguments().putAll(getRecentArguments());
}
if (getArguments() != null) {
fragment.getArguments().putAll(getArguments());
}
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(viewId, fragment).commit();
}