diff --git a/core/src/net/sf/openrocket/document/Simulation.java b/core/src/net/sf/openrocket/document/Simulation.java index 81091ff17..f2f0780d5 100644 --- a/core/src/net/sf/openrocket/document/Simulation.java +++ b/core/src/net/sf/openrocket/document/Simulation.java @@ -1,5 +1,6 @@ package net.sf.openrocket.document; +import java.util.Collection; import java.util.EventListener; import java.util.EventObject; import java.util.List; @@ -281,10 +282,9 @@ public class Simulation implements ChangeSource, Cloneable { } FlightConfiguration config = rocket.getFlightConfiguration(options.getId()); - List motorList = config.getActiveMotors(); - + //Make sure this simulation has motors. - if (0 == motorList.size()){ + if ( ! config.hasMotors() ){ status = Status.CANT_RUN; } @@ -337,14 +337,11 @@ public class Simulation implements ChangeSource, Cloneable { // Set simulated info after simulation, will not be set in case of exception simulatedConditions = options.clone(); - final FlightConfiguration configuration = this.rocket.getFlightConfiguration( options.getId()); - - simulatedConfigurationDescription = descriptor.format(configuration.getRocket(), configuration.getFlightConfigurationID()); + simulatedConfigurationDescription = descriptor.format( this.rocket, options.getId()); simulatedRocketID = rocket.getFunctionalModID(); status = Status.UPTODATE; fireChangeEvent(); - configuration.release(); } finally { mutex.unlock("simulate"); } diff --git a/core/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java b/core/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java index 5bf50a513..eec02a8ec 100644 --- a/core/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java +++ b/core/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java @@ -300,7 +300,7 @@ public abstract class BaseHandler extends AbstractEle * * @return the Method instance, or null */ - private static Method getMethod(RocketComponent component, String name, Class[] args) { + private static Method getMethod(RocketComponent component, String name, Class[] args) { Method method = null; try { method = component.getClass().getMethod(name, args); diff --git a/core/src/net/sf/openrocket/motor/MotorInstance.java b/core/src/net/sf/openrocket/motor/MotorInstance.java index b63598828..59797f96d 100644 --- a/core/src/net/sf/openrocket/motor/MotorInstance.java +++ b/core/src/net/sf/openrocket/motor/MotorInstance.java @@ -155,7 +155,7 @@ public abstract class MotorInstance implements FlightConfigurableParameter= prevTime)) { - // Also catches NaN - throw new IllegalArgumentException("Stepping backwards in time, current=" + - prevTime + " new=" + nextTime); - } if (MathUtil.equals(prevTime, nextTime)) { return; } @@ -241,11 +230,37 @@ public class ThrustCurveMotorInstance extends MotorInstance { clone.ignitionDelay = this.ignitionDelay; clone.ejectionDelay = this.ejectionDelay; clone.position = this.position; - this.ignitionTime = Double.POSITIVE_INFINITY; + clone.ignitionTime = Double.POSITIVE_INFINITY; + //clone.ignitionTime = this.ignitionTime; return clone; } + @Override + public void reset(){ + timeIndex = 0; + prevTime = 0; + instThrust = 0; + stepThrust = 0; + instCG = motor.getLaunchCG(); + stepCG = instCG; + } + + @Override + public String toDebug(){ + String prefix = " "; + StringBuilder sb = new StringBuilder(); + final RocketComponent mountComp = (RocketComponent)this.mount; + + sb.append(String.format("%sMotor= %s(%s)(in %s)\n", prefix, this.motor.getDesignation(), this.id.toShortKey(), mountComp.getName())); + sb.append(String.format("%s Ignite: %s at %+f\n",prefix, this.ignitionEvent.name, this.ignitionDelay)); + //sb.append(String.format("%s Eject at: %+f\n",prefix, this.ejectionDelay)); + sb.append(String.format("%s L:%f W:%f @:%f mm\n",prefix, motor.getLength(), motor.getDiameter(), this.position.multiply(1000).x )); + sb.append(String.format("%s currentTimem: %f\n", prefix, this.prevTime)); + sb.append("\n"); + return sb.toString(); + } + @Override public String toString(){ return this.id.toString(); diff --git a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java index 6d8e35602..bbc9cd2a0 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FlightConfiguration.java @@ -5,7 +5,6 @@ import java.util.Collection; import java.util.EventListener; import java.util.EventObject; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Queue; @@ -14,7 +13,6 @@ import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import net.sf.openrocket.models.atmosphere.AtmosphericConditions; import net.sf.openrocket.motor.MotorInstance; import net.sf.openrocket.motor.MotorInstanceId; import net.sf.openrocket.util.ArrayList; @@ -68,8 +66,6 @@ public class FlightConfiguration implements FlightConfigurableParameterRocket. * @@ -91,10 +87,6 @@ public class FlightConfiguration implements FlightConfigurableParameter \n", curMotor.getID().toShortKey())); @@ -490,21 +479,7 @@ public class FlightConfiguration implements FlightConfigurableParameter= 0) { - inst.step(t, acceleration, cond); - } - } - modID++; - } - - public List getActiveMotors() { + public Collection getActiveMotors() { List activeList = new ArrayList(); for( MotorInstance inst : this.motors.values() ){ if( inst.isActive() ){ @@ -516,47 +491,35 @@ public class FlightConfiguration implements FlightConfigurableParameter motor.refpoint - Coordinate curMotorOffset = curInstance.getOffset(); - curInstance.setPosition( curMountLocation.add(curMotorOffset) ); - this.motors.put( curInstance.getID(), curInstance); - - // vvvv DEVEL vvvv - if(debug){ - System.err.println(String.format(",,,,,,,, [%2d/%2d]: %s. (%s)", - instanceNumber, instanceCount, curInstance.getMotor().getDigest(), curInstance)); - } - // ^^^^ DEVEL ^^^^ - instanceNumber ++; + MotorInstance cloneInstance = sourceInstance.clone(); + cloneInstance.setID( new MotorInstanceId( compMount.getName(), instanceNumber) ); + + // motor location w/in mount: parent.refpoint -> motor.refpoint + Coordinate curMotorOffset = cloneInstance.getOffset(); + cloneInstance.setPosition( curMountLocation.add(curMotorOffset) ); + this.motors.put( cloneInstance.getID(), cloneInstance); + + instanceNumber ++; } } @@ -629,7 +592,9 @@ public class FlightConfiguration implements FlightConfigurableParameter(); clone.stages.putAll( (Map) this.stages); - clone.motors.putAll( (Map) this.motors); + for( MotorInstance mi : this.motors.values()){ + clone.motors.put( mi.getID(), mi.clone()); + } clone.cachedBounds = this.cachedBounds.clone(); clone.modID = this.modID; clone.boundsModID = -1; @@ -662,5 +627,5 @@ public class FlightConfiguration implements FlightConfigurableParameter activeMotors = configuration.getActiveMotors(); - for (MotorInstance currentMotorInstance : activeMotors) { + final double currentTime = status.getSimulationTime() + timestep; + Collection activeMotorList = status.getConfiguration().getActiveMotors(); + for (MotorInstance currentMotorInstance : activeMotorList ) { + // old: transplanted from MotorInstanceConfiguration + double instanceTime = currentTime - currentMotorInstance.getIgnitionTime(); + if (instanceTime >= 0) { + currentMotorInstance.step(instanceTime, acceleration, atmosphericConditions); + } + + // old: from here thrust += currentMotorInstance.getThrust(); } diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java index 83d94189a..061edbb42 100644 --- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java +++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java @@ -1,8 +1,8 @@ package net.sf.openrocket.simulation; import java.util.ArrayDeque; +import java.util.Collection; import java.util.Deque; -import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,15 +56,9 @@ public class BasicEventSimulationEngine implements SimulationEngine { private FlightConfigurationID fcid; - // old: protected Stack stages = new Stack(); - // this variable was class member stack, but parallel staging breaks metaphor: - // parallel stages may ignite before OR after their 'inner' stages - - // this is just a list of simulation branches to Deque toSimulate = new ArrayDeque(); - @Override public FlightData simulate(SimulationConditions simulationConditions) throws SimulationException { @@ -72,21 +66,17 @@ public class BasicEventSimulationEngine implements SimulationEngine { FlightData flightData = new FlightData(); // Set up rocket configuration - this.fcid = simulationConditions.getConfigurationID(); - FlightConfiguration configuration = simulationConditions.getRocket().getFlightConfiguration( this.fcid); - - List activeMotors = configuration.getActiveMotors(); - if ( activeMotors.isEmpty() ) { - final String errorMessage = trans.get("BasicEventSimulationEngine.error.noMotorsDefined"); - log.info(errorMessage); - throw new MotorIgnitionException(errorMessage); + this.fcid = simulationConditions.getFlightConfigurationID(); + FlightConfiguration simulationConfig = simulationConditions.getRocket().getFlightConfiguration( this.fcid).clone(); + if ( ! simulationConfig.hasMotors() ) { + throw new MotorIgnitionException(trans.get("BasicEventSimulationEngine.error.noMotorsDefined")); } - currentStatus = new SimulationStatus(configuration, simulationConditions); + currentStatus = new SimulationStatus(simulationConfig, simulationConditions); currentStatus.getEventQueue().add(new FlightEvent(FlightEvent.Type.LAUNCH, 0, simulationConditions.getRocket())); { // main simulation branch - final String branchName = configuration.getRocket().getTopmostStage().getName(); + final String branchName = simulationConfig.getRocket().getTopmostStage().getName(); currentStatus.setFlightData(new FlightDataBranch( branchName, FlightDataType.TYPE_TIME)); } toSimulate.add(currentStatus); @@ -103,19 +93,18 @@ public class BasicEventSimulationEngine implements SimulationEngine { flightData.addBranch(dataBranch); flightData.getWarningSet().addAll(currentStatus.getWarnings()); - log.info(String.format("<> Starting simulate loop.")); // Start the simulation while (handleEvents()) { - log.info(String.format(" >> Events Handled.")); - // Take the step double oldAlt = currentStatus.getRocketPosition().z; @@ -286,7 +272,6 @@ public class BasicEventSimulationEngine implements SimulationEngine { log.trace("BasicEventSimulationEngine: Handling event " + event); } - log.trace(String.format(" >> about to ignite motors events")); if (event.getType() == FlightEvent.Type.IGNITION) { MotorMount mount = (MotorMount) event.getSource(); MotorInstanceId motorId = (MotorInstanceId) event.getData(); @@ -295,7 +280,6 @@ public class BasicEventSimulationEngine implements SimulationEngine { continue; } } - log.trace(String.format(" >> about to fire motors (?) events")); if (event.getType() == FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT) { RecoveryDevice device = (RecoveryDevice) event.getSource(); if (!SimulationListenerHelper.fireRecoveryDeviceDeployment(currentStatus, device)) { @@ -303,8 +287,6 @@ public class BasicEventSimulationEngine implements SimulationEngine { } } - log.trace(String.format(" >> about to check for motors ignite events")); - // Check for motor ignition events, add ignition events to queue for (MotorInstance motor : currentStatus.getFlightConfiguration().getActiveMotors() ){ MotorInstanceId mid = motor.getID(); @@ -322,7 +304,6 @@ public class BasicEventSimulationEngine implements SimulationEngine { // Check for stage separation event - for (AxialStage stage : currentStatus.getConfiguration().getActiveStages()) { int stageNo = stage.getStageNumber(); if (stageNo == 0) @@ -348,8 +329,6 @@ public class BasicEventSimulationEngine implements SimulationEngine { } } - log.trace(String.format(" >> about to handle events")); - // Handle event switch (event.getType()) { @@ -445,7 +424,7 @@ public class BasicEventSimulationEngine implements SimulationEngine { // TODO: HIGH: Check stage activeness for other events as well? // Check whether any motor in the active stages is active anymore - List activeMotors = currentStatus.getConfiguration().getActiveMotors(); + Collection activeMotors = currentStatus.getConfiguration().getActiveMotors(); for (MotorInstance curMotor : activeMotors) { RocketComponent comp = ((RocketComponent) curMotor.getMount()); int stageNumber = comp.getStageNumber(); @@ -471,6 +450,7 @@ public class BasicEventSimulationEngine implements SimulationEngine { // to determine the optimum altitude. if (currentStatus.getSimulationConditions().isCalculateExtras() && !currentStatus.isApogeeReached()) { FlightData coastStatus = computeCoastTime(); + currentStatus.getFlightData().setOptimumAltitude(coastStatus.getMaxAltitude()); currentStatus.getFlightData().setTimeToOptimumAltitude(coastStatus.getTimeToApogee()); } @@ -580,7 +560,14 @@ public class BasicEventSimulationEngine implements SimulationEngine { SimulationConditions conds = currentStatus.getSimulationConditions().clone(); conds.getSimulationListenerList().add(OptimumCoastListener.INSTANCE); BasicEventSimulationEngine e = new BasicEventSimulationEngine(); - +// log.error(" cloned simConditions: "+conds.toString() +// +" ... "+conds.getRocket().getName() +// +" ... "+conds.getFlightConfigurationID().toShortKey()); +// FlightConfigurationID dbid = conds.getFlightConfigurationID(); +// FlightConfiguration cloneConfig = conds.getRocket().getFlightConfiguration( dbid ); +// System.err.println(" configId: "+dbid.toShortKey()); +// System.err.println(" motors detail: "+cloneConfig.toMotorDetail()); + FlightData d = e.simulate(conds); return d; } catch (Exception e) { diff --git a/core/src/net/sf/openrocket/simulation/RK4SimulationStepper.java b/core/src/net/sf/openrocket/simulation/RK4SimulationStepper.java index 9dee82d4e..1200f331c 100644 --- a/core/src/net/sf/openrocket/simulation/RK4SimulationStepper.java +++ b/core/src/net/sf/openrocket/simulation/RK4SimulationStepper.java @@ -265,6 +265,10 @@ public class RK4SimulationStepper extends AbstractSimulationStepper { w = status.getSimulationConditions().getGeodeticComputation().addCoordinate(w, status.getRocketPosition()); status.setRocketWorldPosition(w); + if (!(0 <= store.timestep)) { + // Also catches NaN + throw new IllegalArgumentException("Stepping backwards in time, timestep=" +store.timestep); + } status.setSimulationTime(status.getSimulationTime() + store.timestep); status.setPreviousTimeStep(store.timestep); diff --git a/core/src/net/sf/openrocket/simulation/SimulationConditions.java b/core/src/net/sf/openrocket/simulation/SimulationConditions.java index 24297b431..4f6d75fdb 100644 --- a/core/src/net/sf/openrocket/simulation/SimulationConditions.java +++ b/core/src/net/sf/openrocket/simulation/SimulationConditions.java @@ -28,7 +28,7 @@ import net.sf.openrocket.util.WorldCoordinate; public class SimulationConditions implements Monitorable, Cloneable { private Rocket rocket; - private FlightConfigurationID configID= null; + private FlightConfigurationID configId= null; private Simulation simulation; // The parent simulation @@ -116,15 +116,15 @@ public class SimulationConditions implements Monitorable, Cloneable { public FlightConfigurationID getMotorConfigurationID() { - return configID; + return configId; } - public FlightConfigurationID getConfigurationID() { - return configID; + public FlightConfigurationID getFlightConfigurationID() { + return configId; } public void setFlightConfigurationID(FlightConfigurationID _fcid) { - this.configID = _fcid; + this.configId = _fcid; this.modID++; } @@ -327,6 +327,9 @@ public class SimulationConditions implements Monitorable, Cloneable { for (SimulationListener listener : this.simulationListeners) { clone.simulationListeners.add(listener.clone()); } + clone.rocket = this.rocket; // the rocket should be read-only from this point + clone.configId = this.configId; // configIds are read-only + return clone; } catch (CloneNotSupportedException e) { throw new BugException(e); diff --git a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java index cb859ca54..25e9c8aa4 100644 --- a/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java +++ b/swing/src/net/sf/openrocket/gui/main/flightconfigpanel/MotorConfigurationPanel.java @@ -19,6 +19,9 @@ import javax.swing.SwingUtilities; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import net.miginfocom.swing.MigLayout; import net.sf.openrocket.gui.components.StyledLabel; import net.sf.openrocket.gui.components.StyledLabel.Style; @@ -35,9 +38,8 @@ import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.util.Chars; public class MotorConfigurationPanel extends FlightConfigurablePanel { - private static final long serialVersionUID = -5046535300435793744L; - + private static final String NONE = trans.get("edtmotorconfdlg.tbl.None"); private final JButton selectMotorButton, removeMotorButton, selectIgnitionButton, resetIgnitionButton; @@ -250,13 +252,12 @@ public class MotorConfigurationPanel extends FlightConfigurablePanel return; } + // this call also performs the update changes IgnitionSelectionDialog ignitionDialog = new IgnitionSelectionDialog( SwingUtilities.getWindowAncestor(this.flightConfigurationPanel), fcid, curMount); ignitionDialog.setVisible(true); - - // changes performed automatically within "new IgnitionSelectionDialog(...)" fireTableDataChanged(); }