Merge branch 'refs/heads/unstable' into sphinx-docs

This commit is contained in:
SiboVG 2024-05-10 05:08:47 +02:00
commit df396228aa
29 changed files with 402 additions and 346 deletions

View File

@ -40,5 +40,5 @@ jobs:
uses: actions/upload-artifact@v3
with:
name: openrocket_build_${{ github.run_number }}
path: ${{github.workspace}}/build/lib/openrocket*.jar
path: ${{github.workspace}}/build/libs/OpenRocket*.jar

1
.gitignore vendored
View File

@ -46,6 +46,7 @@
**/.idea/vcs.xml
**/.idea/jsLibraryMappings.xml
**/.idea/copilot
**/.idea/shelf
# Sensitive or high-churn files:
**/.idea/dataSources.ids

View File

@ -1,10 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="All tests" type="JUnit" factoryName="JUnit">
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="class" />
<option name="PARAMETERS" value="" />
<option name="WORKING_DIRECTORY" value="$MODULE_DIR$" />
<method v="2" />
</configuration>
</component>

View File

@ -1,12 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Openrocket UI Jar" type="JarApplication">
<option name="JAR_PATH" value="$PROJECT_DIR$/build/jar/OpenRocket.jar" />
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="true" />
<option name="ALTERNATIVE_JRE_PATH" value="17" />
<method v="2">
<option name="BuildArtifacts" enabled="true">
<artifact name="openrocket:jar" />
</option>
</method>
</configuration>
</component>

15
.idea/runConfigurations/SwingStartup.xml generated Normal file
View File

@ -0,0 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="SwingStartup" type="Application" factoryName="Application" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="info.openrocket.swing.startup.SwingStartup" />
<module name="info.openrocket.swing.main" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="info.openrocket.swing.startup.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -0,0 +1,27 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="openrocket-jar" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="clean" />
<option value="check" />
<option value="build" />
<option value="dist" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>

View File

@ -0,0 +1,25 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="openrocket-test" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="externalSystemIdString" value="GRADLE" />
<option name="scriptParameters" value="" />
<option name="taskDescriptions">
<list />
</option>
<option name="taskNames">
<list>
<option value="clean" />
<option value="check" />
</list>
</option>
<option name="vmOptions" />
</ExternalSystemSettings>
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
<DebugAllEnabled>false</DebugAllEnabled>
<RunAsTest>false</RunAsTest>
<method v="2" />
</configuration>
</component>

View File

@ -399,14 +399,14 @@ public class Simulation implements ChangeSource, Cloneable {
public void simulate(SimulationListener... additionalListeners)
throws SimulationException {
mutex.lock("simulate");
SimulationEngine simulator = null;
simulatedData = null;
try {
if (this.status == Status.EXTERNAL) {
throw new SimulationException("Cannot simulate imported simulation.");
}
SimulationEngine simulator;
try {
simulator = simulationEngineClass.getConstructor().newInstance();
} catch (InstantiationException e) {
@ -430,18 +430,20 @@ public class Simulation implements ChangeSource, Cloneable {
long t1, t2;
log.debug("Simulation: calling simulator");
t1 = System.currentTimeMillis();
simulatedData = simulator.simulate(simulationConditions);
simulator.simulate(simulationConditions);
t2 = System.currentTimeMillis();
log.debug("Simulation: returning from simulator, simulation took " + (t2 - t1) + "ms");
} catch (SimulationException e) {
simulatedData = e.getFlightData();
throw e;
} finally {
// Set simulated info after simulation
simulatedConditions = options.clone();
simulatedConfigurationDescription = descriptor.format(this.rocket, getId());
simulatedConfigurationID = getActiveConfiguration().getModID();
if (simulator != null) {
simulatedData = simulator.getFlightData();
}
status = Status.UPTODATE;
fireChangeEvent();

View File

@ -483,7 +483,7 @@ public class OpenRocketSaver extends RocketSaver {
// Build the <databranch> tag
StringBuilder sb = new StringBuilder();
sb.append("<databranch name=\"");
sb.append(TextUtil.escapeXML(branch.getBranchName()));
sb.append(TextUtil.escapeXML(branch.getName()));
sb.append("\" ");
// Kevins version where typekeys are used

View File

@ -169,69 +169,69 @@ public abstract class AbstractEulerStepper extends AbstractSimulationStepper {
status.setRocketWorldPosition(w);
// Store data
final FlightDataBranch data = status.getFlightData();
final FlightDataBranch dataBranch = status.getFlightDataBranch();
// Values looked up or calculated at start of time step
data.setValue(FlightDataType.TYPE_REFERENCE_LENGTH, status.getConfiguration().getReferenceLength());
data.setValue(FlightDataType.TYPE_REFERENCE_AREA, status.getConfiguration().getReferenceArea());
data.setValue(FlightDataType.TYPE_WIND_VELOCITY, windSpeed.length());
data.setValue(FlightDataType.TYPE_AIR_TEMPERATURE, atmosphere.getTemperature());
data.setValue(FlightDataType.TYPE_AIR_PRESSURE, atmosphere.getPressure());
data.setValue(FlightDataType.TYPE_SPEED_OF_SOUND, atmosphere.getMachSpeed());
data.setValue(FlightDataType.TYPE_MACH_NUMBER, mach);
dataBranch.setValue(FlightDataType.TYPE_REFERENCE_LENGTH, status.getConfiguration().getReferenceLength());
dataBranch.setValue(FlightDataType.TYPE_REFERENCE_AREA, status.getConfiguration().getReferenceArea());
dataBranch.setValue(FlightDataType.TYPE_WIND_VELOCITY, windSpeed.length());
dataBranch.setValue(FlightDataType.TYPE_AIR_TEMPERATURE, atmosphere.getTemperature());
dataBranch.setValue(FlightDataType.TYPE_AIR_PRESSURE, atmosphere.getPressure());
dataBranch.setValue(FlightDataType.TYPE_SPEED_OF_SOUND, atmosphere.getMachSpeed());
dataBranch.setValue(FlightDataType.TYPE_MACH_NUMBER, mach);
if (status.getSimulationConditions().getGeodeticComputation() != GeodeticComputationStrategy.FLAT) {
data.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, coriolisAcceleration.length());
dataBranch.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, coriolisAcceleration.length());
}
data.setValue(FlightDataType.TYPE_GRAVITY, gravity);
dataBranch.setValue(FlightDataType.TYPE_GRAVITY, gravity);
data.setValue(FlightDataType.TYPE_DRAG_COEFF, getCD());
data.setValue(FlightDataType.TYPE_PRESSURE_DRAG_COEFF, getCD());
data.setValue(FlightDataType.TYPE_FRICTION_DRAG_COEFF, 0);
data.setValue(FlightDataType.TYPE_BASE_DRAG_COEFF, 0);
data.setValue(FlightDataType.TYPE_AXIAL_DRAG_COEFF, getCD());
data.setValue(FlightDataType.TYPE_THRUST_FORCE, 0);
data.setValue(FlightDataType.TYPE_DRAG_FORCE, dragForce);
dataBranch.setValue(FlightDataType.TYPE_DRAG_COEFF, getCD());
dataBranch.setValue(FlightDataType.TYPE_PRESSURE_DRAG_COEFF, getCD());
dataBranch.setValue(FlightDataType.TYPE_FRICTION_DRAG_COEFF, 0);
dataBranch.setValue(FlightDataType.TYPE_BASE_DRAG_COEFF, 0);
dataBranch.setValue(FlightDataType.TYPE_AXIAL_DRAG_COEFF, getCD());
dataBranch.setValue(FlightDataType.TYPE_THRUST_FORCE, 0);
dataBranch.setValue(FlightDataType.TYPE_DRAG_FORCE, dragForce);
data.setValue(FlightDataType.TYPE_MASS, mass);
data.setValue(FlightDataType.TYPE_MOTOR_MASS, motorMass);
data.setValue(FlightDataType.TYPE_THRUST_WEIGHT_RATIO, 0);
dataBranch.setValue(FlightDataType.TYPE_MASS, mass);
dataBranch.setValue(FlightDataType.TYPE_MOTOR_MASS, motorMass);
dataBranch.setValue(FlightDataType.TYPE_THRUST_WEIGHT_RATIO, 0);
data.setValue(FlightDataType.TYPE_ACCELERATION_XY,
dataBranch.setValue(FlightDataType.TYPE_ACCELERATION_XY,
MathUtil.hypot(linearAcceleration.x, linearAcceleration.y));
data.setValue(FlightDataType.TYPE_ACCELERATION_Z, linearAcceleration.z);
data.setValue(FlightDataType.TYPE_ACCELERATION_TOTAL, linearAcceleration.length());
dataBranch.setValue(FlightDataType.TYPE_ACCELERATION_Z, linearAcceleration.z);
dataBranch.setValue(FlightDataType.TYPE_ACCELERATION_TOTAL, linearAcceleration.length());
data.setValue(FlightDataType.TYPE_TIME_STEP, timeStep);
dataBranch.setValue(FlightDataType.TYPE_TIME_STEP, timeStep);
// Values calculated on this step
data.addPoint();
data.setValue(FlightDataType.TYPE_TIME, status.getSimulationTime());
data.setValue(FlightDataType.TYPE_ALTITUDE, status.getRocketPosition().z);
data.setValue(FlightDataType.TYPE_POSITION_X, status.getRocketPosition().x);
data.setValue(FlightDataType.TYPE_POSITION_Y, status.getRocketPosition().y);
dataBranch.addPoint();
dataBranch.setValue(FlightDataType.TYPE_TIME, status.getSimulationTime());
dataBranch.setValue(FlightDataType.TYPE_ALTITUDE, status.getRocketPosition().z);
dataBranch.setValue(FlightDataType.TYPE_POSITION_X, status.getRocketPosition().x);
dataBranch.setValue(FlightDataType.TYPE_POSITION_Y, status.getRocketPosition().y);
data.setValue(FlightDataType.TYPE_POSITION_XY,
dataBranch.setValue(FlightDataType.TYPE_POSITION_XY,
MathUtil.hypot(status.getRocketPosition().x, status.getRocketPosition().y));
data.setValue(FlightDataType.TYPE_POSITION_DIRECTION,
dataBranch.setValue(FlightDataType.TYPE_POSITION_DIRECTION,
Math.atan2(status.getRocketPosition().y, status.getRocketPosition().x));
data.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad());
data.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad());
dataBranch.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad());
dataBranch.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad());
data.setValue(FlightDataType.TYPE_VELOCITY_XY,
dataBranch.setValue(FlightDataType.TYPE_VELOCITY_XY,
MathUtil.hypot(status.getRocketVelocity().x, status.getRocketVelocity().y));
data.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z);
data.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, airSpeed.length());
dataBranch.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z);
dataBranch.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, airSpeed.length());
airSpeed = status.getRocketVelocity().add(windSpeed);
final double Re = airSpeed.length() *
status.getConfiguration().getLengthAerodynamic() /
atmosphere.getKinematicViscosity();
data.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Re);
dataBranch.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Re);
data.setValue(FlightDataType.TYPE_COMPUTATION_TIME,
dataBranch.setValue(FlightDataType.TYPE_COMPUTATION_TIME,
(System.nanoTime() - status.getSimulationStartWallTime()) / 1000000000.0);
log.trace("time " + data.getLast(FlightDataType.TYPE_TIME) + ", altitude " + data.getLast(FlightDataType.TYPE_ALTITUDE) + ", velocity " + data.getLast(FlightDataType.TYPE_VELOCITY_Z));
log.trace("time " + dataBranch.getLast(FlightDataType.TYPE_TIME) + ", altitude " + dataBranch.getLast(FlightDataType.TYPE_ALTITUDE) + ", velocity " + dataBranch.getLast(FlightDataType.TYPE_VELOCITY_Z));
}
private static class EulerValues {

View File

@ -62,93 +62,99 @@ public class BasicEventSimulationEngine implements SimulationEngine {
FlightData flightData;
@Override
public FlightData simulate(SimulationConditions simulationConditions) throws SimulationException {
public void simulate(SimulationConditions simulationConditions) throws SimulationException {
// Set up flight data
flightData = new FlightData();
// Set up rocket configuration
this.fcid = simulationConditions.getFlightConfigurationID();
FlightConfiguration origConfig = simulationConditions.getRocket().getFlightConfiguration(this.fcid);
FlightConfiguration simulationConfig = origConfig.clone(simulationConditions.getRocket().copyWithOriginalID());
simulationConfig.copyStages(origConfig); // Clone the stage activation configuration
currentStatus = new SimulationStatus(simulationConfig, simulationConditions);
// main simulation branch. Need to watch for pathological case with no stages defined
final AxialStage topStage = simulationConfig.getRocket().getTopmostStage(currentStatus.getConfiguration());
final String branchName;
try {
// Set up rocket configuration
this.fcid = simulationConditions.getFlightConfigurationID();
FlightConfiguration origConfig = simulationConditions.getRocket().getFlightConfiguration(this.fcid);
FlightConfiguration simulationConfig = origConfig.clone(simulationConditions.getRocket().copyWithOriginalID());
simulationConfig.copyStages(origConfig); // Clone the stage activation configuration
currentStatus = new SimulationStatus(simulationConfig, simulationConditions);
// main simulation branch. Need to watch for pathological case with no stages defined
final AxialStage topStage = simulationConfig.getRocket().getTopmostStage(currentStatus.getConfiguration());
final String branchName;
if (topStage != null) {
branchName = topStage.getName();
} else {
branchName = trans.get("BasicEventSimulationEngine.nullBranchName");
}
FlightDataBranch initialBranch = new FlightDataBranch( branchName, FlightDataType.TYPE_TIME);
// put a point on it so we can plot if we get an early abort event
initialBranch.addPoint();
initialBranch.setValue(FlightDataType.TYPE_TIME, 0.0);
initialBranch.setValue(FlightDataType.TYPE_ALTITUDE, 0.0);
currentStatus.setFlightData(initialBranch);
// Sanity checks on design and configuration
// Problems that keep us from simulating at all
// No active stages
if (topStage == null) {
currentStatus.abortSimulation(SimulationAbort.Cause.NO_ACTIVE_STAGES);
}
// No motors in configuration
if (!simulationConfig.hasMotors() ) {
currentStatus.abortSimulation(SimulationAbort.Cause.NO_MOTORS_DEFINED);
}
// Problems that let us simulate, but result is likely bad
FlightDataBranch initialBranch = new FlightDataBranch( branchName, FlightDataType.TYPE_TIME);
// No recovery device
if (!simulationConfig.hasRecoveryDevice()) {
currentStatus.getWarnings().add(Warning.NO_RECOVERY_DEVICE);
}
currentStatus.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket()));
toSimulate.push(currentStatus);
SimulationListenerHelper.fireStartSimulation(currentStatus);
do {
if (toSimulate.peek() == null) {
break;
// put a point on it so we can plot if we get an early abort event
initialBranch.addPoint();
initialBranch.setValue(FlightDataType.TYPE_TIME, 0.0);
initialBranch.setValue(FlightDataType.TYPE_ALTITUDE, 0.0);
currentStatus.setFlightDataBranch(initialBranch);
// Sanity checks on design and configuration
// Problems that keep us from simulating at all
// No active stages
if (topStage == null) {
currentStatus.abortSimulation(SimulationAbort.Cause.NO_ACTIVE_STAGES);
}
currentStatus = toSimulate.pop();
log.info(">>Starting simulation of branch: " + currentStatus.getFlightData().getBranchName());
FlightDataBranch dataBranch = simulateLoop();
flightData.addBranch(dataBranch);
flightData.getWarningSet().addAll(currentStatus.getWarnings());
log.info(String.format("<<Finished simulating branch: %s curTime:%s finTime:%s",
dataBranch.getBranchName(),
currentStatus.getSimulationTime(),
dataBranch.getLast(FlightDataType.TYPE_TIME)));
// Did the branch generate any data?
if (dataBranch.getLength() == 0) {
flightData.getWarningSet().add(Warning.EMPTY_BRANCH, dataBranch.getBranchName());
// No motors in configuration
if (!simulationConfig.hasMotors() ) {
currentStatus.abortSimulation(SimulationAbort.Cause.NO_MOTORS_DEFINED);
}
} while (!toSimulate.isEmpty());
// Problems that let us simulate, but result is likely bad
// No recovery device
if (!simulationConfig.hasRecoveryDevice()) {
currentStatus.getWarnings().add(Warning.NO_RECOVERY_DEVICE);
}
currentStatus.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket()));
toSimulate.push(currentStatus);
SimulationListenerHelper.fireEndSimulation(currentStatus, null);
if (!flightData.getWarningSet().isEmpty()) {
log.info("Warnings at the end of simulation: " + flightData.getWarningSet());
SimulationListenerHelper.fireStartSimulation(currentStatus);
do {
if (toSimulate.peek() == null) {
break;
}
currentStatus = toSimulate.pop();
FlightDataBranch dataBranch = currentStatus.getFlightDataBranch();
flightData.addBranch(dataBranch);
log.info(">>Starting simulation of branch: " + currentStatus.getFlightDataBranch().getName());
simulateLoop();
dataBranch.immute();
flightData.getWarningSet().addAll(currentStatus.getWarnings());
log.info(String.format("<<Finished simulating branch: %s curTime:%s finTime:%s",
dataBranch.getName(),
currentStatus.getSimulationTime(),
dataBranch.getLast(FlightDataType.TYPE_TIME)));
// Did the branch generate any data?
if (dataBranch.getLength() == 0) {
flightData.getWarningSet().add(Warning.EMPTY_BRANCH, dataBranch.getName());
}
} while (!toSimulate.isEmpty());
SimulationListenerHelper.fireEndSimulation(currentStatus, null);
if (!flightData.getWarningSet().isEmpty()) {
log.info("Warnings at the end of simulation: " + flightData.getWarningSet());
}
} catch (SimulationException e) {
throw e;
} finally {
flightData.calculateInterestingValues();
}
return flightData;
}
private FlightDataBranch simulateLoop() throws SimulationException {
private void simulateLoop() throws SimulationException {
// Initialize the simulation. We'll use the flight stepper unless we're already
// on the ground
@ -264,9 +270,9 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// and aoa > AOA_TUMBLE_CONDITION threshold
if (!currentStatus.isTumbling()) {
final double cp = currentStatus.getFlightData().getLast(FlightDataType.TYPE_CP_LOCATION);
final double cg = currentStatus.getFlightData().getLast(FlightDataType.TYPE_CG_LOCATION);
final double aoa = currentStatus.getFlightData().getLast(FlightDataType.TYPE_AOA);
final double cp = currentStatus.getFlightDataBranch().getLast(FlightDataType.TYPE_CP_LOCATION);
final double cg = currentStatus.getFlightDataBranch().getLast(FlightDataType.TYPE_CG_LOCATION);
final double aoa = currentStatus.getFlightDataBranch().getLast(FlightDataType.TYPE_AOA);
if (cg > cp && aoa > AOA_TUMBLE_CONDITION) {
currentStatus.addEvent(new FlightEvent(FlightEvent.Type.TUMBLE, currentStatus.getSimulationTime()));
@ -281,21 +287,16 @@ public class BasicEventSimulationEngine implements SimulationEngine {
}
} catch (SimulationException e) {
SimulationListenerHelper.fireEndSimulation(currentStatus, e);
// Add FlightEvent for exception.
currentStatus.getFlightData().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, currentStatus.getSimulationTime(), currentStatus.getConfiguration().getRocket(), e.getLocalizedMessage()));
currentStatus.getFlightDataBranch().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, currentStatus.getSimulationTime(), currentStatus.getConfiguration().getRocket(), e.getLocalizedMessage()));
flightData.addBranch(currentStatus.getFlightData());
flightData.getWarningSet().addAll(currentStatus.getWarnings());
e.setFlightData(flightData);
e.setFlightDataBranch(currentStatus.getFlightData());
throw e;
}
return currentStatus.getFlightData();
}
/**
@ -307,7 +308,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
boolean ret = true;
FlightEvent event;
log.trace("HandleEvents: current branch = " + currentStatus.getFlightData().getBranchName());
log.trace("HandleEvents: current branch = " + currentStatus.getFlightDataBranch().getName());
for (event = nextEvent(); event != null; event = nextEvent()) {
log.trace("Obtained event from queue: " + event.toString());
log.trace("Remaining EventQueue = " + currentStatus.getEventQueue().toString());
@ -390,7 +391,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
switch (event.getType()) {
case LAUNCH: {
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
break;
}
@ -412,7 +413,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
// Ignite the motor
currentStatus.setMotorIgnited(true);
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
// ... ignite ...uhh, again?
// TBH, I'm not sure what this call is for. It seems to be mostly a bunch of
@ -442,14 +443,14 @@ public class BasicEventSimulationEngine implements SimulationEngine {
case LIFTOFF: {
// Mark lift-off as occurred
currentStatus.setLiftoff(true);
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
break;
}
case LAUNCHROD: {
// Mark launch rod as cleared
currentStatus.setLaunchRodCleared(true);
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
break;
}
@ -472,14 +473,14 @@ public class BasicEventSimulationEngine implements SimulationEngine {
currentStatus.addEvent(new FlightEvent(FlightEvent.Type.EJECTION_CHARGE, currentStatus.getSimulationTime() + delay,
stage, event.getData()));
}
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
break;
}
case EJECTION_CHARGE: {
MotorClusterState motorState = (MotorClusterState) event.getData();
motorState.expend( event.getTime() );
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
break;
}
@ -490,7 +491,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
if (currentStatus.getConfiguration().isStageActive(stageNumber - 1)) {
// Record the event.
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
// If I've got something other than one active stage below the separation point,
// flag a warning
@ -513,8 +514,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
SimulationStatus boosterStatus = new SimulationStatus(currentStatus);
// Prepare the new simulation branch
boosterStatus.setFlightData(new FlightDataBranch(boosterStage.getName(), boosterStage, currentStatus.getFlightData()));
boosterStatus.getFlightData().addEvent(event);
boosterStatus.setFlightDataBranch(new FlightDataBranch(boosterStage.getName(), boosterStage, currentStatus.getFlightDataBranch()));
boosterStatus.getFlightDataBranch().addEvent(event);
// Mark the current status as having dropped the current stage and all stages
// below it
@ -530,7 +531,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
log.info(String.format("==>> @ %g; from Branch: %s ---- Branching: %s ---- \n",
currentStatus.getSimulationTime(),
currentStatus.getFlightData().getBranchName(), boosterStatus.getFlightData().getBranchName()));
currentStatus.getFlightDataBranch().getName(), boosterStatus.getFlightDataBranch().getName()));
} else {
log.debug("upper stage is not active; not performing separation");
}
@ -541,11 +542,11 @@ public class BasicEventSimulationEngine implements SimulationEngine {
case APOGEE:
// Mark apogee as reached
currentStatus.setApogeeReached(true);
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
// This apogee event might be the optimum if recovery has not already happened.
if (currentStatus.getDeployedRecoveryDevices().size() == 0) {
currentStatus.getFlightData().setOptimumAltitude(currentStatus.getMaxAlt());
currentStatus.getFlightData().setTimeToOptimumAltitude(currentStatus.getMaxAltTime());
currentStatus.getFlightDataBranch().setOptimumAltitude(currentStatus.getMaxAlt());
currentStatus.getFlightDataBranch().setTimeToOptimumAltitude(currentStatus.getMaxAltTime());
}
break;
@ -582,8 +583,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
if (!currentStatus.isApogeeReached()) {
FlightData coastStatus = computeCoastTime();
currentStatus.getFlightData().setOptimumAltitude(coastStatus.getMaxAltitude());
currentStatus.getFlightData().setTimeToOptimumAltitude(coastStatus.getTimeToApogee());
currentStatus.getFlightDataBranch().setOptimumAltitude(coastStatus.getMaxAltitude());
currentStatus.getFlightDataBranch().setTimeToOptimumAltitude(coastStatus.getTimeToApogee());
}
// switch to landing stepper (unless we're already on the ground)
@ -592,7 +593,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
currentStatus = currentStepper.initialize(currentStatus);
}
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
}
log.debug("deployed recovery devices: " + currentStatus.getDeployedRecoveryDevices().size() );
break;
@ -603,17 +604,17 @@ public class BasicEventSimulationEngine implements SimulationEngine {
currentStepper = groundStepper;
currentStatus = currentStepper.initialize(currentStatus);
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
break;
case SIM_ABORT:
ret = false;
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
break;
case SIMULATION_END:
ret = false;
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
break;
case ALTITUDE:
@ -628,13 +629,13 @@ public class BasicEventSimulationEngine implements SimulationEngine {
currentStepper = tumbleStepper;
currentStatus = currentStepper.initialize(currentStatus);
final boolean tooMuchThrust = currentStatus.getFlightData().getLast(FlightDataType.TYPE_THRUST_FORCE) > THRUST_TUMBLE_CONDITION;
final boolean tooMuchThrust = currentStatus.getFlightDataBranch().getLast(FlightDataType.TYPE_THRUST_FORCE) > THRUST_TUMBLE_CONDITION;
if (tooMuchThrust) {
currentStatus.abortSimulation(SimulationAbort.Cause.TUMBLE_UNDER_THRUST);
}
currentStatus.setTumbling(true);
currentStatus.getFlightData().addEvent(event);
currentStatus.getFlightDataBranch().addEvent(event);
break;
}
@ -645,7 +646,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
if (1200 < currentStatus.getSimulationTime()) {
ret = false;
log.error("Simulation hit max time (1200s): aborting.");
currentStatus.getFlightData()
currentStatus.getFlightDataBranch()
.addEvent(new FlightEvent(FlightEvent.Type.SIMULATION_END, currentStatus.getSimulationTime()));
}
@ -697,7 +698,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
if (currentStatus.getConfiguration().getLengthAerodynamic() < MathUtil.EPSILON) {
currentStatus.abortSimulation(SimulationAbort.Cause.ACTIVE_LENGTH_ZERO);
}
// test -- force an exception if we aren't the sustainer
// if (currentStatus.getConfiguration().isStageActive(0)) {
// throw new SimulationCalculationException("test", currentStatus.getFlightDataBranch());
// }
// Can't calculate stability. If it's the sustainer we'll abort; if a booster
// we'll just transition to tumbling (if it's a booster and under thrust code elsewhere
// will abort).
@ -731,7 +737,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
" rocketOrientationQuaternion=" + currentStatus.getRocketOrientationQuaternion() +
" rocketRotationVelocity=" + currentStatus.getRocketRotationVelocity() +
" effectiveLaunchRodLength=" + currentStatus.getEffectiveLaunchRodLength());
throw new SimulationCalculationException(trans.get("BasicEventSimulationEngine.error.NaNResult"));
throw new SimulationCalculationException(trans.get("BasicEventSimulationEngine.error.NaNResult"),
currentStatus.getFlightDataBranch());
}
}
@ -739,10 +746,10 @@ public class BasicEventSimulationEngine implements SimulationEngine {
try {
SimulationConditions conds = currentStatus.getSimulationConditions().clone();
conds.getSimulationListenerList().add(OptimumCoastListener.INSTANCE);
BasicEventSimulationEngine e = new BasicEventSimulationEngine();
BasicEventSimulationEngine coastEngine = new BasicEventSimulationEngine();
FlightData d = e.simulate(conds);
return d;
coastEngine.simulate(conds);
return coastEngine.getFlightData();
} catch (SimulationException e) {
throw e;
} catch (Exception e) {
@ -750,4 +757,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
return null;
}
}
public FlightData getFlightData() {
return flightData;
}
}

View File

@ -126,12 +126,7 @@ public class FlightData {
public void addBranch(FlightDataBranch branch) {
mutable.check();
branch.immute();
branches.add(branch);
if (branches.size() == 1) {
calculateInterestingValues();
}
}
public int getBranchCount() {
@ -201,7 +196,7 @@ public class FlightData {
* Calculate the max. altitude/velocity/acceleration, time to apogee, flight time
* and ground hit velocity.
*/
private void calculateInterestingValues() {
public void calculateInterestingValues() {
if (branches.isEmpty())
return;

View File

@ -31,7 +31,7 @@ import info.openrocket.core.util.Mutable;
public class FlightDataBranch implements Monitorable {
/** The name of this flight data branch. */
private final String branchName;
private final String name;
private final Map<FlightDataType, ArrayList<Double>> values = new LinkedHashMap<>();
@ -64,7 +64,7 @@ public class FlightDataBranch implements Monitorable {
throw new IllegalArgumentException("Must specify at least one data type.");
}
this.branchName = name;
this.name = name;
for (FlightDataType t : types) {
if (values.containsKey(t)) {
@ -83,12 +83,12 @@ public class FlightDataBranch implements Monitorable {
* when creating a new branch upon stage separation, so the data at separation is present
* in both branches (and if the new branch has an immediate exception, it can be plotted)
*
* @param branchName the name of the new branch.
* @param name the name of the new branch.
* @param srcComponent the component that is the source of the new branch.
* @param parent the parent branch to copy data from.
*/
public FlightDataBranch(String branchName, RocketComponent srcComponent, FlightDataBranch parent) {
this.branchName = branchName;
public FlightDataBranch(String name, RocketComponent srcComponent, FlightDataBranch parent) {
this.name = name;
// Copy all the values from the parent
copyValuesFromBranch(parent, srcComponent);
@ -98,7 +98,7 @@ public class FlightDataBranch implements Monitorable {
* Makes an 'empty' flight data branch which has no data but all built in data types are defined.
*/
public FlightDataBranch() {
branchName = "Empty branch";
name = "Empty branch";
for (FlightDataType type : FlightDataType.ALL_TYPES) {
this.setValue(type, Double.NaN);
}
@ -230,8 +230,8 @@ public class FlightDataBranch implements Monitorable {
/**
* Return the branch name.
*/
public String getBranchName() {
return branchName;
public String getName() {
return name;
}
/**
@ -447,7 +447,7 @@ public class FlightDataBranch implements Monitorable {
public FlightDataBranch clone() {
FlightDataType[] types = getTypes();
FlightDataBranch clone = new FlightDataBranch(branchName, types);
FlightDataBranch clone = new FlightDataBranch(name, types);
for (FlightDataType type : values.keySet()) {
clone.values.put(type, values.get(type).clone());
}

View File

@ -247,7 +247,7 @@ public class RK4SimulationStepper extends AbstractSimulationStepper {
if (status.getRocketVelocity().length2() > 1e18 ||
status.getRocketPosition().length2() > 1e18 ||
status.getRocketRotationVelocity().length2() > 1e18) {
throw new SimulationCalculationException(trans.get("error.valuesTooLarge"));
throw new SimulationCalculationException(trans.get("error.valuesTooLarge"), status.getFlightDataBranch());
}
}
@ -526,117 +526,117 @@ public class RK4SimulationStepper extends AbstractSimulationStepper {
private void storeData(RK4SimulationStatus status, DataStore store) {
FlightDataBranch data = status.getFlightData();
FlightDataBranch dataBranch = status.getFlightDataBranch();
data.addPoint();
data.setValue(FlightDataType.TYPE_TIME, status.getSimulationTime());
data.setValue(FlightDataType.TYPE_ALTITUDE, status.getRocketPosition().z);
data.setValue(FlightDataType.TYPE_POSITION_X, status.getRocketPosition().x);
data.setValue(FlightDataType.TYPE_POSITION_Y, status.getRocketPosition().y);
dataBranch.addPoint();
dataBranch.setValue(FlightDataType.TYPE_TIME, status.getSimulationTime());
dataBranch.setValue(FlightDataType.TYPE_ALTITUDE, status.getRocketPosition().z);
dataBranch.setValue(FlightDataType.TYPE_POSITION_X, status.getRocketPosition().x);
dataBranch.setValue(FlightDataType.TYPE_POSITION_Y, status.getRocketPosition().y);
data.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad());
data.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad());
dataBranch.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad());
dataBranch.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad());
if (status.getSimulationConditions().getGeodeticComputation() != GeodeticComputationStrategy.FLAT) {
data.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, store.coriolisAcceleration.length());
dataBranch.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, store.coriolisAcceleration.length());
}
data.setValue(FlightDataType.TYPE_POSITION_XY,
dataBranch.setValue(FlightDataType.TYPE_POSITION_XY,
MathUtil.hypot(status.getRocketPosition().x, status.getRocketPosition().y));
data.setValue(FlightDataType.TYPE_POSITION_DIRECTION,
dataBranch.setValue(FlightDataType.TYPE_POSITION_DIRECTION,
Math.atan2(status.getRocketPosition().y, status.getRocketPosition().x));
data.setValue(FlightDataType.TYPE_VELOCITY_XY,
dataBranch.setValue(FlightDataType.TYPE_VELOCITY_XY,
MathUtil.hypot(status.getRocketVelocity().x, status.getRocketVelocity().y));
if (store.linearAcceleration != null) {
data.setValue(FlightDataType.TYPE_ACCELERATION_XY,
dataBranch.setValue(FlightDataType.TYPE_ACCELERATION_XY,
MathUtil.hypot(store.linearAcceleration.x, store.linearAcceleration.y));
data.setValue(FlightDataType.TYPE_ACCELERATION_TOTAL, store.linearAcceleration.length());
dataBranch.setValue(FlightDataType.TYPE_ACCELERATION_TOTAL, store.linearAcceleration.length());
}
if (store.flightConditions != null) {
double Re = (store.flightConditions.getVelocity() *
status.getConfiguration().getLengthAerodynamic() /
store.flightConditions.getAtmosphericConditions().getKinematicViscosity());
data.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Re);
dataBranch.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Re);
}
data.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z);
dataBranch.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z);
if (store.linearAcceleration != null) {
data.setValue(FlightDataType.TYPE_ACCELERATION_Z, store.linearAcceleration.z);
dataBranch.setValue(FlightDataType.TYPE_ACCELERATION_Z, store.linearAcceleration.z);
}
if (store.flightConditions != null) {
data.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, status.getRocketVelocity().length());
data.setValue(FlightDataType.TYPE_MACH_NUMBER, store.flightConditions.getMach());
dataBranch.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, status.getRocketVelocity().length());
dataBranch.setValue(FlightDataType.TYPE_MACH_NUMBER, store.flightConditions.getMach());
}
if (store.rocketMass != null) {
data.setValue(FlightDataType.TYPE_CG_LOCATION, store.rocketMass.getCM().x);
dataBranch.setValue(FlightDataType.TYPE_CG_LOCATION, store.rocketMass.getCM().x);
}
if (status.isLaunchRodCleared()) {
// Don't include CP and stability with huge launch AOA
if (store.forces != null) {
data.setValue(FlightDataType.TYPE_CP_LOCATION, store.forces.getCP().x);
dataBranch.setValue(FlightDataType.TYPE_CP_LOCATION, store.forces.getCP().x);
}
if (store.forces != null && store.flightConditions != null && store.rocketMass != null) {
data.setValue(FlightDataType.TYPE_STABILITY,
dataBranch.setValue(FlightDataType.TYPE_STABILITY,
(store.forces.getCP().x - store.rocketMass.getCM().x) / store.flightConditions.getRefLength());
}
}
if (null != store.motorMass) {
data.setValue(FlightDataType.TYPE_MOTOR_MASS, store.motorMass.getMass());
//data.setValue(FlightDataType.TYPE_MOTOR_LONGITUDINAL_INERTIA, store.motorMassData.getLongitudinalInertia());
//data.setValue(FlightDataType.TYPE_MOTOR_ROTATIONAL_INERTIA, store.motorMassData.getRotationalInertia());
dataBranch.setValue(FlightDataType.TYPE_MOTOR_MASS, store.motorMass.getMass());
//dataBranch.setValue(FlightDataType.TYPE_MOTOR_LONGITUDINAL_INERTIA, store.motorMassData.getLongitudinalInertia());
//dataBranch.setValue(FlightDataType.TYPE_MOTOR_ROTATIONAL_INERTIA, store.motorMassData.getRotationalInertia());
}
if (store.rocketMass != null) {
// N.B.: These refer to total mass
data.setValue(FlightDataType.TYPE_MASS, store.rocketMass.getMass());
data.setValue(FlightDataType.TYPE_LONGITUDINAL_INERTIA, store.rocketMass.getLongitudinalInertia());
data.setValue(FlightDataType.TYPE_ROTATIONAL_INERTIA, store.rocketMass.getRotationalInertia());
dataBranch.setValue(FlightDataType.TYPE_MASS, store.rocketMass.getMass());
dataBranch.setValue(FlightDataType.TYPE_LONGITUDINAL_INERTIA, store.rocketMass.getLongitudinalInertia());
dataBranch.setValue(FlightDataType.TYPE_ROTATIONAL_INERTIA, store.rocketMass.getRotationalInertia());
}
data.setValue(FlightDataType.TYPE_THRUST_FORCE, store.thrustForce);
dataBranch.setValue(FlightDataType.TYPE_THRUST_FORCE, store.thrustForce);
double weight = store.rocketMass.getMass() * store.gravity;
data.setValue(FlightDataType.TYPE_THRUST_WEIGHT_RATIO, store.thrustForce / weight);
data.setValue(FlightDataType.TYPE_DRAG_FORCE, store.dragForce);
data.setValue(FlightDataType.TYPE_GRAVITY, store.gravity);
dataBranch.setValue(FlightDataType.TYPE_THRUST_WEIGHT_RATIO, store.thrustForce / weight);
dataBranch.setValue(FlightDataType.TYPE_DRAG_FORCE, store.dragForce);
dataBranch.setValue(FlightDataType.TYPE_GRAVITY, store.gravity);
if (status.isLaunchRodCleared() && store.forces != null) {
if (store.rocketMass != null && store.flightConditions != null) {
data.setValue(FlightDataType.TYPE_PITCH_MOMENT_COEFF,
dataBranch.setValue(FlightDataType.TYPE_PITCH_MOMENT_COEFF,
store.forces.getCm() - store.forces.getCN() * store.rocketMass.getCM().x / store.flightConditions.getRefLength());
data.setValue(FlightDataType.TYPE_YAW_MOMENT_COEFF,
dataBranch.setValue(FlightDataType.TYPE_YAW_MOMENT_COEFF,
store.forces.getCyaw() - store.forces.getCside() * store.rocketMass.getCM().x / store.flightConditions.getRefLength());
}
data.setValue(FlightDataType.TYPE_NORMAL_FORCE_COEFF, store.forces.getCN());
data.setValue(FlightDataType.TYPE_SIDE_FORCE_COEFF, store.forces.getCside());
data.setValue(FlightDataType.TYPE_ROLL_MOMENT_COEFF, store.forces.getCroll());
data.setValue(FlightDataType.TYPE_ROLL_FORCING_COEFF, store.forces.getCrollForce());
data.setValue(FlightDataType.TYPE_ROLL_DAMPING_COEFF, store.forces.getCrollDamp());
data.setValue(FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF,
dataBranch.setValue(FlightDataType.TYPE_NORMAL_FORCE_COEFF, store.forces.getCN());
dataBranch.setValue(FlightDataType.TYPE_SIDE_FORCE_COEFF, store.forces.getCside());
dataBranch.setValue(FlightDataType.TYPE_ROLL_MOMENT_COEFF, store.forces.getCroll());
dataBranch.setValue(FlightDataType.TYPE_ROLL_FORCING_COEFF, store.forces.getCrollForce());
dataBranch.setValue(FlightDataType.TYPE_ROLL_DAMPING_COEFF, store.forces.getCrollDamp());
dataBranch.setValue(FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF,
store.forces.getPitchDampingMoment());
}
if (store.forces != null) {
data.setValue(FlightDataType.TYPE_DRAG_COEFF, store.forces.getCD());
data.setValue(FlightDataType.TYPE_AXIAL_DRAG_COEFF, store.forces.getCDaxial());
data.setValue(FlightDataType.TYPE_FRICTION_DRAG_COEFF, store.forces.getFrictionCD());
data.setValue(FlightDataType.TYPE_PRESSURE_DRAG_COEFF, store.forces.getPressureCD());
data.setValue(FlightDataType.TYPE_BASE_DRAG_COEFF, store.forces.getBaseCD());
dataBranch.setValue(FlightDataType.TYPE_DRAG_COEFF, store.forces.getCD());
dataBranch.setValue(FlightDataType.TYPE_AXIAL_DRAG_COEFF, store.forces.getCDaxial());
dataBranch.setValue(FlightDataType.TYPE_FRICTION_DRAG_COEFF, store.forces.getFrictionCD());
dataBranch.setValue(FlightDataType.TYPE_PRESSURE_DRAG_COEFF, store.forces.getPressureCD());
dataBranch.setValue(FlightDataType.TYPE_BASE_DRAG_COEFF, store.forces.getBaseCD());
}
if (store.flightConditions != null) {
data.setValue(FlightDataType.TYPE_REFERENCE_LENGTH, store.flightConditions.getRefLength());
data.setValue(FlightDataType.TYPE_REFERENCE_AREA, store.flightConditions.getRefArea());
dataBranch.setValue(FlightDataType.TYPE_REFERENCE_LENGTH, store.flightConditions.getRefLength());
dataBranch.setValue(FlightDataType.TYPE_REFERENCE_AREA, store.flightConditions.getRefArea());
data.setValue(FlightDataType.TYPE_PITCH_RATE, store.flightConditions.getPitchRate());
data.setValue(FlightDataType.TYPE_YAW_RATE, store.flightConditions.getYawRate());
data.setValue(FlightDataType.TYPE_ROLL_RATE, store.flightConditions.getRollRate());
dataBranch.setValue(FlightDataType.TYPE_PITCH_RATE, store.flightConditions.getPitchRate());
dataBranch.setValue(FlightDataType.TYPE_YAW_RATE, store.flightConditions.getYawRate());
dataBranch.setValue(FlightDataType.TYPE_ROLL_RATE, store.flightConditions.getRollRate());
data.setValue(FlightDataType.TYPE_AOA, store.flightConditions.getAOA());
dataBranch.setValue(FlightDataType.TYPE_AOA, store.flightConditions.getAOA());
}
Coordinate c = status.getRocketOrientationQuaternion().rotateZ();
@ -644,23 +644,23 @@ public class RK4SimulationStepper extends AbstractSimulationStepper {
double phi = Math.atan2(c.y, c.x);
if (phi < -(Math.PI - 0.0001))
phi = Math.PI;
data.setValue(FlightDataType.TYPE_ORIENTATION_THETA, theta);
data.setValue(FlightDataType.TYPE_ORIENTATION_PHI, phi);
dataBranch.setValue(FlightDataType.TYPE_ORIENTATION_THETA, theta);
dataBranch.setValue(FlightDataType.TYPE_ORIENTATION_PHI, phi);
data.setValue(FlightDataType.TYPE_WIND_VELOCITY, store.windSpeed);
dataBranch.setValue(FlightDataType.TYPE_WIND_VELOCITY, store.windSpeed);
if (store.flightConditions != null) {
data.setValue(FlightDataType.TYPE_AIR_TEMPERATURE,
dataBranch.setValue(FlightDataType.TYPE_AIR_TEMPERATURE,
store.flightConditions.getAtmosphericConditions().getTemperature());
data.setValue(FlightDataType.TYPE_AIR_PRESSURE,
dataBranch.setValue(FlightDataType.TYPE_AIR_PRESSURE,
store.flightConditions.getAtmosphericConditions().getPressure());
data.setValue(FlightDataType.TYPE_SPEED_OF_SOUND,
dataBranch.setValue(FlightDataType.TYPE_SPEED_OF_SOUND,
store.flightConditions.getAtmosphericConditions().getMachSpeed());
}
data.setValue(FlightDataType.TYPE_TIME_STEP, store.timestep);
data.setValue(FlightDataType.TYPE_COMPUTATION_TIME,
dataBranch.setValue(FlightDataType.TYPE_TIME_STEP, store.timestep);
dataBranch.setValue(FlightDataType.TYPE_COMPUTATION_TIME,
(System.nanoTime() - status.getSimulationStartWallTime()) / 1000000000.0);
}

View File

@ -17,10 +17,16 @@ public interface SimulationEngine {
* Simulate the flight of a rocket.
*
* @param simulation the simulation conditions which to simulate.
* @return a FlightData object containing the simulated data.
* @throws SimulationException if an error occurs during simulation
*/
public FlightData simulate(SimulationConditions simulation)
public void simulate(SimulationConditions simulation)
throws SimulationException;
/**
* Obtain data generated by simulation
*
* @return flight data
*/
public FlightData getFlightData();
}

View File

@ -39,7 +39,7 @@ public class SimulationStatus implements Monitorable {
private SimulationConditions simulationConditions;
private FlightConfiguration configuration;
private FlightDataBranch flightData;
private FlightDataBranch flightDataBranch;
private double time;
@ -169,8 +169,8 @@ public class SimulationStatus implements Monitorable {
public SimulationStatus(SimulationStatus orig) {
this.simulationConditions = orig.simulationConditions.clone();
this.configuration = orig.configuration.clone();
// FlightData is not cloned.
this.flightData = orig.flightData;
// FlightDataBranch is not cloned.
this.flightDataBranch = orig.flightDataBranch;
this.time = orig.time;
this.position = orig.position;
this.acceleration = orig.acceleration;
@ -247,15 +247,15 @@ public class SimulationStatus implements Monitorable {
return configuration;
}
public void setFlightData(FlightDataBranch flightData) {
if (this.flightData != null)
this.modIDadd += this.flightData.getModID();
public void setFlightDataBranch(FlightDataBranch flightDataBranch) {
if (this.flightDataBranch != null)
this.modIDadd += this.flightDataBranch.getModID();
this.modID++;
this.flightData = flightData;
this.flightDataBranch = flightDataBranch;
}
public FlightDataBranch getFlightData() {
return flightData;
public FlightDataBranch getFlightDataBranch() {
return flightDataBranch;
}
public void setRocketPosition(Coordinate position) {
@ -481,7 +481,7 @@ public class SimulationStatus implements Monitorable {
@Override
public int getModID() {
return (modID + modIDadd + simulationConditions.getModID() + configuration.getModID() +
flightData.getModID() + deployedRecoveryDevices.getModID() +
flightDataBranch.getModID() + deployedRecoveryDevices.getModID() +
eventQueue.getModID() + warnings.getModID());
}

View File

@ -6,6 +6,7 @@ import java.util.regex.Pattern;
import info.openrocket.core.document.OpenRocketDocument;
import info.openrocket.core.logging.Markers;
import info.openrocket.core.simulation.FlightDataBranch;
import info.openrocket.core.simulation.FlightDataType;
import info.openrocket.core.simulation.SimulationStatus;
import info.openrocket.core.unit.FixedUnitGroup;
@ -431,8 +432,9 @@ public class CustomExpression implements Cloneable {
// Set all the built-in variables. Strictly we surely won't need all of them
// Going through and checking them to include only the ones used *might* give a
// speedup
for (FlightDataType type : status.getFlightData().getTypes()) {
double value = status.getFlightData().getLast(type);
FlightDataBranch dataBranch = status.getFlightDataBranch();
for (FlightDataType type : dataBranch.getTypes()) {
double value = dataBranch.getLast(type);
calc.setVariable(new Variable(type.getSymbol(), value));
}

View File

@ -26,12 +26,12 @@ public class CustomExpressionSimulationListener extends AbstractSimulationListen
return;
}
// Calculate values for custom expressions
FlightDataBranch data = status.getFlightData();
FlightDataBranch dataBranch = status.getFlightDataBranch();
for (CustomExpression expression : expressions) {
double value = expression.evaluateDouble(status);
// log.debug("Setting value of custom expression "+expression.toString()+" =
// "+value);
data.setValue(expression.getType(), value);
dataBranch.setValue(expression.getType(), value);
}
}

View File

@ -10,6 +10,7 @@ import de.congrace.exp4j.Variable;
import info.openrocket.core.document.OpenRocketDocument;
import info.openrocket.core.logging.Markers;
import info.openrocket.core.simulation.customexpression.CustomExpression;
import info.openrocket.core.simulation.FlightDataBranch;
import info.openrocket.core.simulation.FlightDataType;
import info.openrocket.core.simulation.SimulationStatus;
import info.openrocket.core.util.LinearInterpolator;
@ -41,13 +42,14 @@ public class IndexExpression extends CustomExpression {
// Otherwise there will be a type conflict when we get the new data.
FlightDataType myType = FlightDataType.getType(null, getSymbol(), null);
List<Double> data = status.getFlightData().get(myType);
List<Double> time = status.getFlightData().get(FlightDataType.TYPE_TIME);
FlightDataBranch dataBranch = status.getFlightDataBranch();
List<Double> data = dataBranch.get(myType);
List<Double> time = dataBranch.get(FlightDataType.TYPE_TIME);
LinearInterpolator interp = new LinearInterpolator(time, data);
// Set the variables in the expression to evaluate
for (FlightDataType etype : status.getFlightData().getTypes()) {
double value = status.getFlightData().getLast(etype);
for (FlightDataType etype : dataBranch.getTypes()) {
double value = dataBranch.getLast(etype);
calc.setVariable(new Variable(etype.getSymbol(), value));
}

View File

@ -14,6 +14,7 @@ import de.congrace.exp4j.ExpressionBuilder;
import de.congrace.exp4j.Variable;
import info.openrocket.core.document.OpenRocketDocument;
import info.openrocket.core.logging.Markers;
import info.openrocket.core.simulation.FlightDataBranch;
import info.openrocket.core.simulation.FlightDataType;
import info.openrocket.core.simulation.SimulationStatus;
import info.openrocket.core.util.ArrayUtils;
@ -66,9 +67,10 @@ public class RangeExpression extends CustomExpression {
return new Variable("Unknown");
}
FlightDataBranch dataBranch = status.getFlightDataBranch();
// Set the variables in the start and end calculators
for (FlightDataType type : status.getFlightData().getTypes()) {
double value = status.getFlightData().getLast(type);
for (FlightDataType type : dataBranch.getTypes()) {
double value = dataBranch.getLast(type);
startCalc.setVariable(new Variable(type.getSymbol(), value));
endCalc.setVariable(new Variable(type.getSymbol(), value));
}
@ -80,8 +82,8 @@ public class RangeExpression extends CustomExpression {
// Otherwise there will be a type conflict when we get the new data.
FlightDataType type = FlightDataType.getType(null, getSymbol(), null);
List<Double> data = status.getFlightData().get(type);
List<Double> time = status.getFlightData().get(FlightDataType.TYPE_TIME);
List<Double> data = dataBranch.get(type);
List<Double> time = dataBranch.get(FlightDataType.TYPE_TIME);
LinearInterpolator interp = new LinearInterpolator(time, data);
// Evaluate the expression to get the start and end of the range

View File

@ -1,5 +1,7 @@
package info.openrocket.core.simulation.exception;
import info.openrocket.core.simulation.FlightDataBranch;
/**
* An exception that indicates that a computation problem has occurred during
* the simulation, for example that some values have exceed reasonable bounds.
@ -8,19 +10,27 @@ package info.openrocket.core.simulation.exception;
*/
public class SimulationCalculationException extends SimulationException {
private FlightDataBranch flightDataBranch;
public SimulationCalculationException() {
}
public SimulationCalculationException(String message) {
public SimulationCalculationException(String message, FlightDataBranch dataBranch) {
super(message);
flightDataBranch = dataBranch;
}
public SimulationCalculationException(Throwable cause) {
public SimulationCalculationException(Throwable cause, FlightDataBranch dataBranch) {
super(cause);
flightDataBranch = dataBranch;
}
public SimulationCalculationException(String message, Throwable cause) {
public SimulationCalculationException(String message, Throwable cause, FlightDataBranch dataBranch) {
super(message, cause);
flightDataBranch = dataBranch;
}
public FlightDataBranch getFlightDataBranch() {
return flightDataBranch;
}
}

View File

@ -1,15 +1,9 @@
package info.openrocket.core.simulation.exception;
import info.openrocket.core.simulation.FlightData;
import info.openrocket.core.simulation.FlightDataBranch;
public class SimulationException extends Exception {
private FlightData flightData = null;
private FlightDataBranch flightDataBranch = null;
public SimulationException() {
super();
}
public SimulationException(String message) {
@ -23,21 +17,4 @@ public class SimulationException extends Exception {
public SimulationException(String message, Throwable cause) {
super(message, cause);
}
public void setFlightData(FlightData f) {
flightData = f;
}
public FlightData getFlightData() {
return flightData;
}
public void setFlightDataBranch(FlightDataBranch f) {
flightDataBranch = f;
}
public FlightDataBranch getFlightDataBranch() {
return flightDataBranch;
}
}

View File

@ -63,122 +63,122 @@ public class CSVSave extends AbstractSimulationExtension {
THETA {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_ORIENTATION_THETA);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_ORIENTATION_THETA);
}
},
PHI {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_ORIENTATION_PHI);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_ORIENTATION_PHI);
}
},
AOA {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_AOA);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_AOA);
}
},
ROLLRATE {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_ROLL_RATE);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_ROLL_RATE);
}
},
PITCHRATE {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_PITCH_RATE);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_PITCH_RATE);
}
},
PITCHMOMENT {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_PITCH_MOMENT_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_PITCH_MOMENT_COEFF);
}
},
YAWMOMENT {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_YAW_MOMENT_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_YAW_MOMENT_COEFF);
}
},
ROLLMOMENT {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_ROLL_MOMENT_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_ROLL_MOMENT_COEFF);
}
},
NORMALFORCE {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_NORMAL_FORCE_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_NORMAL_FORCE_COEFF);
}
},
SIDEFORCE {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_SIDE_FORCE_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_SIDE_FORCE_COEFF);
}
},
AXIALFORCE {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_DRAG_FORCE);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_DRAG_FORCE);
}
},
WINDSPEED {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_WIND_VELOCITY);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_WIND_VELOCITY);
}
},
PITCHDAMPING {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF);
}
},
CA {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_AXIAL_DRAG_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_AXIAL_DRAG_COEFF);
}
},
CD {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_DRAG_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_DRAG_COEFF);
}
},
CDpressure {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_PRESSURE_DRAG_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_PRESSURE_DRAG_COEFF);
}
},
CDfriction {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_FRICTION_DRAG_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_FRICTION_DRAG_COEFF);
}
},
CDbase {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_BASE_DRAG_COEFF);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_BASE_DRAG_COEFF);
}
},
MACH {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_MACH_NUMBER);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_MACH_NUMBER);
}
},
RE {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_REYNOLDS_NUMBER);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_REYNOLDS_NUMBER);
}
},
@ -204,7 +204,7 @@ public class CSVSave extends AbstractSimulationExtension {
MASS {
@Override
public double getValue(SimulationStatus status) {
return status.getFlightData().getLast(FlightDataType.TYPE_MASS);
return status.getFlightDataBranch().getLast(FlightDataType.TYPE_MASS);
}
}

View File

@ -61,8 +61,8 @@ public class DampingMoment extends AbstractSimulationExtension {
public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions)
throws SimulationException {
// status.getFlightData().setValue(cdm, aerodynamicPart + propulsivePart);
status.getFlightData().setValue(cdm, calculate(status, flightConditions));
// status.getFlightDataBranch().setValue(cdm, aerodynamicPart + propulsivePart);
status.getFlightDataBranch().setValue(cdm, calculate(status, flightConditions));
return flightConditions;
}
@ -72,10 +72,10 @@ public class DampingMoment extends AbstractSimulationExtension {
// Work out the propulsive/jet damping part of the moment.
// dm/dt = (thrust - ma)/v
FlightDataBranch data = status.getFlightData();
FlightDataBranch dataBranch = status.getFlightDataBranch();
List<Double> mpAll = data.get(FlightDataType.TYPE_MOTOR_MASS);
List<Double> time = data.get(FlightDataType.TYPE_TIME);
List<Double> mpAll = dataBranch.get(FlightDataType.TYPE_MOTOR_MASS);
List<Double> time = dataBranch.get(FlightDataType.TYPE_TIME);
if (mpAll == null || time == null) {
return Double.NaN;
}
@ -98,7 +98,7 @@ public class DampingMoment extends AbstractSimulationExtension {
mdot = (mpAll.get(len - 1) - mpAll.get(len - 2)) / (time.get(len - 1) - time.get(len - 2));
}
double cg = data.getLast(FlightDataType.TYPE_CG_LOCATION);
double cg = dataBranch.getLast(FlightDataType.TYPE_CG_LOCATION);
// find the maximum distance from nose to nozzle.
double nozzleDistance = 0;

View File

@ -37,17 +37,17 @@ public class PrintSimulation extends AbstractSimulationExtension {
@Override
public void postStep(SimulationStatus status) throws SimulationException {
FlightDataBranch data = status.getFlightData();
FlightDataBranch dataBranch = status.getFlightDataBranch();
System.out.printf("*** stepTaken *** time=%.3f position=" + status.getRocketPosition() +
" velocity=" + status.getRocketVelocity() + "=%.3f\n", status.getSimulationTime(),
status.getRocketVelocity().length());
System.out.printf(" thrust=%.3fN drag==%.3fN mass=%.3fkg " +
"accZ=%.3fm/s2 acc=%.3fm/s2\n",
data.getLast(FlightDataType.TYPE_THRUST_FORCE),
data.getLast(FlightDataType.TYPE_DRAG_FORCE),
data.getLast(FlightDataType.TYPE_MASS),
data.getLast(FlightDataType.TYPE_ACCELERATION_Z),
data.getLast(FlightDataType.TYPE_ACCELERATION_TOTAL));
dataBranch.getLast(FlightDataType.TYPE_THRUST_FORCE),
dataBranch.getLast(FlightDataType.TYPE_DRAG_FORCE),
dataBranch.getLast(FlightDataType.TYPE_MASS),
dataBranch.getLast(FlightDataType.TYPE_ACCELERATION_Z),
dataBranch.getLast(FlightDataType.TYPE_ACCELERATION_TOTAL));
}
}

View File

@ -198,7 +198,7 @@ public class RollControl extends AbstractSimulationExtension {
// Set the control fin cant and store the data
finset.setCantAngle(finPosition);
status.getFlightData().setValue(FIN_CANT_TYPE, finPosition);
status.getFlightDataBranch().setValue(FIN_CANT_TYPE, finPosition);
}
@Override

View File

@ -216,13 +216,13 @@ public class SimulationPlot {
if (thisBranch.getLength() == 0) {
// Add an empty series to keep the series count consistent
XYSeries series = new XYSeries(seriesCount++, false, true);
series.setDescription(thisBranch.getBranchName() + ": " + name);
series.setDescription(thisBranch.getName() + ": " + name);
data[axis].addSeries(series);
continue;
}
XYSeries series = new XYSeries(seriesCount++, false, true);
series.setDescription(thisBranch.getBranchName() + ": " + name);
series.setDescription(thisBranch.getName() + ": " + name);
// Copy all the data from the secondary branch
List<Double> plotx = thisBranch.get(domainType);
@ -848,7 +848,7 @@ public class SimulationPlot {
abortString = new StringBuilder(trans.get("simulationplot.abort.title"));
}
abortString.append("\n")
.append(trans.get("simulationplot.abort.stage")).append(": ").append(branch.getBranchName()).append("; ")
.append(trans.get("simulationplot.abort.stage")).append(": ").append(branch.getName()).append("; ")
.append(trans.get("simulationplot.abort.time")).append(": ").append(abortEvent.getTime()).append(" s; ")
.append(trans.get("simulationplot.abort.cause")).append(": ").append(((SimulationAbort) abortEvent.getData()).getMessageDescription());
}

View File

@ -28,7 +28,7 @@ public abstract class Util {
// on the stage name there is no guarantee they are unique. In order to address this, we first assume
// all the names are unique, then go through them looking for duplicates.
for (int i = 0; i < simulation.getSimulatedData().getBranchCount(); i++) {
stages.add(simulation.getSimulatedData().getBranch(i).getBranchName());
stages.add(simulation.getSimulatedData().getBranch(i).getName());
}
// check for duplicates:
for( int i = 0; i< stages.size(); i++ ) {

View File

@ -36,6 +36,7 @@ import info.openrocket.core.simulation.FlightEvent;
import info.openrocket.core.simulation.SimulationStatus;
import info.openrocket.core.simulation.customexpression.CustomExpression;
import info.openrocket.core.simulation.customexpression.CustomExpressionSimulationListener;
import info.openrocket.core.simulation.exception.SimulationCalculationException;
import info.openrocket.core.simulation.exception.SimulationCancelledException;
import info.openrocket.core.simulation.exception.SimulationException;
import info.openrocket.core.simulation.listeners.AbstractSimulationListener;
@ -426,14 +427,16 @@ public class SimulationRunDialog extends JDialog {
// Analyze the exception type
if (t instanceof SimulationException) {
String title = simulation.getName();
FlightDataBranch dataBranch = ((SimulationException) t).getFlightDataBranch();
FlightDataBranch dataBranch = null;
if (t instanceof SimulationCalculationException) {
dataBranch = ((SimulationCalculationException) t).getFlightDataBranch();
}
String message;
if (dataBranch != null) {
message = trans.get("SimuRunDlg.msg.branchErrorOccurred") + "\"" + dataBranch.getBranchName() + "\"";
message = trans.get("SimuRunDlg.msg.branchErrorOccurred") + " \"" + dataBranch.getName() + "\"";
} else {
message = trans.get("SimuRunDlg.msg.errorOccurred");
}
}
DetailDialog.showDetailedMessageDialog(SimulationRunDialog.this,
new Object[] {
//// A error occurred during the simulation: