moving to core/
[debian/openrocket] / core / src / net / sf / openrocket / optimization / services / DefaultSimulationModifierService.java
1 package net.sf.openrocket.optimization.services;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8
9 import net.sf.openrocket.document.OpenRocketDocument;
10 import net.sf.openrocket.document.Simulation;
11 import net.sf.openrocket.l10n.Translator;
12 import net.sf.openrocket.optimization.general.OptimizationException;
13 import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier;
14 import net.sf.openrocket.optimization.rocketoptimization.modifiers.GenericComponentModifier;
15 import net.sf.openrocket.rocketcomponent.BodyTube;
16 import net.sf.openrocket.rocketcomponent.EllipticalFinSet;
17 import net.sf.openrocket.rocketcomponent.FinSet;
18 import net.sf.openrocket.rocketcomponent.FreeformFinSet;
19 import net.sf.openrocket.rocketcomponent.InternalComponent;
20 import net.sf.openrocket.rocketcomponent.LaunchLug;
21 import net.sf.openrocket.rocketcomponent.MassComponent;
22 import net.sf.openrocket.rocketcomponent.MotorMount;
23 import net.sf.openrocket.rocketcomponent.NoseCone;
24 import net.sf.openrocket.rocketcomponent.Parachute;
25 import net.sf.openrocket.rocketcomponent.RecoveryDevice;
26 import net.sf.openrocket.rocketcomponent.RecoveryDevice.DeployEvent;
27 import net.sf.openrocket.rocketcomponent.Rocket;
28 import net.sf.openrocket.rocketcomponent.RocketComponent;
29 import net.sf.openrocket.rocketcomponent.Streamer;
30 import net.sf.openrocket.rocketcomponent.Transition;
31 import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
32 import net.sf.openrocket.startup.Application;
33 import net.sf.openrocket.unit.UnitGroup;
34 import net.sf.openrocket.util.BugException;
35 import net.sf.openrocket.util.Reflection;
36 import net.sf.openrocket.util.Reflection.Method;
37
38 public class DefaultSimulationModifierService implements SimulationModifierService {
39         
40         private static final Translator trans = Application.getTranslator();
41         
42         private static final double DEFAULT_RANGE_MULTIPLIER = 2.0;
43         
44
45         private static final Map<Class<?>, List<ModifierDefinition>> definitions = new HashMap<Class<?>, List<ModifierDefinition>>();
46         static {
47                 //addModifier("optimization.modifier.", unitGroup, multiplier, componentClass, methodName);
48                 
49                 /*
50                  * Note:  Each component type must contain only mutually exclusive variables.
51                  * For example, body tube does not have inner diameter definition because it is
52                  * defined by the outer diameter and thickness.
53                  */
54
55                 addModifier("optimization.modifier.nosecone.length", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Length");
56                 addModifier("optimization.modifier.nosecone.diameter", UnitGroup.UNITS_LENGTH, 2.0, NoseCone.class, "AftRadius", "isAftRadiusAutomatic");
57                 addModifier("optimization.modifier.nosecone.thickness", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Thickness", "isFilled");
58                 
59                 addModifier("optimization.modifier.transition.length", UnitGroup.UNITS_LENGTH, 1.0, Transition.class, "Length");
60                 addModifier("optimization.modifier.transition.forediameter", UnitGroup.UNITS_LENGTH, 2.0, Transition.class, "ForeRadius", "isForeRadiusAutomatic");
61                 addModifier("optimization.modifier.transition.aftdiameter", UnitGroup.UNITS_LENGTH, 2.0, Transition.class, "AftRadius", "isAftRadiusAutomatic");
62                 addModifier("optimization.modifier.transition.thickness", UnitGroup.UNITS_LENGTH, 1.0, Transition.class, "Thickness", "isFilled");
63                 
64                 addModifier("optimization.modifier.bodytube.length", UnitGroup.UNITS_LENGTH, 1.0, BodyTube.class, "Length");
65                 addModifier("optimization.modifier.bodytube.outerDiameter", UnitGroup.UNITS_LENGTH, 2.0, BodyTube.class, "OuterRadius", "isOuterRadiusAutomatic");
66                 addModifier("optimization.modifier.bodytube.thickness", UnitGroup.UNITS_LENGTH, 1.0, BodyTube.class, "Thickness", "isFilled");
67                 
68                 addModifier("optimization.modifier.trapezoidfinset.rootChord", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "RootChord");
69                 addModifier("optimization.modifier.trapezoidfinset.tipChord", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "TipChord");
70                 addModifier("optimization.modifier.trapezoidfinset.sweep", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "Sweep");
71                 addModifier("optimization.modifier.trapezoidfinset.height", UnitGroup.UNITS_LENGTH, 1.0, TrapezoidFinSet.class, "Height");
72                 addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, TrapezoidFinSet.class, "CantAngle");
73                 
74                 addModifier("optimization.modifier.ellipticalfinset.length", UnitGroup.UNITS_LENGTH, 1.0, EllipticalFinSet.class, "Length");
75                 addModifier("optimization.modifier.ellipticalfinset.height", UnitGroup.UNITS_LENGTH, 1.0, EllipticalFinSet.class, "Height");
76                 addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, EllipticalFinSet.class, "CantAngle");
77                 
78                 addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, FreeformFinSet.class, "CantAngle");
79                 
80                 addModifier("optimization.modifier.launchlug.length", UnitGroup.UNITS_LENGTH, 1.0, LaunchLug.class, "Length");
81                 addModifier("optimization.modifier.launchlug.outerDiameter", UnitGroup.UNITS_LENGTH, 2.0, LaunchLug.class, "OuterRadius");
82                 addModifier("optimization.modifier.launchlug.thickness", UnitGroup.UNITS_LENGTH, 1.0, LaunchLug.class, "Thickness");
83                 
84
85                 addModifier("optimization.modifier.masscomponent.mass", UnitGroup.UNITS_MASS, 1.0, MassComponent.class, "ComponentMass");
86                 
87                 addModifier("optimization.modifier.parachute.diameter", UnitGroup.UNITS_LENGTH, 1.0, Parachute.class, "Diameter");
88                 addModifier("optimization.modifier.parachute.coefficient", UnitGroup.UNITS_NONE, 1.0, Parachute.class, "CD");
89                 
90                 addModifier("optimization.modifier.streamer.length", UnitGroup.UNITS_LENGTH, 1.0, Streamer.class, "StripLength");
91                 addModifier("optimization.modifier.streamer.width", UnitGroup.UNITS_LENGTH, 1.0, Streamer.class, "StripWidth");
92                 addModifier("optimization.modifier.streamer.aspectRatio", UnitGroup.UNITS_NONE, 1.0, Streamer.class, "AspectRatio");
93                 addModifier("optimization.modifier.streamer.coefficient", UnitGroup.UNITS_NONE, 1.0, Streamer.class, "CD", "isCDAutomatic");
94                 
95         }
96         
97         private static void addModifier(String modifierNameKey, UnitGroup unitGroup, double multiplier,
98                         Class<? extends RocketComponent> componentClass, String methodName) {
99                 addModifier(modifierNameKey, unitGroup, multiplier, componentClass, methodName, null);
100         }
101         
102         private static void addModifier(String modifierNameKey, UnitGroup unitGroup, double multiplier,
103                                 Class<? extends RocketComponent> componentClass, String methodName, String autoMethod) {
104                 
105                 String modifierDescriptionKey = modifierNameKey + ".desc";
106                 
107                 List<ModifierDefinition> list = definitions.get(componentClass);
108                 if (list == null) {
109                         list = new ArrayList<DefaultSimulationModifierService.ModifierDefinition>();
110                         definitions.put(componentClass, list);
111                 }
112                 
113                 ModifierDefinition definition = new ModifierDefinition(modifierNameKey, modifierDescriptionKey, unitGroup,
114                                 multiplier, componentClass, methodName, autoMethod);
115                 list.add(definition);
116         }
117         
118         
119
120
121         @Override
122         public Collection<SimulationModifier> getModifiers(OpenRocketDocument document) {
123                 List<SimulationModifier> modifiers = new ArrayList<SimulationModifier>();
124                 
125                 Rocket rocket = document.getRocket();
126                 
127                 // Simulation is used to calculate default min/max values
128                 Simulation simulation = new Simulation(rocket);
129                 simulation.getConfiguration().setMotorConfigurationID(null);
130                 
131                 for (RocketComponent c : rocket) {
132                         
133                         // Attribute modifiers
134                         List<ModifierDefinition> list = definitions.get(c.getClass());
135                         if (list != null) {
136                                 for (ModifierDefinition def : list) {
137                                         
138                                         // Ignore modifier if value is set to automatic
139                                         if (def.autoMethod != null) {
140                                                 Method m = Reflection.findMethod(c.getClass(), def.autoMethod);
141                                                 if ((Boolean) m.invoke(c)) {
142                                                         continue;
143                                                 }
144                                         }
145                                         
146                                         SimulationModifier mod = new GenericComponentModifier(
147                                                         trans.get(def.modifierNameKey), trans.get(def.modifierDescriptionKey), c, def.unitGroup,
148                                                         def.multiplier, def.componentClass, c.getID(), def.methodName);
149                                         setDefaultMinMax(mod, simulation);
150                                         modifiers.add(mod);
151                                 }
152                         }
153                         
154
155                         // Add override modifiers if mass/CG is overridden
156                         if (c.isMassOverridden()) {
157                                 SimulationModifier mod = new GenericComponentModifier(
158                                                 trans.get("optimization.modifier.rocketcomponent.overrideMass"),
159                                                 trans.get("optimization.modifier.rocketcomponent.overrideMass.desc"),
160                                                 c, UnitGroup.UNITS_MASS,
161                                                 1.0, c.getClass(), c.getID(), "OverrideMass");
162                                 setDefaultMinMax(mod, simulation);
163                                 modifiers.add(mod);
164                         }
165                         if (c.isCGOverridden()) {
166                                 SimulationModifier mod = new GenericComponentModifier(
167                                                 trans.get("optimization.modifier.rocketcomponent.overrideCG"),
168                                                 trans.get("optimization.modifier.rocketcomponent.overrideCG.desc"),
169                                                 c, UnitGroup.UNITS_LENGTH,
170                                                 1.0, c.getClass(), c.getID(), "OverrideCGX");
171                                 mod.setMinValue(0);
172                                 mod.setMaxValue(c.getLength());
173                                 modifiers.add(mod);
174                         }
175                         
176
177                         // Conditional motor mount parameters
178                         if (c instanceof MotorMount) {
179                                 MotorMount mount = (MotorMount) c;
180                                 if (mount.isMotorMount()) {
181                                         
182                                         SimulationModifier mod = new GenericComponentModifier(
183                                                         trans.get("optimization.modifier.motormount.overhang"),
184                                                         trans.get("optimization.modifier.motormount.overhang.desc"),
185                                                         c, UnitGroup.UNITS_LENGTH,
186                                                         1.0, c.getClass(), c.getID(), "MotorOverhang");
187                                         setDefaultMinMax(mod, simulation);
188                                         modifiers.add(mod);
189                                         
190                                         mod = new GenericComponentModifier(
191                                                         trans.get("optimization.modifier.motormount.delay"),
192                                                         trans.get("optimization.modifier.motormount.delay.desc"),
193                                                         c, UnitGroup.UNITS_SHORT_TIME,
194                                                         1.0, c.getClass(), c.getID(), "IgnitionDelay");
195                                         mod.setMinValue(0);
196                                         mod.setMaxValue(5);
197                                         modifiers.add(mod);
198                                         
199                                 }
200                         }
201                         
202
203                         // Inner component positioning
204                         if (c instanceof InternalComponent) {
205                                 RocketComponent parent = c.getParent();
206                                 SimulationModifier mod = new GenericComponentModifier(
207                                                 trans.get("optimization.modifier.internalcomponent.position"),
208                                                 trans.get("optimization.modifier.internalcomponent.position.desc"),
209                                                 c, UnitGroup.UNITS_LENGTH,
210                                                 1.0, c.getClass(), c.getID(), "PositionValue");
211                                 mod.setMinValue(0);
212                                 mod.setMaxValue(parent.getLength());
213                                 modifiers.add(mod);
214                         }
215                         
216
217                         // Custom min/max for fin set position
218                         if (c instanceof FinSet) {
219                                 RocketComponent parent = c.getParent();
220                                 SimulationModifier mod = new GenericComponentModifier(
221                                                 trans.get("optimization.modifier.finset.position"),
222                                                 trans.get("optimization.modifier.finset.position.desc"),
223                                                 c, UnitGroup.UNITS_LENGTH,
224                                                 1.0, c.getClass(), c.getID(), "PositionValue");
225                                 mod.setMinValue(0);
226                                 mod.setMaxValue(parent.getLength());
227                                 modifiers.add(mod);
228                         }
229                         
230
231                         // Custom min/max for launch lug position
232                         if (c instanceof LaunchLug) {
233                                 RocketComponent parent = c.getParent();
234                                 SimulationModifier mod = new GenericComponentModifier(
235                                                 trans.get("optimization.modifier.launchlug.position"),
236                                                 trans.get("optimization.modifier.launchlug.position.desc"),
237                                                 c, UnitGroup.UNITS_LENGTH,
238                                                 1.0, c.getClass(), c.getID(), "PositionValue");
239                                 mod.setMinValue(0);
240                                 mod.setMaxValue(parent.getLength());
241                                 modifiers.add(mod);
242                         }
243                         
244
245                         // Recovery device deployment altitude and delay
246                         if (c instanceof RecoveryDevice) {
247                                 RecoveryDevice device = (RecoveryDevice) c;
248                                 
249                                 SimulationModifier mod = new GenericComponentModifier(
250                                                 trans.get("optimization.modifier.recoverydevice.deployDelay"),
251                                                 trans.get("optimization.modifier.recoverydevice.deployDelay.desc"),
252                                                 c, UnitGroup.UNITS_SHORT_TIME,
253                                                 1.0, c.getClass(), c.getID(), "DeployDelay");
254                                 mod.setMinValue(0);
255                                 mod.setMaxValue(10);
256                                 modifiers.add(mod);
257                                 
258                                 if (device.getDeployEvent() == DeployEvent.ALTITUDE) {
259                                         mod = new GenericComponentModifier(
260                                                         trans.get("optimization.modifier.recoverydevice.deployAltitude"),
261                                                         trans.get("optimization.modifier.recoverydevice.deployAltitude.desc"),
262                                                         c, UnitGroup.UNITS_DISTANCE,
263                                                         1.0, c.getClass(), c.getID(), "DeployAltitude");
264                                         setDefaultMinMax(mod, simulation);
265                                         modifiers.add(mod);
266                                 }
267                         }
268                         
269
270                         // Conditional shape parameter of Transition
271                         if (c instanceof Transition) {
272                                 Transition transition = (Transition) c;
273                                 Transition.Shape shape = transition.getType();
274                                 if (shape.usesParameter()) {
275                                         SimulationModifier mod = new GenericComponentModifier(
276                                                         trans.get("optimization.modifier." + c.getClass().getSimpleName().toLowerCase() + ".shapeparameter"),
277                                                         trans.get("optimization.modifier." + c.getClass().getSimpleName().toLowerCase() + ".shapeparameter.desc"),
278                                                         c, UnitGroup.UNITS_NONE,
279                                                         1.0, c.getClass(), c.getID(), "ShapeParameter");
280                                         mod.setMinValue(shape.minParameter());
281                                         mod.setMaxValue(shape.maxParameter());
282                                         modifiers.add(mod);
283                                 }
284                         }
285                 }
286                 
287                 return modifiers;
288         }
289         
290         
291         private void setDefaultMinMax(SimulationModifier mod, Simulation simulation) {
292                 try {
293                         double current = mod.getCurrentSIValue(simulation);
294                         mod.setMinValue(current / DEFAULT_RANGE_MULTIPLIER);
295                         mod.setMaxValue(current * DEFAULT_RANGE_MULTIPLIER);
296                 } catch (OptimizationException e) {
297                         throw new BugException("Simulation modifier threw exception", e);
298                 }
299         }
300         
301         
302         /*
303          * String modifierName, Object relatedObject, UnitGroup unitGroup,
304                         double multiplier, Class<? extends RocketComponent> componentClass, String componentId, String methodName
305          */
306
307         private static class ModifierDefinition {
308                 private final String modifierNameKey;
309                 private final String modifierDescriptionKey;
310                 private final UnitGroup unitGroup;
311                 private final double multiplier;
312                 private final Class<? extends RocketComponent> componentClass;
313                 private final String methodName;
314                 private final String autoMethod;
315                 
316                 
317                 public ModifierDefinition(String modifierNameKey, String modifierDescriptionKey, UnitGroup unitGroup,
318                                 double multiplier, Class<? extends RocketComponent> componentClass, String methodName, String autoMethod) {
319                         this.modifierNameKey = modifierNameKey;
320                         this.modifierDescriptionKey = modifierDescriptionKey;
321                         this.unitGroup = unitGroup;
322                         this.multiplier = multiplier;
323                         this.componentClass = componentClass;
324                         this.methodName = methodName;
325                         this.autoMethod = autoMethod;
326                 }
327                 
328         }
329 }