From 7b714d129ce49955bd7e048d56ef3e6db8710bc7 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Sun, 11 Dec 2022 23:43:58 +0100 Subject: [PATCH 1/2] [#1868] Set apogee time step at apogee instead of one sample after Currently, the apogee event is added at one simulation time step AFTER the actual apogee, instead of the apogee time step itself --- .../openrocket/simulation/BasicEventSimulationEngine.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java index 63e3f1d7b..682b21b94 100644 --- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java +++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java @@ -139,6 +139,7 @@ public class BasicEventSimulationEngine implements SimulationEngine { currentStepper = flightStepper; currentStatus = currentStepper.initialize(currentStatus); + double previousSimulationTime = currentStatus.getSimulationTime(); // Get originating position (in case listener has modified launch position) Coordinate origin = currentStatus.getRocketPosition(); @@ -219,8 +220,8 @@ public class BasicEventSimulationEngine implements SimulationEngine { // Check for apogee if (!currentStatus.isApogeeReached() && currentStatus.getRocketPosition().z < currentStatus.getMaxAlt() - 0.01) { - currentStatus.setMaxAltTime(currentStatus.getSimulationTime()); - addEvent(new FlightEvent(FlightEvent.Type.APOGEE, currentStatus.getSimulationTime(), + currentStatus.setMaxAltTime(previousSimulationTime); + addEvent(new FlightEvent(FlightEvent.Type.APOGEE, previousSimulationTime, currentStatus.getConfiguration().getRocket())); } @@ -258,6 +259,8 @@ public class BasicEventSimulationEngine implements SimulationEngine { // If I'm on the ground and have no events in the queue, I'm done if (currentStatus.isLanded() && currentStatus.getEventQueue().isEmpty()) addEvent(new FlightEvent(FlightEvent.Type.SIMULATION_END, currentStatus.getSimulationTime())); + + previousSimulationTime = currentStatus.getSimulationTime(); } } catch (SimulationException e) { From 31173ae8517ab458fa6172ccd73e2358bdb15ca8 Mon Sep 17 00:00:00 2001 From: SiboVG Date: Mon, 12 Dec 2022 00:25:23 +0100 Subject: [PATCH 2/2] Add unit tests for flight event times and sources --- .../simulation/FlightEventsTest.java | 75 +++++++++++++++---- 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/core/test/net/sf/openrocket/simulation/FlightEventsTest.java b/core/test/net/sf/openrocket/simulation/FlightEventsTest.java index 2b45608d8..2dc047a22 100644 --- a/core/test/net/sf/openrocket/simulation/FlightEventsTest.java +++ b/core/test/net/sf/openrocket/simulation/FlightEventsTest.java @@ -1,8 +1,14 @@ package net.sf.openrocket.simulation; import net.sf.openrocket.document.Simulation; +import net.sf.openrocket.rocketcomponent.AxialStage; +import net.sf.openrocket.rocketcomponent.BodyTube; import net.sf.openrocket.rocketcomponent.FlightConfigurationId; +import net.sf.openrocket.rocketcomponent.InnerTube; +import net.sf.openrocket.rocketcomponent.Parachute; +import net.sf.openrocket.rocketcomponent.ParallelStage; import net.sf.openrocket.rocketcomponent.Rocket; +import net.sf.openrocket.rocketcomponent.RocketComponent; import net.sf.openrocket.simulation.exception.SimulationException; import net.sf.openrocket.util.BaseTestCase.BaseTestCase; import net.sf.openrocket.util.TestRockets; @@ -23,8 +29,8 @@ public class FlightEventsTest extends BaseTestCase { */ @Test public void testSingleStage() throws SimulationException { - Rocket rocket = TestRockets.makeEstesAlphaIII(); - Simulation sim = new Simulation(rocket); + final Rocket rocket = TestRockets.makeEstesAlphaIII(); + final Simulation sim = new Simulation(rocket); sim.getOptions().setISAAtmosphere(true); sim.getOptions().setTimeStep(0.05); sim.setFlightConfigurationId(TestRockets.TEST_FCID_0); @@ -32,12 +38,18 @@ public class FlightEventsTest extends BaseTestCase { sim.simulate(); // Test branch count - int branchCount = sim.getSimulatedData().getBranchCount(); + final int branchCount = sim.getSimulatedData().getBranchCount(); assertEquals(" Single stage simulation invalid branch count", 1, branchCount); - FlightEvent.Type[] expectedEventTypes = {FlightEvent.Type.LAUNCH, FlightEvent.Type.IGNITION, FlightEvent.Type.LIFTOFF, + final FlightEvent.Type[] expectedEventTypes = {FlightEvent.Type.LAUNCH, FlightEvent.Type.IGNITION, FlightEvent.Type.LIFTOFF, FlightEvent.Type.LAUNCHROD, FlightEvent.Type.BURNOUT, FlightEvent.Type.EJECTION_CHARGE, FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT, FlightEvent.Type.APOGEE, FlightEvent.Type.GROUND_HIT, FlightEvent.Type.SIMULATION_END}; + final double[] expectedEventTimes = {0.0, 0.0, 0.1275, 0.13, 2.0, 2.0, 2.001, 2.48338}; // Ground hit time is too variable, so don't include it + final AxialStage stage = rocket.getStage(0); + final InnerTube motorMountTube = (InnerTube) stage.getChild(1).getChild(2); + final Parachute parachute = (Parachute) stage.getChild(1).getChild(3); + final RocketComponent[] expectedSources = {rocket, motorMountTube, null, null, motorMountTube, + stage, parachute, rocket, null, null}; // Test event count FlightDataBranch branch = sim.getSimulatedData().getBranch(0); @@ -48,7 +60,20 @@ public class FlightEventsTest extends BaseTestCase { // Test that all expected events are present, and in the right order for (int i = 0; i < expectedEventTypes.length; i++) { assertSame(" Flight type " + expectedEventTypes[i] + " not found in single stage simulation", - eventTypes.get(i), expectedEventTypes[i]); + expectedEventTypes[i], eventTypes.get(i)); + } + + // Test that the event times are correct + for (int i = 0; i < expectedEventTimes.length; i++) { + assertEquals(" Flight type " + expectedEventTypes[i] + " has wrong time", + expectedEventTimes[i], eventList.get(i).getTime(), 0.001); + + } + + // Test that the event sources are correct + for (int i = 0; i < expectedSources.length; i++) { + assertSame(" Flight type " + expectedEventTypes[i] + " has wrong source", + expectedSources[i], eventList.get(i).getSource()); } } @@ -57,8 +82,8 @@ public class FlightEventsTest extends BaseTestCase { */ @Test public void testMultiStage() throws SimulationException { - Rocket rocket = TestRockets.makeFalcon9Heavy(); - Simulation sim = new Simulation(rocket); + final Rocket rocket = TestRockets.makeFalcon9Heavy(); + final Simulation sim = new Simulation(rocket); sim.getOptions().setISAAtmosphere(true); sim.getOptions().setTimeStep(0.05); rocket.getSelectedConfiguration().setAllStages(); @@ -68,11 +93,13 @@ public class FlightEventsTest extends BaseTestCase { sim.simulate(); // Test branch count - int branchCount = sim.getSimulatedData().getBranchCount(); + final int branchCount = sim.getSimulatedData().getBranchCount(); assertEquals(" Multi-stage simulation invalid branch count", 3, branchCount); for (int b = 0; b < 3; b++) { - FlightEvent.Type[] expectedEventTypes; + final FlightEvent.Type[] expectedEventTypes; + final double[] expectedEventTimes; + final RocketComponent[] expectedSources; switch (b) { case 0: expectedEventTypes = new FlightEvent.Type[]{FlightEvent.Type.LAUNCH, FlightEvent.Type.IGNITION, FlightEvent.Type.IGNITION, @@ -80,26 +107,48 @@ public class FlightEventsTest extends BaseTestCase { FlightEvent.Type.BURNOUT, FlightEvent.Type.EJECTION_CHARGE, FlightEvent.Type.STAGE_SEPARATION, FlightEvent.Type.BURNOUT, FlightEvent.Type.EJECTION_CHARGE, FlightEvent.Type.STAGE_SEPARATION, FlightEvent.Type.TUMBLE, FlightEvent.Type.GROUND_HIT, FlightEvent.Type.SIMULATION_END}; + expectedEventTimes = new double[]{0.0, 0.0, 0.0, 0.1225, 0.125, 1.735, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0}; // Tumble and ground hit time are too variable, so don't include it + final AxialStage coreStage = rocket.getStage(1); + final ParallelStage boosterStage = (ParallelStage) rocket.getStage(2); + final InnerTube boosterMotorTubes = (InnerTube) boosterStage.getChild(1).getChild(0); + final BodyTube coreBody = (BodyTube) coreStage.getChild(0); + expectedSources = new RocketComponent[]{rocket, boosterMotorTubes, coreBody, null, null, rocket, + boosterMotorTubes, boosterStage, boosterStage, coreBody, coreStage, coreStage, + null, null, null}; break; case 1: case 2: expectedEventTypes = new FlightEvent.Type[]{FlightEvent.Type.TUMBLE, FlightEvent.Type.GROUND_HIT, FlightEvent.Type.SIMULATION_END}; + expectedEventTimes = new double[]{}; // Tumble and ground hit time are too variable, so don't include it + expectedSources = new RocketComponent[]{null, null, null}; break; default: throw new IllegalStateException("Invalid branch number " + b); } // Test event count - FlightDataBranch branch = sim.getSimulatedData().getBranch(b); - List eventList = branch.getEvents(); - List eventTypes = eventList.stream().map(FlightEvent::getType).collect(Collectors.toList()); + final FlightDataBranch branch = sim.getSimulatedData().getBranch(b); + final List eventList = branch.getEvents(); + final List eventTypes = eventList.stream().map(FlightEvent::getType).collect(Collectors.toList()); assertEquals(" Multi-stage simulation, branch " + b + " invalid number of events", expectedEventTypes.length, eventTypes.size()); // Test that all expected events are present, and in the right order for (int i = 0; i < expectedEventTypes.length; i++) { assertSame(" Flight type " + expectedEventTypes[i] + ", branch " + b + " not found in multi-stage simulation", - eventTypes.get(i), expectedEventTypes[i]); + expectedEventTypes[i], eventTypes.get(i)); + } + + // Test that the event times are correct + for (int i = 0; i < expectedEventTimes.length; i++) { + assertEquals(" Flight type " + expectedEventTypes[i] + " has wrong time", + expectedEventTimes[i], eventList.get(i).getTime(), 0.001); + } + + // Test that the event sources are correct + for (int i = 0; i < expectedSources.length; i++) { + assertSame(" Flight type " + expectedEventTypes[i] + " has wrong source", + expectedSources[i], eventList.get(i).getSource()); } } }