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().getLaunchSite().getAltitude();
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().getLaunchSite().getAltitude();
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);
96 gravity = status.getSimulationConditions().getGravityModel().getGravity(status.getRocketWorldPosition());
99 gravity = SimulationListenerHelper.firePostGravityModel(status, gravity);
109 * Compute the mass data to use, allowing listeners to override.
111 * @param status the simulation status
112 * @return the mass data to use
113 * @throws SimulationException if a listener throws SimulationException
115 protected MassData calculateMassData(SimulationStatus status) throws SimulationException {
118 double longitudinalInertia, rotationalInertia;
121 mass = SimulationListenerHelper.firePreMassCalculation(status);
126 MassCalculator calc = status.getSimulationConditions().getMassCalculator();
127 cg = calc.getCG(status.getConfiguration(), status.getMotorConfiguration());
128 longitudinalInertia = calc.getLongitudinalInertia(status.getConfiguration(), status.getMotorConfiguration());
129 rotationalInertia = calc.getRotationalInertia(status.getConfiguration(), status.getMotorConfiguration());
130 mass = new MassData(cg, longitudinalInertia, rotationalInertia);
132 // Call post-listener
133 mass = SimulationListenerHelper.firePostMassCalculation(status, mass);
135 checkNaN(mass.getCG());
136 checkNaN(mass.getLongitudinalInertia());
137 checkNaN(mass.getRotationalInertia());
147 * Calculate the average thrust produced by the motors in the current configuration, allowing
148 * listeners to override. The average is taken between <code>status.time</code> and
149 * <code>status.time + timestep</code>.
151 * TODO: HIGH: This method does not take into account any moments generated by off-center motors.
153 * @param status the current simulation status.
154 * @param timestep the time step of the current iteration.
155 * @param acceleration the current (approximate) acceleration
156 * @param atmosphericConditions the current atmospheric conditions
157 * @param stepMotors whether to step the motors forward or work on a clone object
158 * @return the average thrust during the time step.
160 protected double calculateThrust(SimulationStatus status, double timestep,
161 double acceleration, AtmosphericConditions atmosphericConditions,
162 boolean stepMotors) throws SimulationException {
166 thrust = SimulationListenerHelper.firePreThrustCalculation(status);
167 if (!Double.isNaN(thrust)) {
171 // Iterate over the motors and calculate combined thrust
172 MotorInstanceConfiguration configuration = status.getMotorConfiguration();
174 configuration = configuration.clone();
176 configuration.step(status.getSimulationTime() + timestep, acceleration, atmosphericConditions);
178 for (MotorId id : configuration.getMotorIDs()) {
179 MotorInstance motor = configuration.getMotorInstance(id);
180 thrust += motor.getThrust();
184 thrust = SimulationListenerHelper.firePostThrustCalculation(status, thrust);
193 * Check that the provided value is not NaN.
195 * @param d the double value to check.
196 * @throws BugException if the value is NaN.
198 protected void checkNaN(double d) {
199 if (Double.isNaN(d)) {
200 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug.");
205 * Check that the provided coordinate is not NaN.
207 * @param c the coordinate value to check.
208 * @throws BugException if the value is NaN.
210 protected void checkNaN(Coordinate c) {
212 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug, c=" + c);
218 * Check that the provided quaternion is not NaN.
220 * @param q the quaternion value to check.
221 * @throws BugException if the value is NaN.
223 protected void checkNaN(Quaternion q) {
225 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug, q=" + q);