optimization updates
This commit is contained in:
parent
9a8e702df2
commit
2639d13391
@ -1,3 +1,8 @@
|
|||||||
|
2011-08-08 Sampo Niskanen
|
||||||
|
|
||||||
|
* Enhanced one-dimensional optimization algorithm
|
||||||
|
* [BUG] l10n/ directory not included in source distribution
|
||||||
|
|
||||||
2011-08-07 Sampo Niskanen
|
2011-08-07 Sampo Niskanen
|
||||||
|
|
||||||
* Optimization implementation
|
* Optimization implementation
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
<fileset dir="." includes="*">
|
<fileset dir="." includes="*">
|
||||||
<type type="file"/>
|
<type type="file"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
<fileset dir="." includes="datafiles/ lib/ lib-test/ pix/ src/ test/"/>
|
<fileset dir="." includes="datafiles/ lib/ lib-test/ pix/ src/ test/ l10n/"/>
|
||||||
</copy>
|
</copy>
|
||||||
<zip destfile="${dist.src}" basedir="${build.dir}" includes="${pkgname}/"/>
|
<zip destfile="${dist.src}" basedir="${build.dir}" includes="${pkgname}/"/>
|
||||||
<delete dir="${build.dir}/${pkgname}"/>
|
<delete dir="${build.dir}/${pkgname}"/>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.sf.openrocket.gui.components;
|
package net.sf.openrocket.gui.components;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.text.ParseException;
|
||||||
|
|
||||||
import javax.swing.AbstractCellEditor;
|
import javax.swing.AbstractCellEditor;
|
||||||
import javax.swing.JSpinner;
|
import javax.swing.JSpinner;
|
||||||
@ -34,6 +35,17 @@ public class DoubleCellEditor extends AbstractCellEditor implements TableCellEdi
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stopCellEditing() {
|
||||||
|
try {
|
||||||
|
editor.commitEdit();
|
||||||
|
} catch (ParseException e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
return super.stopCellEditing();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getCellEditorValue() {
|
public Object getCellEditorValue() {
|
||||||
return model.getValue();
|
return model.getValue();
|
||||||
|
@ -95,6 +95,8 @@ import net.sf.openrocket.util.TextUtil;
|
|||||||
|
|
||||||
import com.itextpdf.text.Font;
|
import com.itextpdf.text.Font;
|
||||||
|
|
||||||
|
// FIXME: Override to zero mass produces NaN in simulation
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* General rocket optimization dialog.
|
* General rocket optimization dialog.
|
||||||
*
|
*
|
||||||
@ -937,7 +939,10 @@ public class GeneralOptimizationDialog extends JDialog {
|
|||||||
if (newModifiers != null) {
|
if (newModifiers != null) {
|
||||||
int index = newModifiers.indexOf(original);
|
int index = newModifiers.indexOf(original);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
newSelected.add(newModifiers.get(index));
|
SimulationModifier updated = newModifiers.get(index);
|
||||||
|
updated.setMinValue(original.getMinValue());
|
||||||
|
updated.setMaxValue(original.getMaxValue());
|
||||||
|
newSelected.add(updated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import net.sf.openrocket.optimization.general.ParallelExecutorCache;
|
|||||||
import net.sf.openrocket.optimization.general.ParallelFunctionCache;
|
import net.sf.openrocket.optimization.general.ParallelFunctionCache;
|
||||||
import net.sf.openrocket.optimization.general.Point;
|
import net.sf.openrocket.optimization.general.Point;
|
||||||
import net.sf.openrocket.optimization.general.multidim.MultidirectionalSearchOptimizer;
|
import net.sf.openrocket.optimization.general.multidim.MultidirectionalSearchOptimizer;
|
||||||
|
import net.sf.openrocket.optimization.general.onedim.GoldenSectionSearchOptimizer;
|
||||||
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
||||||
import net.sf.openrocket.optimization.rocketoptimization.OptimizationGoal;
|
import net.sf.openrocket.optimization.rocketoptimization.OptimizationGoal;
|
||||||
import net.sf.openrocket.optimization.rocketoptimization.RocketOptimizationFunction;
|
import net.sf.openrocket.optimization.rocketoptimization.RocketOptimizationFunction;
|
||||||
@ -90,7 +91,11 @@ public abstract class OptimizationWorker extends Thread implements OptimizationC
|
|||||||
cache = new ParallelExecutorCache(1);
|
cache = new ParallelExecutorCache(1);
|
||||||
cache.setFunction(function);
|
cache.setFunction(function);
|
||||||
|
|
||||||
optimizer = new MultidirectionalSearchOptimizer(cache);
|
if (modifiers.length == 1) {
|
||||||
|
optimizer = new GoldenSectionSearchOptimizer(cache);
|
||||||
|
} else {
|
||||||
|
optimizer = new MultidirectionalSearchOptimizer(cache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package net.sf.openrocket.optimization.general;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
@ -201,6 +202,30 @@ public class ParallelExecutorCache implements ParallelFunctionCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void abortAll() {
|
||||||
|
Iterator<Point> iterator = futureMap.keySet().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Point point = iterator.next();
|
||||||
|
Future<Double> future = futureMap.get(point);
|
||||||
|
iterator.remove();
|
||||||
|
|
||||||
|
if (future.isDone()) {
|
||||||
|
// Evaluation has been completed, store value in cache
|
||||||
|
try {
|
||||||
|
double value = future.get();
|
||||||
|
functionCache.put(point, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Cancel the evaluation
|
||||||
|
future.cancel(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getValue(Point point) {
|
public double getValue(Point point) {
|
||||||
if (isOutsideRange(point)) {
|
if (isOutsideRange(point)) {
|
||||||
@ -274,4 +299,5 @@ public class ParallelExecutorCache implements ParallelFunctionCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -68,4 +68,10 @@ public interface ParallelFunctionCache extends FunctionCache {
|
|||||||
* @return <code>true</code> if the point has been computed anyway, <code>false</code> if not.
|
* @return <code>true</code> if the point has been computed anyway, <code>false</code> if not.
|
||||||
*/
|
*/
|
||||||
public boolean abort(Point point);
|
public boolean abort(Point point);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abort the computation of all still unexecuted points.
|
||||||
|
*/
|
||||||
|
public void abortAll();
|
||||||
}
|
}
|
||||||
|
@ -215,6 +215,7 @@ public class MultidirectionalSearchOptimizer implements FunctionOptimizer, Stati
|
|||||||
|
|
||||||
log.info("Finishing optimization at point " + simplex.get(0) + " value = " +
|
log.info("Finishing optimization at point " + simplex.get(0) + " value = " +
|
||||||
functionExecutor.getValue(simplex.get(0)));
|
functionExecutor.getValue(simplex.get(0)));
|
||||||
|
log.info("Optimization statistics: " + getStatistics());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,275 @@
|
|||||||
|
package net.sf.openrocket.optimization.general.onedim;
|
||||||
|
|
||||||
|
import net.sf.openrocket.logging.LogHelper;
|
||||||
|
import net.sf.openrocket.optimization.general.FunctionCache;
|
||||||
|
import net.sf.openrocket.optimization.general.FunctionOptimizer;
|
||||||
|
import net.sf.openrocket.optimization.general.OptimizationController;
|
||||||
|
import net.sf.openrocket.optimization.general.OptimizationException;
|
||||||
|
import net.sf.openrocket.optimization.general.ParallelFunctionCache;
|
||||||
|
import net.sf.openrocket.optimization.general.Point;
|
||||||
|
import net.sf.openrocket.startup.Application;
|
||||||
|
import net.sf.openrocket.util.MathUtil;
|
||||||
|
import net.sf.openrocket.util.Statistics;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of a one-dimensional golden section search method
|
||||||
|
* (see e.g. Nonlinear programming, Bazaraa, Sherall, Shetty, 2nd edition, p. 270)
|
||||||
|
* <p>
|
||||||
|
* This implementation attempts to guess future evaluations and computes them in parallel
|
||||||
|
* with the next point.
|
||||||
|
* <p>
|
||||||
|
* The optimization can be aborted by interrupting the current thread.
|
||||||
|
*/
|
||||||
|
public class GoldenSectionSearchOptimizer implements FunctionOptimizer, Statistics {
|
||||||
|
private static final LogHelper log = Application.getLogger();
|
||||||
|
|
||||||
|
private static final double ALPHA = (Math.sqrt(5) - 1) / 2.0;
|
||||||
|
|
||||||
|
|
||||||
|
private ParallelFunctionCache functionExecutor;
|
||||||
|
|
||||||
|
private Point current = null;
|
||||||
|
|
||||||
|
private int guessSuccess = 0;
|
||||||
|
private int guessFailure = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an optimizer with no function executor.
|
||||||
|
*/
|
||||||
|
public GoldenSectionSearchOptimizer() {
|
||||||
|
// No-op
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an optimizer.
|
||||||
|
*
|
||||||
|
* @param functionExecutor the function executor.
|
||||||
|
*/
|
||||||
|
public GoldenSectionSearchOptimizer(ParallelFunctionCache functionExecutor) {
|
||||||
|
super();
|
||||||
|
this.functionExecutor = functionExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void optimize(Point initial, OptimizationController control) throws OptimizationException {
|
||||||
|
|
||||||
|
if (initial.dim() != 1) {
|
||||||
|
throw new IllegalArgumentException("Only single-dimensional optimization supported, dim=" +
|
||||||
|
initial.dim());
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Starting golden section search for optimization");
|
||||||
|
|
||||||
|
Point guessAC = null;
|
||||||
|
Point guessBD = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
boolean guessedAC;
|
||||||
|
|
||||||
|
Point previous = p(0);
|
||||||
|
double previousValue = Double.NaN;
|
||||||
|
current = previous;
|
||||||
|
double currentValue = Double.NaN;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the points + computation.
|
||||||
|
*/
|
||||||
|
Point a = p(0);
|
||||||
|
Point d = p(1.0);
|
||||||
|
Point b = section1(a, d);
|
||||||
|
Point c = section2(a, d);
|
||||||
|
|
||||||
|
functionExecutor.compute(a);
|
||||||
|
functionExecutor.compute(d);
|
||||||
|
functionExecutor.compute(b);
|
||||||
|
functionExecutor.compute(c);
|
||||||
|
|
||||||
|
// Wait for points a and d, which normally are already precomputed
|
||||||
|
functionExecutor.waitFor(a);
|
||||||
|
functionExecutor.waitFor(d);
|
||||||
|
|
||||||
|
boolean continueOptimization = true;
|
||||||
|
while (continueOptimization) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get values at A & D for guessing.
|
||||||
|
* These are pre-calculated except during the first step.
|
||||||
|
*/
|
||||||
|
double fa, fd;
|
||||||
|
fa = functionExecutor.getValue(a);
|
||||||
|
fd = functionExecutor.getValue(d);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start calculating possible two next points. The order of evaluation
|
||||||
|
* is selected based on the function values at A and D.
|
||||||
|
*/
|
||||||
|
guessAC = section1(a, c);
|
||||||
|
guessBD = section2(b, d);
|
||||||
|
System.err.println("Queueing " + guessAC + " and " + guessBD);
|
||||||
|
if (Double.isNaN(fd) || fa < fd) {
|
||||||
|
guessedAC = true;
|
||||||
|
functionExecutor.compute(guessAC);
|
||||||
|
functionExecutor.compute(guessBD);
|
||||||
|
} else {
|
||||||
|
guessedAC = false;
|
||||||
|
functionExecutor.compute(guessBD);
|
||||||
|
functionExecutor.compute(guessAC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get values at B and C.
|
||||||
|
*/
|
||||||
|
double fb, fc;
|
||||||
|
functionExecutor.waitFor(b);
|
||||||
|
functionExecutor.waitFor(c);
|
||||||
|
fb = functionExecutor.getValue(b);
|
||||||
|
fc = functionExecutor.getValue(c);
|
||||||
|
|
||||||
|
double min = MathUtil.min(fa, fb, fc, fd);
|
||||||
|
if (Double.isNaN(min)) {
|
||||||
|
throw new OptimizationException("Unable to compute initial function values");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update previous and current values for step control.
|
||||||
|
*/
|
||||||
|
previousValue = currentValue;
|
||||||
|
currentValue = min;
|
||||||
|
previous = current;
|
||||||
|
if (min == fa) {
|
||||||
|
current = a;
|
||||||
|
} else if (min == fb) {
|
||||||
|
current = b;
|
||||||
|
} else if (min == fc) {
|
||||||
|
current = c;
|
||||||
|
} else {
|
||||||
|
current = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Select next positions. These are already being calculated in the background
|
||||||
|
* as guessAC and guessBD.
|
||||||
|
*/
|
||||||
|
if (min == fa || min == fb) {
|
||||||
|
d = c;
|
||||||
|
c = b;
|
||||||
|
b = guessAC;
|
||||||
|
functionExecutor.abort(guessBD);
|
||||||
|
guessBD = null;
|
||||||
|
log.debug("Selecting A-C region, a=" + a.get(0) + " c=" + c.get(0));
|
||||||
|
if (guessedAC) {
|
||||||
|
guessSuccess++;
|
||||||
|
} else {
|
||||||
|
guessFailure++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
a = b;
|
||||||
|
b = c;
|
||||||
|
c = guessBD;
|
||||||
|
functionExecutor.abort(guessAC);
|
||||||
|
guessAC = null;
|
||||||
|
log.debug("Selecting B-D region, b=" + b.get(0) + " d=" + d.get(0));
|
||||||
|
if (!guessedAC) {
|
||||||
|
guessSuccess++;
|
||||||
|
} else {
|
||||||
|
guessFailure++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check optimization control.
|
||||||
|
*/
|
||||||
|
continueOptimization = control.stepTaken(previous, previousValue,
|
||||||
|
current, currentValue, c.get(0) - a.get(0));
|
||||||
|
|
||||||
|
if (Thread.interrupted()) {
|
||||||
|
throw new InterruptedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.info("Optimization was interrupted with InterruptedException");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (guessAC != null) {
|
||||||
|
System.err.println("Aborting " + guessAC);
|
||||||
|
functionExecutor.abort(guessAC);
|
||||||
|
}
|
||||||
|
if (guessBD != null) {
|
||||||
|
System.err.println("Aborting " + guessBD);
|
||||||
|
functionExecutor.abort(guessBD);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
log.info("Finishing optimization at point " + getOptimumPoint() + " value " + getOptimumValue());
|
||||||
|
log.info("Optimization statistics: " + getStatistics());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Point p(double v) {
|
||||||
|
return new Point(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Point section1(Point a, Point b) {
|
||||||
|
double va = a.get(0);
|
||||||
|
double vb = b.get(0);
|
||||||
|
return p(va + (1 - ALPHA) * (vb - va));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Point section2(Point a, Point b) {
|
||||||
|
double va = a.get(0);
|
||||||
|
double vb = b.get(0);
|
||||||
|
return p(va + ALPHA * (vb - va));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Point getOptimumPoint() {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getOptimumValue() {
|
||||||
|
if (getOptimumPoint() == null) {
|
||||||
|
return Double.NaN;
|
||||||
|
}
|
||||||
|
return functionExecutor.getValue(getOptimumPoint());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FunctionCache getFunctionCache() {
|
||||||
|
return functionExecutor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFunctionCache(FunctionCache functionCache) {
|
||||||
|
if (!(functionCache instanceof ParallelFunctionCache)) {
|
||||||
|
throw new IllegalArgumentException("Function cache needs to be a ParallelFunctionCache: " + functionCache);
|
||||||
|
}
|
||||||
|
this.functionExecutor = (ParallelFunctionCache) functionCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getStatistics() {
|
||||||
|
return String.format("Guess hit rate %d/%d = %.3f", guessSuccess, guessSuccess + guessFailure,
|
||||||
|
((double) guessSuccess) / (guessSuccess + guessFailure));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetStatistics() {
|
||||||
|
guessSuccess = 0;
|
||||||
|
guessFailure = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -29,7 +29,7 @@ public interface OptimizableParameter {
|
|||||||
* @return the parameter value (any double value)
|
* @return the parameter value (any double value)
|
||||||
* @throws OptimizationException if an error occurs preventing the optimization from continuing
|
* @throws OptimizationException if an error occurs preventing the optimization from continuing
|
||||||
*/
|
*/
|
||||||
public double computeValue(Simulation simulation) throws OptimizationException;
|
public double computeValue(Simulation simulation) throws OptimizationException, InterruptedException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,8 +7,10 @@ import net.sf.openrocket.optimization.general.OptimizationException;
|
|||||||
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
||||||
import net.sf.openrocket.simulation.FlightDataType;
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
||||||
|
import net.sf.openrocket.simulation.exception.SimulationCancelledException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
||||||
|
import net.sf.openrocket.simulation.listeners.system.InterruptListener;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
|
|
||||||
@ -28,10 +30,10 @@ public class GroundHitVelocityParameter implements OptimizableParameter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double computeValue(Simulation simulation) throws OptimizationException {
|
public double computeValue(Simulation simulation) throws OptimizationException, InterruptedException {
|
||||||
try {
|
try {
|
||||||
log.debug("Running simulation to evaluate ground hit speed");
|
log.debug("Running simulation to evaluate ground hit speed");
|
||||||
simulation.simulate();
|
simulation.simulate(new InterruptListener());
|
||||||
double value = simulation.getSimulatedData().getBranch(0).getLast(FlightDataType.TYPE_VELOCITY_TOTAL);
|
double value = simulation.getSimulatedData().getBranch(0).getLast(FlightDataType.TYPE_VELOCITY_TOTAL);
|
||||||
log.debug("Ground hit speed was " + value);
|
log.debug("Ground hit speed was " + value);
|
||||||
return value;
|
return value;
|
||||||
@ -41,6 +43,8 @@ public class GroundHitVelocityParameter implements OptimizableParameter {
|
|||||||
} catch (SimulationLaunchException e) {
|
} catch (SimulationLaunchException e) {
|
||||||
// Other launch exceptions result in zero altitude
|
// Other launch exceptions result in zero altitude
|
||||||
return Double.NaN;
|
return Double.NaN;
|
||||||
|
} catch (SimulationCancelledException e) {
|
||||||
|
throw (InterruptedException) new InterruptedException("Optimization was interrupted").initCause(e);
|
||||||
} catch (SimulationException e) {
|
} catch (SimulationException e) {
|
||||||
// Other exceptions fail
|
// Other exceptions fail
|
||||||
throw new OptimizationException(e);
|
throw new OptimizationException(e);
|
||||||
|
@ -7,8 +7,10 @@ import net.sf.openrocket.optimization.general.OptimizationException;
|
|||||||
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
||||||
import net.sf.openrocket.simulation.FlightDataType;
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
||||||
|
import net.sf.openrocket.simulation.exception.SimulationCancelledException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
||||||
|
import net.sf.openrocket.simulation.listeners.system.InterruptListener;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
|
|
||||||
@ -28,10 +30,10 @@ public class LandingDistanceParameter implements OptimizableParameter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double computeValue(Simulation simulation) throws OptimizationException {
|
public double computeValue(Simulation simulation) throws OptimizationException, InterruptedException {
|
||||||
try {
|
try {
|
||||||
log.debug("Running simulation to evaluate rocket landing distance");
|
log.debug("Running simulation to evaluate rocket landing distance");
|
||||||
simulation.simulate();
|
simulation.simulate(new InterruptListener());
|
||||||
double value = simulation.getSimulatedData().getBranch(0).getLast(FlightDataType.TYPE_POSITION_XY);
|
double value = simulation.getSimulatedData().getBranch(0).getLast(FlightDataType.TYPE_POSITION_XY);
|
||||||
log.debug("Landing distance was " + value);
|
log.debug("Landing distance was " + value);
|
||||||
return value;
|
return value;
|
||||||
@ -41,6 +43,8 @@ public class LandingDistanceParameter implements OptimizableParameter {
|
|||||||
} catch (SimulationLaunchException e) {
|
} catch (SimulationLaunchException e) {
|
||||||
// Other launch exceptions result in zero altitude
|
// Other launch exceptions result in zero altitude
|
||||||
return Double.NaN;
|
return Double.NaN;
|
||||||
|
} catch (SimulationCancelledException e) {
|
||||||
|
throw (InterruptedException) new InterruptedException("Optimization was interrupted").initCause(e);
|
||||||
} catch (SimulationException e) {
|
} catch (SimulationException e) {
|
||||||
// Other exceptions fail
|
// Other exceptions fail
|
||||||
throw new OptimizationException(e);
|
throw new OptimizationException(e);
|
||||||
|
@ -7,9 +7,11 @@ import net.sf.openrocket.optimization.general.OptimizationException;
|
|||||||
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
||||||
import net.sf.openrocket.simulation.FlightDataType;
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
||||||
|
import net.sf.openrocket.simulation.exception.SimulationCancelledException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
||||||
import net.sf.openrocket.simulation.listeners.system.ApogeeEndListener;
|
import net.sf.openrocket.simulation.listeners.system.ApogeeEndListener;
|
||||||
|
import net.sf.openrocket.simulation.listeners.system.InterruptListener;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
|
|
||||||
@ -29,10 +31,10 @@ public class MaximumAccelerationParameter implements OptimizableParameter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double computeValue(Simulation simulation) throws OptimizationException {
|
public double computeValue(Simulation simulation) throws OptimizationException, InterruptedException {
|
||||||
try {
|
try {
|
||||||
log.debug("Running simulation to evaluate maximum acceleration");
|
log.debug("Running simulation to evaluate maximum acceleration");
|
||||||
simulation.simulate(new ApogeeEndListener());
|
simulation.simulate(new ApogeeEndListener(), new InterruptListener());
|
||||||
double value = simulation.getSimulatedData().getBranch(0).getMaximum(FlightDataType.TYPE_ACCELERATION_TOTAL);
|
double value = simulation.getSimulatedData().getBranch(0).getMaximum(FlightDataType.TYPE_ACCELERATION_TOTAL);
|
||||||
log.debug("Maximum acceleration was " + value);
|
log.debug("Maximum acceleration was " + value);
|
||||||
return value;
|
return value;
|
||||||
@ -42,6 +44,8 @@ public class MaximumAccelerationParameter implements OptimizableParameter {
|
|||||||
} catch (SimulationLaunchException e) {
|
} catch (SimulationLaunchException e) {
|
||||||
// Other launch exceptions result in zero velocity
|
// Other launch exceptions result in zero velocity
|
||||||
return Double.NaN;
|
return Double.NaN;
|
||||||
|
} catch (SimulationCancelledException e) {
|
||||||
|
throw (InterruptedException) new InterruptedException("Optimization was interrupted").initCause(e);
|
||||||
} catch (SimulationException e) {
|
} catch (SimulationException e) {
|
||||||
// Other exceptions fail
|
// Other exceptions fail
|
||||||
throw new OptimizationException(e);
|
throw new OptimizationException(e);
|
||||||
|
@ -7,9 +7,11 @@ import net.sf.openrocket.optimization.general.OptimizationException;
|
|||||||
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
||||||
import net.sf.openrocket.simulation.FlightDataType;
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
||||||
|
import net.sf.openrocket.simulation.exception.SimulationCancelledException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
||||||
import net.sf.openrocket.simulation.listeners.system.ApogeeEndListener;
|
import net.sf.openrocket.simulation.listeners.system.ApogeeEndListener;
|
||||||
|
import net.sf.openrocket.simulation.listeners.system.InterruptListener;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
|
|
||||||
@ -29,10 +31,10 @@ public class MaximumAltitudeParameter implements OptimizableParameter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double computeValue(Simulation simulation) throws OptimizationException {
|
public double computeValue(Simulation simulation) throws OptimizationException, InterruptedException {
|
||||||
try {
|
try {
|
||||||
log.debug("Running simulation to evaluate apogee altitude");
|
log.debug("Running simulation to evaluate apogee altitude");
|
||||||
simulation.simulate(new ApogeeEndListener());
|
simulation.simulate(new ApogeeEndListener(), new InterruptListener());
|
||||||
log.debug("Maximum altitude was " + simulation.getSimulatedData().getBranch(0).getMaximum(FlightDataType.TYPE_ALTITUDE));
|
log.debug("Maximum altitude was " + simulation.getSimulatedData().getBranch(0).getMaximum(FlightDataType.TYPE_ALTITUDE));
|
||||||
return simulation.getSimulatedData().getBranch(0).getMaximum(FlightDataType.TYPE_ALTITUDE);
|
return simulation.getSimulatedData().getBranch(0).getMaximum(FlightDataType.TYPE_ALTITUDE);
|
||||||
} catch (MotorIgnitionException e) {
|
} catch (MotorIgnitionException e) {
|
||||||
@ -41,6 +43,8 @@ public class MaximumAltitudeParameter implements OptimizableParameter {
|
|||||||
} catch (SimulationLaunchException e) {
|
} catch (SimulationLaunchException e) {
|
||||||
// Other launch exceptions result in zero altitude
|
// Other launch exceptions result in zero altitude
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
} catch (SimulationCancelledException e) {
|
||||||
|
throw (InterruptedException) new InterruptedException("Optimization was interrupted").initCause(e);
|
||||||
} catch (SimulationException e) {
|
} catch (SimulationException e) {
|
||||||
// Other exceptions fail
|
// Other exceptions fail
|
||||||
throw new OptimizationException(e);
|
throw new OptimizationException(e);
|
||||||
|
@ -7,9 +7,11 @@ import net.sf.openrocket.optimization.general.OptimizationException;
|
|||||||
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
|
||||||
import net.sf.openrocket.simulation.FlightDataType;
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
import net.sf.openrocket.simulation.exception.MotorIgnitionException;
|
||||||
|
import net.sf.openrocket.simulation.exception.SimulationCancelledException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationException;
|
import net.sf.openrocket.simulation.exception.SimulationException;
|
||||||
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
import net.sf.openrocket.simulation.exception.SimulationLaunchException;
|
||||||
import net.sf.openrocket.simulation.listeners.system.ApogeeEndListener;
|
import net.sf.openrocket.simulation.listeners.system.ApogeeEndListener;
|
||||||
|
import net.sf.openrocket.simulation.listeners.system.InterruptListener;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.unit.UnitGroup;
|
import net.sf.openrocket.unit.UnitGroup;
|
||||||
|
|
||||||
@ -29,10 +31,10 @@ public class MaximumVelocityParameter implements OptimizableParameter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double computeValue(Simulation simulation) throws OptimizationException {
|
public double computeValue(Simulation simulation) throws OptimizationException, InterruptedException {
|
||||||
try {
|
try {
|
||||||
log.debug("Running simulation to evaluate maximum velocity");
|
log.debug("Running simulation to evaluate maximum velocity");
|
||||||
simulation.simulate(new ApogeeEndListener());
|
simulation.simulate(new ApogeeEndListener(), new InterruptListener());
|
||||||
double value = simulation.getSimulatedData().getBranch(0).getMaximum(FlightDataType.TYPE_VELOCITY_TOTAL);
|
double value = simulation.getSimulatedData().getBranch(0).getMaximum(FlightDataType.TYPE_VELOCITY_TOTAL);
|
||||||
log.debug("Maximum velocity was " + value);
|
log.debug("Maximum velocity was " + value);
|
||||||
return value;
|
return value;
|
||||||
@ -42,6 +44,8 @@ public class MaximumVelocityParameter implements OptimizableParameter {
|
|||||||
} catch (SimulationLaunchException e) {
|
} catch (SimulationLaunchException e) {
|
||||||
// Other launch exceptions result in zero velocity
|
// Other launch exceptions result in zero velocity
|
||||||
return Double.NaN;
|
return Double.NaN;
|
||||||
|
} catch (SimulationCancelledException e) {
|
||||||
|
throw (InterruptedException) new InterruptedException("Optimization was interrupted").initCause(e);
|
||||||
} catch (SimulationException e) {
|
} catch (SimulationException e) {
|
||||||
// Other exceptions fail
|
// Other exceptions fail
|
||||||
throw new OptimizationException(e);
|
throw new OptimizationException(e);
|
||||||
|
@ -152,6 +152,18 @@ public class MathUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the minimum of three values. This is performed by direct comparison.
|
||||||
|
* However, if one of the values is NaN and the other is not, the non-NaN value is
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
public static double min(double w, double x, double y, double z) {
|
||||||
|
return min(min(w, x), min(y, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the maximum of three values. This is performed by direct comparison.
|
* Compute the maximum of three values. This is performed by direct comparison.
|
||||||
* However, if one of the values is NaN and the other is not, the non-NaN value is
|
* However, if one of the values is NaN and the other is not, the non-NaN value is
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
package net.sf.openrocket.l10n;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.MissingResourceException;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class TestResourceBundleTranslator {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSuccessfulUS() {
|
||||||
|
ResourceBundleTranslator trans = new ResourceBundleTranslator("l10n.messages", Locale.US);
|
||||||
|
assertEquals("messages.properties", trans.get("debug.currentFile"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSuccessfulFR() {
|
||||||
|
ResourceBundleTranslator trans = new ResourceBundleTranslator("l10n.messages", Locale.FRENCH);
|
||||||
|
assertEquals("messages_fr.properties", trans.get("debug.currentFile"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFailure() {
|
||||||
|
ResourceBundleTranslator trans = new ResourceBundleTranslator("l10n.messages", Locale.US);
|
||||||
|
try {
|
||||||
|
fail("Returned: " + trans.get("missing"));
|
||||||
|
} catch (MissingResourceException e) {
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -98,6 +98,16 @@ public class MathUtilTest {
|
|||||||
assertEquals(2.0, MathUtil.max(2.0, NaN, 1.0), 0);
|
assertEquals(2.0, MathUtil.max(2.0, NaN, 1.0), 0);
|
||||||
assertEquals(2.0, MathUtil.max(1.0, 2.0, NaN), 0);
|
assertEquals(2.0, MathUtil.max(1.0, 2.0, NaN), 0);
|
||||||
assertEquals(2.0, MathUtil.max(NaN, 2.0, 1.0), 0);
|
assertEquals(2.0, MathUtil.max(NaN, 2.0, 1.0), 0);
|
||||||
|
|
||||||
|
assertEquals(1.0, MathUtil.min(1.0, 2.0, 3.0, 4.0), 0);
|
||||||
|
assertEquals(1.0, MathUtil.min(1.0, NaN, NaN, NaN), 0);
|
||||||
|
assertEquals(1.0, MathUtil.min(NaN, 1.0, NaN, NaN), 0);
|
||||||
|
assertEquals(1.0, MathUtil.min(NaN, NaN, 1.0, NaN), 0);
|
||||||
|
assertEquals(1.0, MathUtil.min(2.0, NaN, 1.0, NaN), 0);
|
||||||
|
assertEquals(1.0, MathUtil.min(2.0, NaN, NaN, 1.0), 0);
|
||||||
|
assertEquals(1.0, MathUtil.min(1.0, 2.0, NaN, 3.0), 0);
|
||||||
|
assertEquals(1.0, MathUtil.min(NaN, 2.0, 3.0, 1.0), 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user