1 package net.sf.openrocket.optimization.rocketoptimization;
3 import java.util.Arrays;
5 import java.util.concurrent.ConcurrentHashMap;
7 import net.sf.openrocket.document.Simulation;
8 import net.sf.openrocket.logging.LogHelper;
9 import net.sf.openrocket.optimization.general.Function;
10 import net.sf.openrocket.optimization.general.Point;
11 import net.sf.openrocket.rocketcomponent.Rocket;
12 import net.sf.openrocket.startup.Application;
15 * A Function that optimizes a specific RocketOptimizationParameter to some goal
16 * by modifying a base simulation using SimulationModifiers.
18 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
20 public class RocketOptimizationFunction implements Function {
21 private static final LogHelper log = Application.getLogger();
24 * NOTE: This class must be thread-safe!!!
27 private final Simulation baseSimulation;
28 private final RocketOptimizationParameter parameter;
29 private final OptimizationGoal goal;
30 private final SimulationModifier[] modifiers;
32 private final Map<Point, Double> parameterValueCache = new ConcurrentHashMap<Point, Double>();
33 private final Map<Point, Double> goalValueCache = new ConcurrentHashMap<Point, Double>();
39 * The dimensionality of the resulting function is the same as the length of the
42 * @param baseSimulation the base simulation to modify
43 * @param parameter the rocket parameter to optimize
44 * @param goal the goal of the rocket parameter
45 * @param modifiers the modifiers that modify the simulation
47 public RocketOptimizationFunction(Simulation baseSimulation, RocketOptimizationParameter parameter,
48 OptimizationGoal goal, SimulationModifier... modifiers) {
49 this.baseSimulation = baseSimulation;
50 this.parameter = parameter;
52 this.modifiers = modifiers.clone();
53 if (modifiers.length == 0) {
54 throw new IllegalArgumentException("No SimulationModifiers specified");
60 public double evaluate(Point point) throws InterruptedException {
62 // Check for precomputed value
63 double value = preComputed(point);
64 if (!Double.isNaN(value)) {
68 // Create the new simulation based on the point
69 double[] p = point.asArray();
70 if (p.length != modifiers.length) {
71 throw new IllegalArgumentException("Point has length " + p.length + " while function has " +
72 modifiers.length + " simulation modifiers");
74 Simulation simulation = newSimulationInstance();
75 for (int i = 0; i < modifiers.length; i++) {
76 modifiers[i].modify(simulation, p[i]);
79 // Compute the optimization value
80 value = parameter.computeValue(simulation);
81 parameterValueCache.put(point, value);
83 value = goal.getMinimizationParameter(value);
84 if (Double.isNaN(value)) {
85 log.warn("Computed value was NaN, baseSimulation=" + baseSimulation + " parameter=" + parameter +
86 " goal=" + goal + " modifiers=" + Arrays.toString(modifiers) + " simulation=" + simulation);
87 value = Double.MAX_VALUE;
89 goalValueCache.put(point, value);
95 public double preComputed(Point point) {
96 Double value = goalValueCache.get(point);
101 // TODO: : is in domain?
107 * Return the parameter value at a point that has been computed. The purpose is
108 * to allow retrieving the parameter value corresponding to the found minimum value.
110 * @param point the point to use.
111 * @return the parameter value at that point, or NaN if the value at this point has not been computed.
113 public double getComputedParameterValue(Point point) {
114 Double value = parameterValueCache.get(point);
124 * Returns a new deep copy of the simulation and rocket. This methods performs
125 * synchronization on the simulation for thread protection.
129 private Simulation newSimulationInstance() {
130 synchronized (baseSimulation) {
131 Rocket newRocket = (Rocket) baseSimulation.getRocket().copy();
132 Simulation newSimulation = baseSimulation.duplicateSimulation(newRocket);
133 return newSimulation;