1 package net.sf.openrocket.optimization.rocketoptimization.domains;
3 import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
4 import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
5 import net.sf.openrocket.aerodynamics.FlightConditions;
6 import net.sf.openrocket.document.Simulation;
7 import net.sf.openrocket.masscalc.BasicMassCalculator;
8 import net.sf.openrocket.masscalc.MassCalculator;
9 import net.sf.openrocket.masscalc.MassCalculator.MassCalcType;
10 import net.sf.openrocket.optimization.rocketoptimization.SimulationDomain;
11 import net.sf.openrocket.rocketcomponent.Configuration;
12 import net.sf.openrocket.rocketcomponent.RocketComponent;
13 import net.sf.openrocket.rocketcomponent.SymmetricComponent;
14 import net.sf.openrocket.startup.Application;
15 import net.sf.openrocket.unit.UnitGroup;
16 import net.sf.openrocket.unit.Value;
17 import net.sf.openrocket.util.Coordinate;
18 import net.sf.openrocket.util.MathUtil;
19 import net.sf.openrocket.util.Pair;
22 * A simulation domain that limits the required stability of the rocket.
24 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
26 public class StabilityDomain implements SimulationDomain {
28 private final double minimum;
29 private final boolean minAbsolute;
30 private final double maximum;
31 private final boolean maxAbsolute;
37 * @param minimum minimum stability requirement (or <code>NaN</code> for no limit)
38 * @param minAbsolute <code>true</code> if minimum is an absolute SI measurement,
39 * <code>false</code> if it is relative to the rocket caliber
40 * @param maximum maximum stability requirement (or <code>NaN</code> for no limit)
41 * @param maxAbsolute <code>true</code> if maximum is an absolute SI measurement,
42 * <code>false</code> if it is relative to the rocket caliber
44 public StabilityDomain(double minimum, boolean minAbsolute, double maximum, boolean maxAbsolute) {
46 this.minimum = minimum;
47 this.minAbsolute = minAbsolute;
48 this.maximum = maximum;
49 this.maxAbsolute = maxAbsolute;
56 public Pair<Double, Value> getDistanceToDomain(Simulation simulation) {
63 * These are instantiated each time because this class must be thread-safe.
64 * Caching would in any case be inefficient since the rocket changes all the time.
66 AerodynamicCalculator aerodynamicCalculator = new BarrowmanCalculator();
67 MassCalculator massCalculator = new BasicMassCalculator();
70 Configuration configuration = simulation.getConfiguration();
71 FlightConditions conditions = new FlightConditions(configuration);
72 conditions.setMach(Application.getPreferences().getDefaultMach());
74 conditions.setRollRate(0);
76 // TODO: HIGH: This re-calculates the worst theta value every time
77 cp = aerodynamicCalculator.getWorstCP(configuration, conditions, null);
78 cg = massCalculator.getCG(configuration, MassCalcType.LAUNCH_MASS);
80 if (cp.weight > 0.000001)
85 if (cg.weight > 0.000001)
91 // Calculate the reference (absolute or relative)
95 for (RocketComponent c : configuration) {
96 if (c instanceof SymmetricComponent) {
97 double d1 = ((SymmetricComponent) c).getForeRadius() * 2;
98 double d2 = ((SymmetricComponent) c).getAftRadius() * 2;
99 diameter = MathUtil.max(diameter, d1, d2);
102 relative = absolute / diameter;
106 if (minAbsolute && maxAbsolute) {
107 desc = new Value(absolute, UnitGroup.UNITS_LENGTH);
109 desc = new Value(relative, UnitGroup.UNITS_STABILITY_CALIBERS);
114 ref = minimum - absolute;
116 return new Pair<Double, Value>(ref, desc);
119 ref = minimum - relative;
121 return new Pair<Double, Value>(ref, desc);
126 ref = absolute - maximum;
128 return new Pair<Double, Value>(ref, desc);
131 ref = relative - maximum;
133 return new Pair<Double, Value>(ref, desc);
137 return new Pair<Double, Value>(0.0, desc);