Added gravitational acceleration and propellant mass datatypes.
[debian/openrocket] / core / src / net / sf / openrocket / simulation / BasicLandingStepper.java
1 package net.sf.openrocket.simulation;
2
3 import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
4 import net.sf.openrocket.rocketcomponent.RecoveryDevice;
5 import net.sf.openrocket.simulation.exception.SimulationException;
6 import net.sf.openrocket.util.Coordinate;
7 import net.sf.openrocket.util.GeodeticComputationStrategy;
8 import net.sf.openrocket.util.MathUtil;
9 import net.sf.openrocket.util.WorldCoordinate;
10
11 public class BasicLandingStepper extends AbstractSimulationStepper {
12         
13         private static final double RECOVERY_TIME_STEP = 0.5;
14         
15         @Override
16         public SimulationStatus initialize(SimulationStatus status) throws SimulationException {
17                 return status;
18         }
19         
20         @Override
21         public void step(SimulationStatus status, double maxTimeStep) throws SimulationException {
22                 double totalCD = 0;
23                 double refArea = status.getConfiguration().getReferenceArea();
24                 
25                 // Get the atmospheric conditions
26                 AtmosphericConditions atmosphere = modelAtmosphericConditions(status);
27                 
28                 //// Local wind speed and direction
29                 Coordinate windSpeed = modelWindVelocity(status);
30                 Coordinate airSpeed = status.getRocketVelocity().add(windSpeed);
31                 
32                 // Get total CD
33                 double mach = airSpeed.length() / atmosphere.getMachSpeed();
34                 for (RecoveryDevice c : status.getDeployedRecoveryDevices()) {
35                         totalCD += c.getCD(mach) * c.getArea() / refArea;
36                 }
37                 
38                 // Compute drag force
39                 double dynP = (0.5 * atmosphere.getDensity() * airSpeed.length2());
40                 double dragForce = totalCD * dynP * refArea;
41                 MassData massData = calculateMassData(status);
42                 double mass = massData.getCG().weight;
43                 
44
45                 // Compute drag acceleration
46                 Coordinate linearAcceleration;
47                 if (airSpeed.length() > 0.001) {
48                         linearAcceleration = airSpeed.normalize().multiply(-dragForce / mass);
49                 } else {
50                         linearAcceleration = Coordinate.NUL;
51                 }
52                 
53                 // Add effect of gravity
54                 double gravity = modelGravity(status);
55                 linearAcceleration = linearAcceleration.sub(0, 0, gravity);
56                 
57
58                 // Add coriolis acceleration
59                 Coordinate coriolisAcceleration = status.getSimulationConditions().getGeodeticComputation().getCoriolisAcceleration(
60                                 status.getRocketWorldPosition(), status.getRocketVelocity());
61                 linearAcceleration = linearAcceleration.add(coriolisAcceleration);
62                 
63
64
65                 // Select time step
66                 double timeStep = MathUtil.min(0.5 / linearAcceleration.length(), RECOVERY_TIME_STEP);
67                 
68                 // Perform Euler integration
69                 status.setRocketPosition(status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
70                                 add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2)));
71                 status.setRocketVelocity(status.getRocketVelocity().add(linearAcceleration.multiply(timeStep)));
72                 status.setSimulationTime(status.getSimulationTime() + timeStep);
73                 
74
75                 // Update the world coordinate
76                 WorldCoordinate w = status.getSimulationConditions().getLaunchSite();
77                 w = status.getSimulationConditions().getGeodeticComputation().addCoordinate(w, status.getRocketPosition());
78                 status.setRocketWorldPosition(w);
79                 
80
81                 // Store data
82                 FlightDataBranch data = status.getFlightData();
83                 boolean extra = status.getSimulationConditions().isCalculateExtras();
84                 data.addPoint();
85                 
86                 data.setValue(FlightDataType.TYPE_TIME, status.getSimulationTime());
87                 data.setValue(FlightDataType.TYPE_ALTITUDE, status.getRocketPosition().z);
88                 data.setValue(FlightDataType.TYPE_POSITION_X, status.getRocketPosition().x);
89                 data.setValue(FlightDataType.TYPE_POSITION_Y, status.getRocketPosition().y);
90                 if (extra) {
91                         data.setValue(FlightDataType.TYPE_POSITION_XY,
92                                         MathUtil.hypot(status.getRocketPosition().x, status.getRocketPosition().y));
93                         data.setValue(FlightDataType.TYPE_POSITION_DIRECTION,
94                                         Math.atan2(status.getRocketPosition().y, status.getRocketPosition().x));
95                         
96                         data.setValue(FlightDataType.TYPE_VELOCITY_XY,
97                                         MathUtil.hypot(status.getRocketVelocity().x, status.getRocketVelocity().y));
98                         data.setValue(FlightDataType.TYPE_ACCELERATION_XY,
99                                         MathUtil.hypot(linearAcceleration.x, linearAcceleration.y));
100                         
101                         data.setValue(FlightDataType.TYPE_ACCELERATION_TOTAL, linearAcceleration.length());
102                         
103                         double Re = airSpeed.length() *
104                                         status.getConfiguration().getLength() /
105                                         atmosphere.getKinematicViscosity();
106                         data.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Re);
107                 }
108                 
109
110                 data.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad());
111                 data.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad());
112                 data.setValue(FlightDataType.TYPE_GRAVITY, gravity);
113                 
114                 if (status.getSimulationConditions().getGeodeticComputation() != GeodeticComputationStrategy.FLAT) {
115                         data.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, coriolisAcceleration.length());
116                 }
117                 
118
119                 data.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z);
120                 data.setValue(FlightDataType.TYPE_ACCELERATION_Z, linearAcceleration.z);
121                 
122                 data.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, airSpeed.length());
123                 data.setValue(FlightDataType.TYPE_MACH_NUMBER, mach);
124                 
125                 data.setValue(FlightDataType.TYPE_MASS, mass);
126                 data.setValue(FlightDataType.TYPE_PROPELLANT_MASS, 0.0); // Is this a reasonable assumption? Probably.
127                 
128                 data.setValue(FlightDataType.TYPE_THRUST_FORCE, 0);
129                 data.setValue(FlightDataType.TYPE_DRAG_FORCE, dragForce);
130                 
131                 data.setValue(FlightDataType.TYPE_WIND_VELOCITY, windSpeed.length());
132                 data.setValue(FlightDataType.TYPE_AIR_TEMPERATURE, atmosphere.getTemperature());
133                 data.setValue(FlightDataType.TYPE_AIR_PRESSURE, atmosphere.getPressure());
134                 data.setValue(FlightDataType.TYPE_SPEED_OF_SOUND, atmosphere.getMachSpeed());
135                 
136                 data.setValue(FlightDataType.TYPE_TIME_STEP, timeStep);
137                 data.setValue(FlightDataType.TYPE_COMPUTATION_TIME,
138                                 (System.nanoTime() - status.getSimulationStartWallTime()) / 1000000000.0);
139         }
140         
141 }