/// <summary> /// Calculates the <see cref="BalancedFieldLengthOutput"/> based on <paramref name="calculation"/>. /// </summary> /// <param name="calculation">The <see cref="BalancedFieldLengthCalculation"/> to calculate for.</param> /// <returns>A <see cref="BalancedFieldLengthOutput"/>.</returns> /// <exception cref="ArgumentNullException">Thrown when <paramref name="calculation"/> is <c>null</c>.</exception> /// <exception cref="CreateKernelDataException">Thrown when the calculation input /// could not be created for the kernel.</exception> /// <exception cref="KernelCalculationException">Thrown when <see cref="AggregatedDistanceOutput"/> /// could not be calculated.</exception> public BalancedFieldLengthOutput Calculate(BalancedFieldLengthCalculation calculation) { if (calculation == null) { throw new ArgumentNullException(nameof(calculation)); } GeneralSimulationSettingsData generalSimulationSettings = calculation.SimulationSettings; double density = generalSimulationSettings.Density; int endVelocity = generalSimulationSettings.EndFailureVelocity; double gravitationalAcceleration = generalSimulationSettings.GravitationalAcceleration; EngineData engineData = calculation.EngineData; int nrOfFailedEngines = engineData.NrOfFailedEngines; AircraftData aircraftData = AircraftDataFactory.Create(calculation.AircraftData, engineData); var integrator = new EulerIntegrator(); var outputs = new List <AggregatedDistanceOutput>(); for (int i = 0; i < endVelocity; i++) { var calculationInput = new CalculationInput(generalSimulationSettings, i, aircraftData, integrator, nrOfFailedEngines, density, gravitationalAcceleration); AggregatedDistanceOutput output = CalculateDistances(calculationInput); outputs.Add(output); } return(BalancedFieldLengthOutputFactory.Create(outputs)); }
public static void Calculate_WithArguments_ExecutesDistanceCalculatorsAndReturnsExpectedOutput() { // Setup var random = new Random(21); AircraftData aircraftData = AircraftDataTestFactory.CreateRandomAircraftData(); var integrator = Substitute.For <IIntegrator>(); int nrOfFailedEngines = random.Next(); double density = random.NextDouble(); double gravitationalAcceleration = random.NextDouble(); CalculationSettings calculationSettings = CalculationSettingsTestFactory.CreateDistanceCalculatorSettings(); var abortedTakeOffDistanceCalculator = Substitute.For <IDistanceCalculator>(); var abortedTakeOffDistanceOutput = new DistanceCalculatorOutput(calculationSettings.FailureSpeed, random.NextDouble()); abortedTakeOffDistanceCalculator.Calculate().Returns(abortedTakeOffDistanceOutput); var continuedTakeOffDistanceCalculator = Substitute.For <IDistanceCalculator>(); var continuedTakeOffDistanceOutput = new DistanceCalculatorOutput(calculationSettings.FailureSpeed, random.NextDouble()); continuedTakeOffDistanceCalculator.Calculate().Returns(continuedTakeOffDistanceOutput); var distanceCalculatorFactory = Substitute.For <IDistanceCalculatorFactory>(); distanceCalculatorFactory.CreateAbortedTakeOffDistanceCalculator(Arg.Is(aircraftData), Arg.Is(integrator), Arg.Is(density), Arg.Is(gravitationalAcceleration), Arg.Is(calculationSettings)) .Returns(abortedTakeOffDistanceCalculator); distanceCalculatorFactory.CreateContinuedTakeOffDistanceCalculator(Arg.Is(aircraftData), Arg.Is(integrator), Arg.Is(nrOfFailedEngines), Arg.Is(density), Arg.Is(gravitationalAcceleration), Arg.Is(calculationSettings)) .Returns(continuedTakeOffDistanceCalculator); var aggregatedCalculator = new Calculator.AggregatedDistanceCalculator.AggregatedDistanceCalculator(distanceCalculatorFactory); // Call AggregatedDistanceOutput output = aggregatedCalculator.Calculate(aircraftData, integrator, nrOfFailedEngines, density, gravitationalAcceleration, calculationSettings); // Assert Assert.AreEqual(calculationSettings.FailureSpeed, output.FailureSpeed); Assert.AreEqual(abortedTakeOffDistanceOutput.Distance, output.AbortedTakeOffDistance); Assert.AreEqual(continuedTakeOffDistanceOutput.Distance, output.ContinuedTakeOffDistance); }
public void GivenKernel_WhenCalculationsAreMadeForVelocityRange_ThenReturnsExpectedOutputsAndBalancedFieldLength(AircraftData aircraftData, IntegrationReferenceData integrationReferenceData) { // Given var integrator = new EulerIntegrator(); var calculationKernel = new AggregatedDistanceCalculatorKernel(); // When var outputs = new List <AggregatedDistanceOutput>(); for (int i = 0; i < 90; i++) { var calculationSettings = new CalculationSettings(i, maximumTimeSteps, timeStep); AggregatedDistanceOutput result = calculationKernel.Calculate(aircraftData, integrator, 1, density, gravitationalAcceleration, calculationSettings); outputs.Add(result); } BalancedFieldLength balancedFieldLength = BalancedFieldLengthCalculator.CalculateBalancedFieldLength(outputs); // Then IEnumerable <ReferenceOutput> referenceOutputs = GetReferenceOutputs(integrationReferenceData.FileName); int expectedLength = referenceOutputs.Count(); Assert.AreEqual(expectedLength, outputs.Count, "Number of reference data entries do not match with actual number of entries"); int velocity = 0; foreach (ReferenceOutput referenceOutput in referenceOutputs) { Assert.AreEqual(referenceOutput.Velocity, outputs[velocity].FailureSpeed); Assert.AreEqual(referenceOutput.ContinuedTakeOffDistance, outputs[velocity].ContinuedTakeOffDistance, tolerance); Assert.AreEqual(referenceOutput.AbortedTakeOffDistance, outputs[velocity].AbortedTakeOffDistance, tolerance); velocity++; } Assert.AreEqual(integrationReferenceData.Velocity, balancedFieldLength.Velocity, tolerance); Assert.AreEqual(integrationReferenceData.Distance, balancedFieldLength.Distance, tolerance); }
/// <summary> /// Calculates the balanced field length by determining the intersection between the distances covered by the rejected /// and the continued take off. /// </summary> /// <param name="outputs">The collection of <see cref="AggregatedDistanceOutput"/> to determine the balanced field length for.</param> /// <returns>An <see cref="BalancedFieldLength"/> containing the information at which balanced field length occurs.</returns> /// <exception cref="ArgumentNullException">Thrown when <see cref="outputs"/> is <c>null</c>.</exception> /// <exception cref="ArgumentException">Thrown when <paramref name="outputs"/> /// <list type="bullet"> /// <item>contains a duplicate definition for a certain failure speed,</item> /// <item>is empty,</item> /// <item>contains only one element.</item> /// </list></exception> /// <remarks>This method will sort <paramref name="outputs"/> in an ascending order based on the failure speed. /// The intersection is determined based on this sorted list.</remarks> public static BalancedFieldLength CalculateBalancedFieldLength(IEnumerable <AggregatedDistanceOutput> outputs) { if (outputs == null) { throw new ArgumentNullException(nameof(outputs)); } IEnumerable <AggregatedDistanceOutput> sortedOutputs = SortOutputs(outputs); if (sortedOutputs.Count() <= 1) { throw new ArgumentException(Resources.BalancedFieldLengthCalculator_Cannot_determine_crossing_from_empty_or_single_item_collection); } AggregatedDistanceOutput previousOutput = sortedOutputs.First(); for (int i = 1; i < sortedOutputs.Count(); i++) { AggregatedDistanceOutput currentOutput = sortedOutputs.ElementAt(i); // Create line segments var continuedTakeOffSegment = new LineSegment(new Point2D(previousOutput.FailureSpeed, previousOutput.ContinuedTakeOffDistance), new Point2D(currentOutput.FailureSpeed, currentOutput.ContinuedTakeOffDistance)); var abortedTakeOffSegment = new LineSegment(new Point2D(previousOutput.FailureSpeed, previousOutput.AbortedTakeOffDistance), new Point2D(currentOutput.FailureSpeed, currentOutput.AbortedTakeOffDistance)); // Determine whether lines cross Point2D crossingPoint = Geometry2DHelper.DetermineLineIntersection(continuedTakeOffSegment, abortedTakeOffSegment); // Determine if the result is valid if (!double.IsNaN(crossingPoint.X) && !double.IsNaN(crossingPoint.Y)) { double intersectionDistance = crossingPoint.Y; return(new BalancedFieldLength(crossingPoint.X, intersectionDistance)); } previousOutput = currentOutput; } return(new BalancedFieldLength(double.NaN, double.NaN)); }