bug fixes
[debian/openrocket] / src / net / sf / openrocket / simulation / FlightDataBranch.java
1 package net.sf.openrocket.simulation;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.HashMap;
6 import java.util.LinkedHashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 import net.sf.openrocket.unit.UnitGroup;
11 import net.sf.openrocket.util.Pair;
12
13
14 public class FlightDataBranch {
15         
16         //// Time
17         public static final Type TYPE_TIME = 
18                 new Type("Time", UnitGroup.UNITS_FLIGHT_TIME, 1);
19         
20         
21         //// Vertical position and motion
22         public static final Type TYPE_ALTITUDE = 
23                 new Type("Altitude", UnitGroup.UNITS_DISTANCE, 10);
24         public static final Type TYPE_VELOCITY_Z = 
25                 new Type("Vertical velocity", UnitGroup.UNITS_VELOCITY, 11);
26         public static final Type TYPE_ACCELERATION_Z = 
27                 new Type("Vertical acceleration", UnitGroup.UNITS_ACCELERATION, 12);
28
29         
30         //// Total motion
31         public static final Type TYPE_VELOCITY_TOTAL =
32                 new Type("Total velocity", UnitGroup.UNITS_VELOCITY, 20);
33         public static final Type TYPE_ACCELERATION_TOTAL =
34                 new Type("Total acceleration", UnitGroup.UNITS_ACCELERATION, 21);
35
36         
37         //// Lateral position and motion
38         
39         public static final Type TYPE_POSITION_X =
40                 new Type("Position upwind", UnitGroup.UNITS_DISTANCE, 30);
41         public static final Type TYPE_POSITION_Y =
42                 new Type("Position parallel to wind", UnitGroup.UNITS_DISTANCE, 31);
43         public static final Type TYPE_POSITION_XY =
44                 new Type("Lateral distance", UnitGroup.UNITS_DISTANCE, 32);
45         public static final Type TYPE_POSITION_DIRECTION =
46                 new Type("Lateral direction", UnitGroup.UNITS_ANGLE, 33);
47
48         public static final Type TYPE_VELOCITY_XY =
49                 new Type("Lateral velocity", UnitGroup.UNITS_VELOCITY, 34);
50         public static final Type TYPE_ACCELERATION_XY =
51                 new Type("Lateral acceleration", UnitGroup.UNITS_ACCELERATION, 35);
52
53         
54         //// Angular motion
55         public static final Type TYPE_AOA = new Type("Angle of attack", UnitGroup.UNITS_ANGLE, 40);
56         public static final Type TYPE_ROLL_RATE = new Type("Roll rate", UnitGroup.UNITS_ROLL, 41);
57         public static final Type TYPE_PITCH_RATE = new Type("Pitch rate", UnitGroup.UNITS_ROLL, 42);
58         public static final Type TYPE_YAW_RATE = new Type("Yaw rate", UnitGroup.UNITS_ROLL, 43);
59
60         
61         //// Stability information
62         public static final Type TYPE_MASS = 
63                 new Type("Mass", UnitGroup.UNITS_MASS, 50);
64         public static final Type TYPE_CP_LOCATION = 
65                 new Type("CP location", UnitGroup.UNITS_LENGTH, 51);
66         public static final Type TYPE_CG_LOCATION = 
67                 new Type("CG location", UnitGroup.UNITS_LENGTH, 52);
68         public static final Type TYPE_STABILITY = 
69                 new Type("Stability margin calibers", UnitGroup.UNITS_COEFFICIENT, 53);
70
71         
72         //// Characteristic numbers
73         public static final Type TYPE_MACH_NUMBER =
74                 new Type("Mach number", UnitGroup.UNITS_COEFFICIENT, 60);
75         public static final Type TYPE_REYNOLDS_NUMBER =
76                 new Type("Reynolds number", UnitGroup.UNITS_COEFFICIENT, 61);
77         
78
79         //// Thrust and drag
80         public static final Type TYPE_THRUST_FORCE = 
81                 new Type("Thrust", UnitGroup.UNITS_FORCE, 70);
82         public static final Type TYPE_DRAG_FORCE = 
83                 new Type("Drag force", UnitGroup.UNITS_FORCE, 71);
84
85         public static final Type TYPE_DRAG_COEFF = 
86                 new Type("Drag coefficient", UnitGroup.UNITS_COEFFICIENT, 72);
87         public static final Type TYPE_AXIAL_DRAG_COEFF = 
88                 new Type("Axial drag coefficient", UnitGroup.UNITS_COEFFICIENT, 73);
89
90         
91         ////  Component drag coefficients
92         public static final Type TYPE_FRICTION_DRAG_COEFF = 
93                 new Type("Friction drag coefficient", UnitGroup.UNITS_COEFFICIENT, 80);
94         public static final Type TYPE_PRESSURE_DRAG_COEFF = 
95                 new Type("Pressure drag coefficient", UnitGroup.UNITS_COEFFICIENT, 81);
96         public static final Type TYPE_BASE_DRAG_COEFF = 
97                 new Type("Base drag coefficient", UnitGroup.UNITS_COEFFICIENT, 82);
98
99
100         ////  Other coefficients
101         public static final Type TYPE_NORMAL_FORCE_COEFF =
102                 new Type("Normal force coefficient", UnitGroup.UNITS_COEFFICIENT, 90);
103         public static final Type TYPE_PITCH_MOMENT_COEFF =
104                 new Type("Pitch moment coefficient", UnitGroup.UNITS_COEFFICIENT, 91);
105         public static final Type TYPE_YAW_MOMENT_COEFF =
106                 new Type("Yaw moment coefficient", UnitGroup.UNITS_COEFFICIENT, 92);
107         public static final Type TYPE_SIDE_FORCE_COEFF =
108                 new Type("Side force coefficient", UnitGroup.UNITS_COEFFICIENT, 93);
109         public static final Type TYPE_ROLL_MOMENT_COEFF =
110                 new Type("Roll moment coefficient", UnitGroup.UNITS_COEFFICIENT, 94);
111         public static final Type TYPE_ROLL_FORCING_COEFF =
112                 new Type("Roll forcing coefficient", UnitGroup.UNITS_COEFFICIENT, 95);
113         public static final Type TYPE_ROLL_DAMPING_COEFF =
114                 new Type("Roll damping coefficient", UnitGroup.UNITS_COEFFICIENT, 96);
115         
116         public static final Type TYPE_PITCH_DAMPING_MOMENT_COEFF =
117                 new Type("Pitch damping coefficient", UnitGroup.UNITS_COEFFICIENT, 97);
118         public static final Type TYPE_YAW_DAMPING_MOMENT_COEFF =
119                 new Type("Yaw damping coefficient", UnitGroup.UNITS_COEFFICIENT, 98);
120         
121         
122         ////  Reference length + area
123         public static final Type TYPE_REFERENCE_LENGTH = 
124                 new Type("Reference length", UnitGroup.UNITS_LENGTH, 100);
125         public static final Type TYPE_REFERENCE_AREA = 
126                 new Type("Reference area", UnitGroup.UNITS_AREA, 101);
127         
128
129         ////  Orientation
130         public static final Type TYPE_ORIENTATION_THETA = 
131                 new Type("Vertical orientation (zenith)", UnitGroup.UNITS_ANGLE, 106);
132         public static final Type TYPE_ORIENTATION_PHI =
133                 new Type("Lateral orientation (azimuth)", UnitGroup.UNITS_ANGLE, 107);
134         
135         
136         ////  Atmospheric conditions
137         public static final Type TYPE_WIND_VELOCITY = new Type("Wind velocity", 
138                         UnitGroup.UNITS_VELOCITY, 110);
139         public static final Type TYPE_AIR_TEMPERATURE = new Type("Air temperature",
140                         UnitGroup.UNITS_TEMPERATURE, 111);
141         public static final Type TYPE_AIR_PRESSURE = new Type("Air pressure",
142                         UnitGroup.UNITS_PRESSURE, 112);
143         public static final Type TYPE_SPEED_OF_SOUND = new Type("Speed of sound",
144                         UnitGroup.UNITS_VELOCITY, 113);
145
146
147         ////  Simulation information
148         public static final Type TYPE_TIME_STEP = new Type("Simulation time step",
149                         UnitGroup.UNITS_TIME_STEP, 200);
150         public static final Type TYPE_COMPUTATION_TIME = new Type("Computation time",
151                         UnitGroup.UNITS_SHORT_TIME, 201);
152
153         
154         /**
155          * Array of known data types for String -> Type conversion.
156          */
157         private static final Type[] TYPES = {
158                 TYPE_TIME, 
159                 TYPE_ALTITUDE, TYPE_VELOCITY_Z, TYPE_ACCELERATION_Z,
160                 TYPE_VELOCITY_TOTAL, TYPE_ACCELERATION_TOTAL,
161                 TYPE_POSITION_X, TYPE_POSITION_Y, TYPE_POSITION_XY, TYPE_POSITION_DIRECTION,
162                 TYPE_VELOCITY_XY, TYPE_ACCELERATION_XY,
163                 TYPE_AOA, TYPE_ROLL_RATE, TYPE_PITCH_RATE, TYPE_YAW_RATE,
164                 TYPE_MASS, TYPE_CP_LOCATION, TYPE_CG_LOCATION, TYPE_STABILITY,
165                 TYPE_MACH_NUMBER, TYPE_REYNOLDS_NUMBER,
166                 TYPE_THRUST_FORCE, TYPE_DRAG_FORCE,
167                 TYPE_DRAG_COEFF, TYPE_AXIAL_DRAG_COEFF,
168                 TYPE_FRICTION_DRAG_COEFF, TYPE_PRESSURE_DRAG_COEFF, TYPE_BASE_DRAG_COEFF,
169                 TYPE_NORMAL_FORCE_COEFF, TYPE_PITCH_MOMENT_COEFF, TYPE_YAW_MOMENT_COEFF, TYPE_SIDE_FORCE_COEFF,
170                 TYPE_ROLL_MOMENT_COEFF, TYPE_ROLL_FORCING_COEFF, TYPE_ROLL_DAMPING_COEFF,
171                 TYPE_PITCH_DAMPING_MOMENT_COEFF, TYPE_YAW_DAMPING_MOMENT_COEFF,
172                 TYPE_REFERENCE_LENGTH, TYPE_REFERENCE_AREA, 
173                 TYPE_ORIENTATION_THETA, TYPE_ORIENTATION_PHI,
174                 TYPE_WIND_VELOCITY, TYPE_AIR_TEMPERATURE, TYPE_AIR_PRESSURE, TYPE_SPEED_OF_SOUND,
175                 TYPE_TIME_STEP, TYPE_COMPUTATION_TIME
176         };
177         
178         /**
179          * Return a {@link Type} based on a string description.  This returns known data types
180          * if possible, or a new type otherwise.
181          * 
182          * @param s             the string description of the type.
183          * @param u             the unit group the new type should belong to if a new group is created.
184          * @return              a data type.
185          */
186         public static Type getType(String s, UnitGroup u) {
187                 for (Type t: TYPES) {
188                         if (t.getName().equalsIgnoreCase(s))
189                                 return t;
190                 }
191                 return new Type(s, u);
192         }
193         
194         
195         
196         public static class Type implements Comparable<Type> {
197                 private final String name;
198                 private final UnitGroup units;
199                 private final int priority;
200                 private final int hashCode;
201                 
202                 private Type(String typeName, UnitGroup units) {
203                         this(typeName, units, 999);
204                 }
205                 
206                 public Type(String typeName, UnitGroup units, int priority) {
207                         if (typeName == null)
208                                 throw new IllegalArgumentException("typeName is null");
209                         this.name = typeName;
210                         this.units = units;
211                         this.priority = priority;
212                         this.hashCode = this.name.toLowerCase().hashCode();
213                 }
214                 
215                 public String getName() {
216                         return name;
217                 }
218                 
219                 public UnitGroup getUnitGroup() {
220                         return units;
221                 }
222                 
223                 @Override
224                 public String toString() {
225                         return name;
226                 }
227                 
228                 @Override
229                 public boolean equals(Object other) {
230                         if (!(other instanceof Type))
231                                 return false;
232                         return this.name.equalsIgnoreCase(((Type)other).name);
233                 }
234                 @Override
235                 public int hashCode() {
236                         return hashCode;
237                 }
238
239                 @Override
240                 public int compareTo(Type o) {
241                         return this.priority - o.priority;
242                 }
243         }
244         
245
246         
247         
248         /** The name of this flight data branch. */
249         private final String branchName;
250         
251         private final Map<Type, ArrayList<Double>> values = 
252                 new LinkedHashMap<Type, ArrayList<Double>>();
253         
254         private final Map<Type, Double> maxValues = new HashMap<Type, Double>();
255         private final Map<Type, Double> minValues = new HashMap<Type, Double>();
256         
257         
258         private final ArrayList<Pair<Double,FlightEvent>> events =
259                 new ArrayList<Pair<Double,FlightEvent>>();
260         
261         private boolean mutable = true;
262         
263         
264         public FlightDataBranch(String name, Type... types) {
265                 if (types.length == 0) {
266                         throw new IllegalArgumentException("Must specify at least one data type.");
267                 }
268                 
269                 this.branchName = name;
270
271                 for (Type t: types) {
272                         if (values.containsKey(t)) {
273                                 throw new IllegalArgumentException("Value type "+t+" specified multiple " +
274                                 "times in constructor.");
275                         }
276                         
277                         values.put(t, new ArrayList<Double>());
278                         minValues.put(t, Double.NaN);
279                         maxValues.put(t, Double.NaN);
280                 }
281         }
282         
283         
284         public String getBranchName() {
285                 return branchName;
286         }
287         
288         public Type[] getTypes() {
289                 Type[] array = values.keySet().toArray(new Type[0]);
290                 Arrays.sort(array);
291                 return array;
292         }
293         
294         public int getLength() {
295                 for (Type t: values.keySet()) {
296                         return values.get(t).size();
297                 }
298                 return 0;
299         }
300         
301         
302         
303         public void addPoint() {
304                 if (!mutable)
305                         throw new IllegalStateException("FlightDataBranch has been made immutable.");
306                 for (Type t: values.keySet()) {
307                         values.get(t).add(Double.NaN);
308                 }
309         }
310         
311         public void setValue(Type type, double value) {
312                 if (!mutable)
313                         throw new IllegalStateException("FlightDataBranch has been made immutable.");
314                 ArrayList<Double> list = values.get(type);
315                 if (list == null) {
316                         
317                         list = new ArrayList<Double>();
318                         int n = getLength();
319                         for (int i=0; i < n; i++) {
320                                 list.add(Double.NaN);
321                         }
322                         values.put(type, list);
323                         minValues.put(type, value);
324                         maxValues.put(type, value);
325                         
326                 }
327                 list.set(list.size()-1, value);
328                 double min = minValues.get(type);
329                 double max = maxValues.get(type);
330                 
331                 if (Double.isNaN(min) || (value < min)) {
332                         minValues.put(type, value);
333                 }
334                 if (Double.isNaN(max) || (value > max)) {
335                         maxValues.put(type, value);
336                 }
337         }
338         
339         
340         @SuppressWarnings("unchecked")
341         public List<Double> get(Type type) {
342                 ArrayList<Double> list = values.get(type);
343                 if (list==null)
344                         return null;
345                 return (List<Double>)list.clone();
346         }
347         
348         
349         public double get(Type type, int index) {
350                 ArrayList<Double> list = values.get(type);
351                 if (list==null)
352                         return Double.NaN;
353                 return list.get(index);
354         }
355         
356
357         /**
358          * Return the last value of the specified type in the branch, or NaN if the type is
359          * unavailable.
360          * 
361          * @param type  the parameter type.
362          * @return              the last value in this branch, or NaN.
363          */
364         public double getLast(Type type) {
365                 ArrayList<Double> list = values.get(type);
366                 if (list==null || list.isEmpty())
367                         return Double.NaN;
368                 return list.get(list.size()-1);
369         }
370
371         /**
372          * Return the minimum value of the specified type in the branch, or NaN if the type
373          * is unavailable.
374          * 
375          * @param type  the parameter type.
376          * @return              the minimum value in this branch, or NaN.
377          */
378         public double getMinimum(Type type) {
379                 Double v = minValues.get(type);
380                 if (v==null)
381                         return Double.NaN;
382                 return v;
383         }
384         
385         /**
386          * Return the maximum value of the specified type in the branch, or NaN if the type
387          * is unavailable.
388          * 
389          * @param type  the parameter type.
390          * @return              the maximum value in this branch, or NaN.
391          */
392         public double getMaximum(Type type) {
393                 Double v = maxValues.get(type);
394                 if (v==null)
395                         return Double.NaN;
396                 return v;
397         }
398         
399         
400         public void addEvent(double time, FlightEvent event) {
401                 if (!mutable)
402                         throw new IllegalStateException("FlightDataBranch has been made immutable.");
403                 events.add(new Pair<Double,FlightEvent>(time,event));
404         }
405         
406         
407         /**
408          * Return the list of events.  The list is a list of (time, event) pairs.
409          * 
410          * @return      the list of events during the flight.
411          */
412         @SuppressWarnings("unchecked")
413         public List<Pair<Double, FlightEvent>> getEvents() {
414                 return (List<Pair<Double, FlightEvent>>) events.clone();
415         }
416
417         
418         /**
419          * Make this FlightDataBranch immutable.  Any calls to the set methods that would
420          * modify this object will after this call throw an <code>IllegalStateException</code>.
421          */
422         public void immute() {
423                 mutable = false;
424         }
425         
426         public boolean isMutable() {
427                 return mutable;
428         }
429         
430         
431
432         
433 }