create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / optimization / rocketoptimization / domains / StabilityDomain.java
1 package net.sf.openrocket.optimization.rocketoptimization.domains;
2
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;
20
21 /**
22  * A simulation domain that limits the required stability of the rocket.
23  * 
24  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
25  */
26 public class StabilityDomain implements SimulationDomain {
27         
28         private final double minimum;
29         private final boolean minAbsolute;
30         private final double maximum;
31         private final boolean maxAbsolute;
32         
33         
34         /**
35          * Sole constructor.
36          * 
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
43          */
44         public StabilityDomain(double minimum, boolean minAbsolute, double maximum, boolean maxAbsolute) {
45                 super();
46                 this.minimum = minimum;
47                 this.minAbsolute = minAbsolute;
48                 this.maximum = maximum;
49                 this.maxAbsolute = maxAbsolute;
50         }
51         
52         
53
54
55         @Override
56         public Pair<Double, Value> getDistanceToDomain(Simulation simulation) {
57                 Coordinate cp, cg;
58                 double cpx, cgx;
59                 double absolute;
60                 double relative;
61                 
62                 /*
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.
65                  */
66                 AerodynamicCalculator aerodynamicCalculator = new BarrowmanCalculator();
67                 MassCalculator massCalculator = new BasicMassCalculator();
68                 
69
70                 Configuration configuration = simulation.getConfiguration();
71                 FlightConditions conditions = new FlightConditions(configuration);
72                 conditions.setMach(Application.getPreferences().getDefaultMach());
73                 conditions.setAOA(0);
74                 conditions.setRollRate(0);
75                 
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);
79                 
80                 if (cp.weight > 0.000001)
81                         cpx = cp.x;
82                 else
83                         cpx = Double.NaN;
84                 
85                 if (cg.weight > 0.000001)
86                         cgx = cg.x;
87                 else
88                         cgx = Double.NaN;
89                 
90
91                 // Calculate the reference (absolute or relative)
92                 absolute = cpx - cgx;
93                 
94                 double diameter = 0;
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);
100                         }
101                 }
102                 relative = absolute / diameter;
103                 
104
105                 Value desc;
106                 if (minAbsolute && maxAbsolute) {
107                         desc = new Value(absolute, UnitGroup.UNITS_LENGTH);
108                 } else {
109                         desc = new Value(relative, UnitGroup.UNITS_STABILITY_CALIBERS);
110                 }
111                 
112                 double ref;
113                 if (minAbsolute) {
114                         ref = minimum - absolute;
115                         if (ref > 0) {
116                                 return new Pair<Double, Value>(ref, desc);
117                         }
118                 } else {
119                         ref = minimum - relative;
120                         if (ref > 0) {
121                                 return new Pair<Double, Value>(ref, desc);
122                         }
123                 }
124                 
125                 if (maxAbsolute) {
126                         ref = absolute - maximum;
127                         if (ref > 0) {
128                                 return new Pair<Double, Value>(ref, desc);
129                         }
130                 } else {
131                         ref = relative - maximum;
132                         if (ref > 0) {
133                                 return new Pair<Double, Value>(ref, desc);
134                         }
135                 }
136                 
137                 return new Pair<Double, Value>(0.0, desc);
138         }
139 }