added more tests and adjusted the test certificate to make it injective

This commit is contained in:
Axel Uhl
2020-02-11 18:29:04 +01:00
parent f35879729f
commit 3738dcef86
3 changed files with 36 additions and 11 deletions
@@ -159,7 +159,7 @@
530.3,
516.8,
510.9,
508.9
506.9
],
"R75":[
697.1,
@@ -70,6 +70,16 @@ public class TestORCPerformanceCurve {
}
}
public void assertEquals(String message, double a, double b, double accuracy) {
try {
Assert.assertEquals(message, a, b, accuracy);
} catch (AssertionError e) {
if (collectErrors) {
collector.addError(e);
}
}
}
@BeforeClass
public static void initialize() throws IOException, ParseException {
List<ORCPerformanceCurveLeg> legs = new ArrayList<>();
@@ -253,15 +263,18 @@ public class TestORCPerformanceCurve {
}
@Test
public void testAllowancesAndImpliedWindForSpecificBins() throws FunctionEvaluationException {
public void testAllowancesAndImpliedWindForSpecificBins() throws FunctionEvaluationException, MaxIterationsExceededException {
final double highAccuracy = 0.01;
final double allowanceAccuracy = 0.1;
final Distance ONE_NAUTICAL_MILE = new NauticalMileDistance(1.0);
final ORCCertificate certificateWithSpecificBins = importerWithSpecificBins.getCertificateById("GRA00073GR317");
for (final Bearing twa : certificateWithSpecificBins.getTrueWindAngles()) {
final ORCPerformanceCurveCourse singleLegOneMileCourseWithTwa = createSingleLegCourseWithTwa(twa);
final ORCPerformanceCurve performanceCurveSpecificBins = new ORCPerformanceCurveImpl(certificateWithSpecificBins, singleLegOneMileCourseWithTwa);
for (final Speed tws : certificateWithSpecificBins.getTrueWindSpeeds()) {
Assert.assertEquals(certificateWithSpecificBins.getVelocityPredictionPerTrueWindSpeedAndAngle().get(tws).get(twa).getDuration(ONE_NAUTICAL_MILE),
performanceCurveSpecificBins.getAllowancePerCourse(tws));
final Duration duration = certificateWithSpecificBins.getVelocityPredictionPerTrueWindSpeedAndAngle().get(tws).get(twa).getDuration(ONE_NAUTICAL_MILE);
assertEquals("mismatch for twa "+twa+", tws "+tws, duration.asSeconds(), performanceCurveSpecificBins.getAllowancePerCourse(tws).asSeconds(), allowanceAccuracy);
assertEquals("mismatch for twa "+twa+", tws "+tws, tws.getKnots(), performanceCurveSpecificBins.getImpliedWind(duration).getKnots(), highAccuracy);
}
}
}
@@ -284,7 +297,7 @@ public class TestORCPerformanceCurve {
list.add(new ORCPerformanceCurveLegImpl(new NauticalMileDistance(1), new DegreeBearingImpl(180)));
ORCPerformanceCurveCourse complexCourse = new ORCPerformanceCurveCourseImpl(list);
double accuracy = 0.0001;
final double accuracy = 0.0001;
ORCCertificate certificateMoana = importerLocal.getCertificateById("GER140772GER5549");
ORCCertificate certificateMilan = importerLocal.getCertificateById("GER166844GER7323");
ORCCertificate certificateTutima = importerLocal.getCertificateById("GER140618GER5609");
@@ -71,6 +71,16 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
* allowance in sec/nm.
*/
private final UnivariateDifferentiableFunction functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse;
/**
* The {@link ORCCertificate#getTrueWindAngles()} from the certificate
*/
private final Bearing[] trueWindAngles;
/**
* The {@link ORCCertificate#getTrueWindSpeeds()} from the certificate
*/
private final Speed[] trueWindSpeeds;
/**
* Accepts the simplified polar data, one "column" for each of the defined true wind speeds, where each column is a
@@ -79,6 +89,8 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
*/
public ORCPerformanceCurveImpl(ORCCertificate certificate, ORCPerformanceCurveCourse course) throws FunctionEvaluationException {
this.course = course;
this.trueWindAngles = certificate.getTrueWindAngles();
this.trueWindSpeeds = certificate.getTrueWindSpeeds();
functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse = createPerformanceCurve(certificate);
}
@@ -251,14 +263,14 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
@Override
public Speed getImpliedWind(Duration durationToCompleteCourse) throws MaxIterationsExceededException, FunctionEvaluationException{
final Speed averageSpeedOnCourse = getCourse().getTotalLength().inTime(durationToCompleteCourse);
final double[] predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed = Arrays.stream(ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS).mapToDouble
final double[] predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed = Arrays.stream(trueWindSpeeds).mapToDouble
(tws->{ return functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse.value(tws.getKnots()); }).toArray();
final Speed result;
// Corner cases for Allowance > Allowance(20kt) or Allowance < Allowance(6kt)
if (averageSpeedOnCourse.getKnots() >= predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed[predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed.length-1]) {
result = ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS.length-1];
result = trueWindSpeeds[trueWindSpeeds.length-1];
} else if (averageSpeedOnCourse.equals(Speed.NULL) || averageSpeedOnCourse.getKnots() <= predictedSpeedsInKnotsForTotalCourseByTrueWindSpeed[0]) {
result = ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS[0];
result = trueWindSpeeds[0];
} else {
// find the polynomial splined function that produces the durationToCompleteCourse within its validity range
int i = 1; // skip the auxiliary spline segment from (0.0, 0.0) to (6.0, ...)
@@ -272,7 +284,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
final UnivariateDifferentiableFunction targetZeroFunction = FunctionUtils.add(functionImpliedWindInKnotsToAverageSpeedInKnotsForCourse,
FunctionUtils.multiply((UnivariateDifferentiableFunction) averageSpeedInKnots,
(UnivariateDifferentiableFunction) new Constant(-1)));
final double impliedWindSpeedInKnots = newtonSolver.solve(1000, targetZeroFunction, 10 /* knots of true wind speed */);
final double impliedWindSpeedInKnots = newtonSolver.solve(1000, targetZeroFunction, 12 /* knots of true wind speed */);
result = new KnotSpeedImpl(impliedWindSpeedInKnots);
}
return result;
@@ -296,7 +308,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
Bearing trueWindAngle) throws FunctionEvaluationException, IllegalArgumentException {
return getLagrangeSpeedPredictionForTrueWindSpeedAndAngle(twaAllowances, beatAngles,
beatVMGPredictionPerTrueWindSpeed, runAngles, runVMGPredictionPerTrueWindSpeed, trueWindSpeed,
trueWindAngle, ORCCertificate.ALLOWANCES_TRUE_WIND_ANGLES);
trueWindAngle, trueWindAngles);
}
public Speed getLagrangeSpeedPredictionForTrueWindSpeedAndAngle(Map<Speed, Map<Bearing, Speed>> twaAllowances,
@@ -341,7 +353,7 @@ public class ORCPerformanceCurveImpl implements Serializable, ORCPerformanceCurv
*/
private LinkedHashMap<Speed, Duration> getAllowancesPerTrueWindSpeedsForCourse() throws ArgumentOutsideDomainException {
final LinkedHashMap<Speed, Duration> result = new LinkedHashMap<>();
for (final Speed tws : ORCCertificate.ALLOWANCES_TRUE_WIND_SPEEDS) {
for (final Speed tws : trueWindSpeeds) {
result.put(tws, getAllowancePerCourse(tws));
}
return result;