c975a8a4fc41bc71b6f4f2c57376883ddcb2a5ba
[debian/openrocket] / src / net / sf / openrocket / optimization / rocketoptimization / RocketOptimizationFunction.java
1 package net.sf.openrocket.optimization.rocketoptimization;
2
3 import java.util.Arrays;
4 import java.util.Map;
5 import java.util.concurrent.ConcurrentHashMap;
6
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;
13
14 /**
15  * A Function that optimizes a specific RocketOptimizationParameter to some goal
16  * by modifying a base simulation using SimulationModifiers.
17  * 
18  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
19  */
20 public class RocketOptimizationFunction implements Function {
21         private static final LogHelper log = Application.getLogger();
22         
23         /*
24          * NOTE:  This class must be thread-safe!!!
25          */
26
27         private final Simulation baseSimulation;
28         private final RocketOptimizationParameter parameter;
29         private final OptimizationGoal goal;
30         private final SimulationModifier[] modifiers;
31         
32         private final Map<Point, Double> parameterValueCache = new ConcurrentHashMap<Point, Double>();
33         private final Map<Point, Double> goalValueCache = new ConcurrentHashMap<Point, Double>();
34         
35         
36         /**
37          * Sole constructor.
38          * <p>
39          * The dimensionality of the resulting function is the same as the length of the
40          * modifiers array.
41          * 
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
46          */
47         public RocketOptimizationFunction(Simulation baseSimulation, RocketOptimizationParameter parameter,
48                         OptimizationGoal goal, SimulationModifier... modifiers) {
49                 this.baseSimulation = baseSimulation;
50                 this.parameter = parameter;
51                 this.goal = goal;
52                 this.modifiers = modifiers.clone();
53                 if (modifiers.length == 0) {
54                         throw new IllegalArgumentException("No SimulationModifiers specified");
55                 }
56         }
57         
58         
59         @Override
60         public double evaluate(Point point) throws InterruptedException {
61                 
62                 // Check for precomputed value
63                 double value = preComputed(point);
64                 if (!Double.isNaN(value)) {
65                         return value;
66                 }
67                 
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");
73                 }
74                 Simulation simulation = newSimulationInstance();
75                 for (int i = 0; i < modifiers.length; i++) {
76                         modifiers[i].modify(simulation, p[i]);
77                 }
78                 
79                 // Compute the optimization value
80                 value = parameter.computeValue(simulation);
81                 parameterValueCache.put(point, value);
82                 
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;
88                 }
89                 goalValueCache.put(point, value);
90                 
91                 return value;
92         }
93         
94         @Override
95         public double preComputed(Point point) {
96                 Double value = goalValueCache.get(point);
97                 if (value != null) {
98                         return value;
99                 }
100                 
101                 // TODO: : is in domain?
102                 return 0;
103         }
104         
105         
106         /**
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.
109          * 
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.
112          */
113         public double getComputedParameterValue(Point point) {
114                 Double value = parameterValueCache.get(point);
115                 if (value != null) {
116                         return value;
117                 } else {
118                         return Double.NaN;
119                 }
120         }
121         
122         
123         /**
124          * Returns a new deep copy of the simulation and rocket.  This methods performs
125          * synchronization on the simulation for thread protection.
126          * 
127          * @return
128          */
129         private Simulation newSimulationInstance() {
130                 synchronized (baseSimulation) {
131                         Rocket newRocket = (Rocket) baseSimulation.getRocket().copy();
132                         Simulation newSimulation = baseSimulation.duplicateSimulation(newRocket);
133                         return newSimulation;
134                 }
135         }
136         
137 }