optimization.modifier.ellipticalfinset.length = Root chord
optimization.modifier.ellipticalfinset.length.desc = Optimize the root chord length of the fin set.
optimization.modifier.ellipticalfinset.height = Height
-optimization.modifier.ellipticalfinset.height = Optimize the height (semi-span) of the fin set.
+optimization.modifier.ellipticalfinset.height.desc = Optimize the height (semi-span) of the fin set.
optimization.modifier.finset.cant = Cant angle
optimization.modifier.finset.cant.desc = Optimize the cant angle of the fin set.
OptimizationPlotDialog.plot2d.path = Optimization path
OptimizationPlotDialog.plot2d.evals = Evaluations
OptimizationPlotDialog.plot.ttip.stability = Stability:
+OptimizationPlotDialog.plot.label.optimum = Optimum
! Optimization parameters
MaximumAltitudeParameter.name = Apogee altitude
total.setCm(total.getCm() - total.getPitchDampingMoment());
total.setCyaw(total.getCyaw() - total.getYawDampingMoment());
+
return total;
}
double yaw = conditions.getYawRate();
double vel = conditions.getVelocity();
+ vel = MathUtil.max(vel, 1);
+
// double Cm = total.Cm - total.CN * total.cg.x / conditions.getRefLength();
// System.out.printf("Damping pitch/yaw, mul=%.4f pitch rate=%.4f "+
// "Cm=%.4f / %.4f effect=%.4f aoa=%.4f\n", mul, pitch, total.Cm, Cm,
// total.Cyaw -= mul * yaw / pow2(vel);
total.setPitchDampingMoment(mul * MathUtil.sign(pitch) * pow2(pitch / vel));
total.setYawDampingMoment(mul * MathUtil.sign(yaw) * pow2(yaw / vel));
-
}
// TODO: MEDIUM: Are the rotation etc. being added correctly? sin/cos theta?
import javax.swing.JTable;
import javax.swing.JToggleButton;
import javax.swing.ListSelectionModel;
+import javax.swing.Timer;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import com.itextpdf.text.Font;
-// FIXME: Override to zero mass produces NaN in simulation
/**
* General rocket optimization dialog.
worker = null;
stopOptimization();
+
+ // Disable the start/stop button for a short while after ending the simulation
+ // to prevent accidentally starting a new optimization when trying to stop it
+ startButton.setEnabled(false);
+ Timer timer = new Timer(750, new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ startButton.setEnabled(true);
+ }
+ });
+ timer.setRepeats(false);
+ timer.start();
}
@Override
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
+import org.jfree.chart.annotations.XYBoxAnnotation;
+import org.jfree.chart.annotations.XYLineAnnotation;
+import org.jfree.chart.annotations.XYPointerAnnotation;
import org.jfree.chart.axis.AxisLocation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.labels.CustomXYToolTipGenerator;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RectangleEdge;
+import org.jfree.ui.TextAnchor;
/**
* A class that plots the path of an optimization.
private static final LogHelper log = Application.getLogger();
private static final Translator trans = Application.getTranslator();
- // FIXME: Set range to optimization range
-
+
private static final LinearInterpolator RED = new LinearInterpolator(
new double[] { 0.0, 1.0 }, new double[] { 0.0, 1.0 }
);
false); // Urls
+ // Set the scale of the plot to the limits
+ double x1 = xUnit.toUnit(modX.getMinValue());
+ double x2 = xUnit.toUnit(modX.getMaxValue());
+
+ chart.getXYPlot().getDomainAxis().setRange(x1, x2);
+
+ // Add lines to show optimization limits
+ XYLineAnnotation line = new XYLineAnnotation(x1, -1e19, x1, 1e19);
+ chart.getXYPlot().addAnnotation(line);
+ line = new XYLineAnnotation(x2, -1e19, x2, 1e19);
+ chart.getXYPlot().addAnnotation(line);
+
+ // Mark the optimum point
+ Point optimum = path.get(path.size() - 1);
+ FunctionEvaluationData data = evaluations.get(optimum);
+ if (data != null) {
+ if (data.getParameterValue() != null) {
+ Value[] state = data.getState();
+ double x = xUnit.toUnit(state[0].getValue());
+ double y = yUnit.toUnit(data.getParameterValue().getValue());
+
+ XYPointerAnnotation text = new XYPointerAnnotation(trans.get("plot.label.optimum"),
+ x, y, Math.PI / 2);
+ text.setTextAnchor(TextAnchor.TOP_LEFT);
+ chart.getXYPlot().addAnnotation(text);
+ }
+ } else {
+ log.error("Could not find evaluation data for point " + optimum);
+ }
+
+
XYLineAndShapeRenderer lineRenderer = new XYLineAndShapeRenderer(true, true);
lineRenderer.setBaseShapesVisible(true);
lineRenderer.setSeriesShapesFilled(0, false);
Unit yUnit = modY.getUnitGroup().getDefaultUnit();
// Create the optimization path dataset
- XYSeries series = new XYSeries(trans.get("plot2d.path"), false, true);
+ XYSeries pathSeries = new XYSeries(trans.get("plot2d.path"), false, true);
List<String> pathTooltips = new ArrayList<String>();
for (Point p : path) {
FunctionEvaluationData data = evaluations.get(p);
if (data != null) {
Value[] state = data.getState();
- series.add(xUnit.toUnit(state[0].getValue()), yUnit.toUnit(state[1].getValue()));
+ pathSeries.add(xUnit.toUnit(state[0].getValue()), yUnit.toUnit(state[1].getValue()));
pathTooltips.add(getTooltip(data, parameter));
} else {
log.error("Could not find evaluation data for point " + p);
false); // Urls
- chart.getXYPlot().getDomainAxis().setRange(xUnit.toUnit(modX.getMinValue()),
- xUnit.toUnit(modX.getMaxValue()));
+ // Set the scale of the plot to the limits
+ double x1 = xUnit.toUnit(modX.getMinValue());
+ double x2 = xUnit.toUnit(modX.getMaxValue());
+ double y1 = yUnit.toUnit(modY.getMinValue());
+ double y2 = yUnit.toUnit(modY.getMaxValue());
- chart.getXYPlot().getRangeAxis().setRange(yUnit.toUnit(modY.getMinValue()),
- yUnit.toUnit(modY.getMaxValue()));
+ chart.getXYPlot().getDomainAxis().setRange(x1, x2);
+ chart.getXYPlot().getRangeAxis().setRange(y1, y2);
+
+ XYBoxAnnotation box = new XYBoxAnnotation(x1, y1, x2, y2);
+ chart.getXYPlot().addAnnotation(box);
+
+ int n = pathSeries.getItemCount();
+ XYPointerAnnotation text = new XYPointerAnnotation(trans.get("plot.label.optimum"),
+ (Double) pathSeries.getX(n - 1), (Double) pathSeries.getY(n - 1), -Math.PI / 5);
+ text.setTextAnchor(TextAnchor.BASELINE_LEFT);
+ chart.getXYPlot().addAnnotation(text);
-
PaintScale paintScale = new GradientScale(min, max);
XYShapeRenderer shapeRenderer = new XYShapeRenderer();
XYPlot plot = chart.getXYPlot();
- plot.setDataset(0, new XYSeriesCollection(series));
+ plot.setDataset(0, new XYSeriesCollection(pathSeries));
plot.setRenderer(lineRenderer);
plot.setDataset(1, evalDataset);
* @param message the error message.
* @param exception the exception that occurred.
*/
- public static void handleErrorCondition(String message, Exception exception) {
+ public static void handleErrorCondition(String message, Throwable exception) {
log.error(1, message, exception);
handleErrorCondition(new InternalException(message, exception));
}
*
* @param exception the exception that occurred.
*/
- public static void handleErrorCondition(final Exception exception) {
+ public static void handleErrorCondition(final Throwable exception) {
try {
if (!(exception instanceof InternalException)) {
log.error(1, "Error occurred", exception);
},
stackTrace, simulation.getName(), JOptionPane.ERROR_MESSAGE);
- } else if (t instanceof Exception) {
-
- // TODO: MEDIUM: Check the exception handling here...
- t.printStackTrace();
- DetailDialog.showDetailedMessageDialog(SimulationRunDialog.this,
- new Object[] {
- //// An exception occurred during the simulation:
- trans.get("SimuRunDlg.msg.AnException1"),
- t.getMessage(),
- simulation.getSimulationListeners().isEmpty() ?
- trans.get("SimuRunDlg.msg.AnException2") : ""
- },
- stackTrace, simulation.getName(), JOptionPane.ERROR_MESSAGE);
-
- } else if (t instanceof AssertionError) {
-
- t.printStackTrace();
- DetailDialog.showDetailedMessageDialog(SimulationRunDialog.this,
- new Object[] {
- //// A computation error occurred during the simulation.
- trans.get("SimuRunDlg.msg.AssertionError1"),
- //// Please report this as a bug along with the details below.
- trans.get("SimuRunDlg.msg.AssertionError2")
- },
- stackTrace, simulation.getName(), JOptionPane.ERROR_MESSAGE);
-
} else {
- // Probably an Error
- DetailDialog.showDetailedMessageDialog(SimulationRunDialog.this,
- new Object[] {
- //// An unknown error was encountered during the simulation.
- trans.get("SimuRunDlg.msg.unknownerror1"),
- //// The program may be unstable, you should save all your designs and restart OpenRocket now!
- trans.get("SimuRunDlg.msg.unknownerror2")
- },
- stackTrace, simulation.getName(), JOptionPane.ERROR_MESSAGE);
+ ExceptionHandler.handleErrorCondition("An exception occurred during the simulation", t);
}
simulationDone();
}
-
private void setSimulationProgress(double p) {
int exact = Math.max(progress, (int) (100 * p + 0.5));
progress = MathUtil.clamp(exact, 0, 100);
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
import net.sf.openrocket.simulation.FlightData;
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
+import net.sf.openrocket.simulation.exception.SimulationCalculationException;
import net.sf.openrocket.simulation.exception.SimulationCancelledException;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
} catch (SimulationLaunchException e) {
// Other launch exceptions result in illegal value
return Double.NaN;
+ } catch (SimulationCalculationException e) {
+ // Calculation errors result in illegal value
+ return Double.NaN;
} catch (SimulationCancelledException e) {
// Simulation cancellation stops the optimization
throw (InterruptedException) new InterruptedException("Optimization was interrupted").initCause(e);
*/
protected void checkNaN(Coordinate c) {
if (c.isNaN()) {
- throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug.");
+ throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug, c=" + c);
}
}
*/
protected void checkNaN(Quaternion q) {
if (q.isNaN()) {
- throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug.");
+ throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug, q=" + q);
}
}
}
import net.sf.openrocket.aerodynamics.WarningSet;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
+import net.sf.openrocket.simulation.exception.SimulationCalculationException;
import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.simulation.listeners.SimulationListenerHelper;
import net.sf.openrocket.startup.Application;
status.setSimulationTime(status.getSimulationTime() + store.timestep);
status.setPreviousTimeStep(store.timestep);
+
+ // Verify that values don't run out of range
+ if (status.getRocketVelocity().length2() > 1e18 ||
+ status.getRocketPosition().length2() > 1e18 ||
+ status.getRocketRotationVelocity().length2() > 1e18) {
+ throw new SimulationCalculationException("Simulation values exceeded limits");
+ }
}
// Compute acceleration in rocket coordinates
store.angularAcceleration = new Coordinate(momX / store.massData.getLongitudinalInertia(),
- momY / store.massData.getLongitudinalInertia(), momZ / store.massData.getRotationalInertia());
+ momY / store.massData.getLongitudinalInertia(),
+ momZ / store.massData.getRotationalInertia());
store.rollAcceleration = store.angularAcceleration.z;
// TODO: LOW: This should be hypot, but does it matter?
--- /dev/null
+package net.sf.openrocket.simulation.exception;
+
+/**
+ * An exception that indicates that a computation problem has occurred during
+ * the simulation, for example that some values have exceed reasonable bounds.
+ *
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class SimulationCalculationException extends SimulationException {
+
+ public SimulationCalculationException() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public SimulationCalculationException(String message) {
+ super(message);
+ // TODO Auto-generated constructor stub
+ }
+
+ public SimulationCalculationException(Throwable cause) {
+ super(cause);
+ // TODO Auto-generated constructor stub
+ }
+
+ public SimulationCalculationException(String message, Throwable cause) {
+ super(message, cause);
+ // TODO Auto-generated constructor stub
+ }
+
+}