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 //double altitude = status.getRocketPosition().z + status.getSimulationConditions().getLaunchAltitude();
97 //gravity = status.getSimulationConditions().getGravityModel().getGravity(altitude);
98 gravity = status.getSimulationConditions().getGravityModel().getGravity(status.getRocketWorldPosition());
100 // Call post-listener
101 gravity = SimulationListenerHelper.firePostGravityModel(status, gravity);
111 * Compute the mass data to use, allowing listeners to override.
113 * @param status the simulation status
114 * @return the mass data to use
115 * @throws SimulationException if a listener throws SimulationException
117 protected MassData calculateMassData(SimulationStatus status) throws SimulationException {
120 double longitudinalInertia, rotationalInertia;
123 mass = SimulationListenerHelper.firePreMassCalculation(status);
128 MassCalculator calc = status.getSimulationConditions().getMassCalculator();
129 cg = calc.getCG(status.getConfiguration(), status.getMotorConfiguration());
130 longitudinalInertia = calc.getLongitudinalInertia(status.getConfiguration(), status.getMotorConfiguration());
131 rotationalInertia = calc.getRotationalInertia(status.getConfiguration(), status.getMotorConfiguration());
132 mass = new MassData(cg, longitudinalInertia, rotationalInertia);
134 // Call post-listener
135 mass = SimulationListenerHelper.firePostMassCalculation(status, mass);
137 checkNaN(mass.getCG());
138 checkNaN(mass.getLongitudinalInertia());
139 checkNaN(mass.getRotationalInertia());
149 * Calculate the average thrust produced by the motors in the current configuration, allowing
150 * listeners to override. The average is taken between <code>status.time</code> and
151 * <code>status.time + timestep</code>.
153 * TODO: HIGH: This method does not take into account any moments generated by off-center motors.
155 * @param status the current simulation status.
156 * @param timestep the time step of the current iteration.
157 * @param acceleration the current (approximate) acceleration
158 * @param atmosphericConditions the current atmospheric conditions
159 * @param stepMotors whether to step the motors forward or work on a clone object
160 * @return the average thrust during the time step.
162 protected double calculateThrust(SimulationStatus status, double timestep,
163 double acceleration, AtmosphericConditions atmosphericConditions,
164 boolean stepMotors) throws SimulationException {
168 thrust = SimulationListenerHelper.firePreThrustCalculation(status);
169 if (!Double.isNaN(thrust)) {
173 Configuration configuration = status.getConfiguration();
175 // Iterate over the motors and calculate combined thrust
176 MotorInstanceConfiguration mic = status.getMotorConfiguration();
180 mic.step(status.getSimulationTime() + timestep, acceleration, atmosphericConditions);
182 for (MotorId id : mic.getMotorIDs()) {
183 if (configuration.isComponentActive((RocketComponent) mic.getMotorMount(id))) {
184 MotorInstance motor = mic.getMotorInstance(id);
185 thrust += motor.getThrust();
190 thrust = SimulationListenerHelper.firePostThrustCalculation(status, thrust);
199 * Check that the provided value is not NaN.
201 * @param d the double value to check.
202 * @throws BugException if the value is NaN.
204 protected void checkNaN(double d) {
205 if (Double.isNaN(d)) {
206 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug.");
211 * Check that the provided coordinate is not NaN.
213 * @param c the coordinate value to check.
214 * @throws BugException if the value is NaN.
216 protected void checkNaN(Coordinate c) {
218 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug, c=" + c);
224 * Check that the provided quaternion is not NaN.
226 * @param q the quaternion value to check.
227 * @throws BugException if the value is NaN.
229 protected void checkNaN(Quaternion q) {
231 throw new BugException("Simulation resulted in not-a-number (NaN) value, please report a bug, q=" + q);