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.rocketcomponent.Configuration;
9 import net.sf.openrocket.rocketcomponent.RocketComponent;
10 import net.sf.openrocket.simulation.exception.SimulationException;
11 import net.sf.openrocket.simulation.listeners.SimulationListenerHelper;
12 import net.sf.openrocket.util.BugException;
13 import net.sf.openrocket.util.Coordinate;
14 import net.sf.openrocket.util.Quaternion;
16 public abstract class AbstractSimulationStepper implements SimulationStepper {
19 * Compute the atmospheric conditions, allowing listeners to override.
21 * @param status the simulation status
22 * @return the atmospheric conditions to use
23 * @throws SimulationException if a listener throws SimulationException
25 protected AtmosphericConditions modelAtmosphericConditions(SimulationStatus status) throws SimulationException {
26 AtmosphericConditions conditions;
29 conditions = SimulationListenerHelper.firePreAtmosphericModel(status);
30 if (conditions != null) {
35 double altitude = status.getRocketPosition().z + status.getSimulationConditions().getLaunchSite().getAltitude();
36 conditions = status.getSimulationConditions().getAtmosphericModel().getConditions(altitude);
39 conditions = SimulationListenerHelper.firePostAtmosphericModel(status, conditions);
41 checkNaN(conditions.getPressure());
42 checkNaN(conditions.getTemperature());
50 * Compute the wind to use, allowing listeners to override.
52 * @param status the simulation status
53 * @return the wind conditions to use
54 * @throws SimulationException if a listener throws SimulationException
56 protected Coordinate modelWindVelocity(SimulationStatus status) throws SimulationException {
60 wind = SimulationListenerHelper.firePreWindModel(status);
66 double altitude = status.getRocketPosition().z + status.getSimulationConditions().getLaunchSite().getAltitude();
67 wind = status.getSimulationConditions().getWindModel().getWindVelocity(status.getSimulationTime(), altitude);
70 wind = SimulationListenerHelper.firePostWindModel(status, wind);
80 * Compute the gravity to use, allowing listeners to override.
82 * @param status the simulation status
83 * @return the gravitational acceleration to use
84 * @throws SimulationException if a listener throws SimulationException
86 protected double modelGravity(SimulationStatus status) throws SimulationException {
90 gravity = SimulationListenerHelper.firePreGravityModel(status);
91 if (!Double.isNaN(gravity)) {
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 Configuration configuration = status.getConfiguration();
173 // Iterate over the motors and calculate combined thrust
174 MotorInstanceConfiguration mic = status.getMotorConfiguration();
178 mic.step(status.getSimulationTime() + timestep, acceleration, atmosphericConditions);
180 for (MotorId id : mic.getMotorIDs()) {
181 if (configuration.isComponentActive((RocketComponent) mic.getMotorMount(id))) {
182 MotorInstance motor = mic.getMotorInstance(id);
183 thrust += motor.getThrust();
188 thrust = SimulationListenerHelper.firePostThrustCalculation(status, thrust);
197 * Check that the provided value is not NaN.
199 * @param d the double value to check.
200 * @throws BugException if the value is NaN.
202 protected void checkNaN(double d) {
203 if (Double.isNaN(d)) {
204 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug.");
209 * Check that the provided coordinate is not NaN.
211 * @param c the coordinate value to check.
212 * @throws BugException if the value is NaN.
214 protected void checkNaN(Coordinate c) {
216 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug, c=" + c);
222 * Check that the provided quaternion is not NaN.
224 * @param q the quaternion value to check.
225 * @throws BugException if the value is NaN.
227 protected void checkNaN(Quaternion q) {
229 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug, q=" + q);