1 package net.sf.openrocket.optimization.services;
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.HashMap;
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;
38 public class DefaultSimulationModifierService implements SimulationModifierService {
40 private static final Translator trans = Application.getTranslator();
42 private static final double DEFAULT_RANGE_MULTIPLIER = 2.0;
45 private static final Map<Class<?>, List<ModifierDefinition>> definitions = new HashMap<Class<?>, List<ModifierDefinition>>();
47 //addModifier("optimization.modifier.", unitGroup, multiplier, componentClass, methodName);
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.
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");
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");
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");
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");
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");
78 addModifier("optimization.modifier.finset.cant", UnitGroup.UNITS_ANGLE, 1.0, FreeformFinSet.class, "CantAngle");
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");
85 addModifier("optimization.modifier.masscomponent.mass", UnitGroup.UNITS_MASS, 1.0, MassComponent.class, "ComponentMass");
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");
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");
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);
102 private static void addModifier(String modifierNameKey, UnitGroup unitGroup, double multiplier,
103 Class<? extends RocketComponent> componentClass, String methodName, String autoMethod) {
105 String modifierDescriptionKey = modifierNameKey + ".desc";
107 List<ModifierDefinition> list = definitions.get(componentClass);
109 list = new ArrayList<DefaultSimulationModifierService.ModifierDefinition>();
110 definitions.put(componentClass, list);
113 ModifierDefinition definition = new ModifierDefinition(modifierNameKey, modifierDescriptionKey, unitGroup,
114 multiplier, componentClass, methodName, autoMethod);
115 list.add(definition);
122 public Collection<SimulationModifier> getModifiers(OpenRocketDocument document) {
123 List<SimulationModifier> modifiers = new ArrayList<SimulationModifier>();
125 Rocket rocket = document.getRocket();
127 // Simulation is used to calculate default min/max values
128 Simulation simulation = new Simulation(rocket);
129 simulation.getConfiguration().setMotorConfigurationID(null);
131 for (RocketComponent c : rocket) {
133 // Attribute modifiers
134 List<ModifierDefinition> list = definitions.get(c.getClass());
136 for (ModifierDefinition def : list) {
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)) {
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);
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);
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");
172 mod.setMaxValue(c.getLength());
177 // Conditional motor mount parameters
178 if (c instanceof MotorMount) {
179 MotorMount mount = (MotorMount) c;
180 if (mount.isMotorMount()) {
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);
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");
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");
212 mod.setMaxValue(parent.getLength());
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");
226 mod.setMaxValue(parent.getLength());
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");
240 mod.setMaxValue(parent.getLength());
245 // Recovery device deployment altitude and delay
246 if (c instanceof RecoveryDevice) {
247 RecoveryDevice device = (RecoveryDevice) c;
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");
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);
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());
291 private void setDefaultMinMax(SimulationModifier mod, Simulation simulation) {
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);
303 * String modifierName, Object relatedObject, UnitGroup unitGroup,
304 double multiplier, Class<? extends RocketComponent> componentClass, String componentId, String methodName
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;
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;