1 package net.sf.openrocket.simulation;
3 import net.sf.openrocket.masscalc.MassCalculator;
4 import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
5 import net.sf.openrocket.motor.MotorId;
6 import net.sf.openrocket.motor.MotorInstance;
7 import net.sf.openrocket.motor.MotorInstanceConfiguration;
8 import net.sf.openrocket.simulation.exception.SimulationException;
9 import net.sf.openrocket.simulation.listeners.SimulationListenerHelper;
10 import net.sf.openrocket.util.BugException;
11 import net.sf.openrocket.util.Coordinate;
12 import net.sf.openrocket.util.Quaternion;
14 public abstract class AbstractSimulationStepper implements SimulationStepper {
17 * Compute the atmospheric conditions, allowing listeners to override.
19 * @param status the simulation status
20 * @return the atmospheric conditions to use
21 * @throws SimulationException if a listener throws SimulationException
23 protected AtmosphericConditions modelAtmosphericConditions(SimulationStatus status) throws SimulationException {
24 AtmosphericConditions conditions;
27 conditions = SimulationListenerHelper.firePreAtmosphericModel(status);
28 if (conditions != null) {
33 double altitude = status.getRocketPosition().z + status.getSimulationConditions().getLaunchAltitude();
34 conditions = status.getSimulationConditions().getAtmosphericModel().getConditions(altitude);
37 conditions = SimulationListenerHelper.firePostAtmosphericModel(status, conditions);
39 checkNaN(conditions.getPressure());
40 checkNaN(conditions.getTemperature());
48 * Compute the wind to use, allowing listeners to override.
50 * @param status the simulation status
51 * @return the wind conditions to use
52 * @throws SimulationException if a listener throws SimulationException
54 protected Coordinate modelWindVelocity(SimulationStatus status) throws SimulationException {
58 wind = SimulationListenerHelper.firePreWindModel(status);
64 double altitude = status.getRocketPosition().z + status.getSimulationConditions().getLaunchAltitude();
65 wind = status.getSimulationConditions().getWindModel().getWindVelocity(status.getSimulationTime(), altitude);
68 wind = SimulationListenerHelper.firePostWindModel(status, wind);
78 * Compute the gravity to use, allowing listeners to override.
80 * @param status the simulation status
81 * @return the gravitational acceleration to use
82 * @throws SimulationException if a listener throws SimulationException
84 protected double modelGravity(SimulationStatus status) throws SimulationException {
88 gravity = SimulationListenerHelper.firePreGravityModel(status);
89 if (!Double.isNaN(gravity)) {
94 double altitude = status.getRocketPosition().z + status.getSimulationConditions().getLaunchAltitude();
95 gravity = status.getSimulationConditions().getGravityModel().getGravity(altitude);
98 gravity = SimulationListenerHelper.firePostGravityModel(status, gravity);
108 * Compute the mass data to use, allowing listeners to override.
110 * @param status the simulation status
111 * @return the mass data to use
112 * @throws SimulationException if a listener throws SimulationException
114 protected MassData calculateMassData(SimulationStatus status) throws SimulationException {
117 double longitudinalInertia, rotationalInertia;
120 mass = SimulationListenerHelper.firePreMassCalculation(status);
125 MassCalculator calc = status.getSimulationConditions().getMassCalculator();
126 cg = calc.getCG(status.getConfiguration(), status.getMotorConfiguration());
127 longitudinalInertia = calc.getLongitudinalInertia(status.getConfiguration(), status.getMotorConfiguration());
128 rotationalInertia = calc.getRotationalInertia(status.getConfiguration(), status.getMotorConfiguration());
129 mass = new MassData(cg, longitudinalInertia, rotationalInertia);
131 // Call post-listener
132 mass = SimulationListenerHelper.firePostMassCalculation(status, mass);
134 checkNaN(mass.getCG());
135 checkNaN(mass.getLongitudinalInertia());
136 checkNaN(mass.getRotationalInertia());
146 * Calculate the average thrust produced by the motors in the current configuration, allowing
147 * listeners to override. The average is taken between <code>status.time</code> and
148 * <code>status.time + timestep</code>.
150 * TODO: HIGH: This method does not take into account any moments generated by off-center motors.
152 * @param status the current simulation status.
153 * @param timestep the time step of the current iteration.
154 * @param acceleration the current (approximate) acceleration
155 * @param atmosphericConditions the current atmospheric conditions
156 * @param stepMotors whether to step the motors forward or work on a clone object
157 * @return the average thrust during the time step.
159 protected double calculateThrust(SimulationStatus status, double timestep,
160 double acceleration, AtmosphericConditions atmosphericConditions,
161 boolean stepMotors) throws SimulationException {
165 thrust = SimulationListenerHelper.firePreThrustCalculation(status);
166 if (!Double.isNaN(thrust)) {
170 // Iterate over the motors and calculate combined thrust
171 MotorInstanceConfiguration configuration = status.getMotorConfiguration();
173 configuration = configuration.clone();
175 configuration.step(status.getSimulationTime() + timestep, acceleration, atmosphericConditions);
177 for (MotorId id : configuration.getMotorIDs()) {
178 MotorInstance motor = configuration.getMotorInstance(id);
179 thrust += motor.getThrust();
183 thrust = SimulationListenerHelper.firePostThrustCalculation(status, thrust);
192 * Check that the provided value is not NaN.
194 * @param d the double value to check.
195 * @throws BugException if the value is NaN.
197 protected void checkNaN(double d) {
198 if (Double.isNaN(d)) {
199 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug.");
204 * Check that the provided coordinate is not NaN.
206 * @param c the coordinate value to check.
207 * @throws BugException if the value is NaN.
209 protected void checkNaN(Coordinate c) {
211 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug.");
217 * Check that the provided quaternion is not NaN.
219 * @param q the quaternion value to check.
220 * @throws BugException if the value is NaN.
222 protected void checkNaN(Quaternion q) {
224 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug.");