private FlightDataBranch simulateLoop() {

    // Initialize the simulation
    currentStepper = flightStepper;
    currentStatus = currentStepper.initialize(currentStatus);

    // Get originating position (in case listener has modified launch position)
    Coordinate origin = currentStatus.getRocketPosition();
    Coordinate originVelocity = currentStatus.getRocketVelocity();

    try {

      // Start the simulation
      while (handleEvents()) {
        // Take the step
        double oldAlt = currentStatus.getRocketPosition().z;

        if (SimulationListenerHelper.firePreStep(currentStatus)) {
          // Step at most to the next event
          double maxStepTime = Double.MAX_VALUE;
          FlightEvent nextEvent = currentStatus.getEventQueue().peek();
          if (nextEvent != null) {
            maxStepTime =
                MathUtil.max(nextEvent.getTime() - currentStatus.getSimulationTime(), 0.001);
          }
          log.trace(
              "BasicEventSimulationEngine: Taking simulation step at t="
                  + currentStatus.getSimulationTime());
          currentStepper.step(currentStatus, maxStepTime);
        }
        SimulationListenerHelper.firePostStep(currentStatus);

        // Check for NaN values in the simulation status
        checkNaN();

        // Add altitude event
        addEvent(
            new FlightEvent(
                FlightEvent.Type.ALTITUDE,
                currentStatus.getSimulationTime(),
                currentStatus.getConfiguration().getRocket(),
                new Pair<Double, Double>(oldAlt, currentStatus.getRocketPosition().z)));

        if (currentStatus.getRocketPosition().z > currentStatus.getMaxAlt()) {
          currentStatus.setMaxAlt(currentStatus.getRocketPosition().z);
        }

        // Position relative to start location
        Coordinate relativePosition = currentStatus.getRocketPosition().sub(origin);

        // Add appropriate events
        if (!currentStatus.isLiftoff()) {

          // Avoid sinking into ground before liftoff
          if (relativePosition.z < 0) {
            currentStatus.setRocketPosition(origin);
            currentStatus.setRocketVelocity(originVelocity);
          }
          // Detect lift-off
          if (relativePosition.z > 0.02) {
            addEvent(new FlightEvent(FlightEvent.Type.LIFTOFF, currentStatus.getSimulationTime()));
          }

        } else {

          // Check ground hit after liftoff
          if (currentStatus.getRocketPosition().z < 0) {
            currentStatus.setRocketPosition(currentStatus.getRocketPosition().setZ(0));
            addEvent(
                new FlightEvent(FlightEvent.Type.GROUND_HIT, currentStatus.getSimulationTime()));
            addEvent(
                new FlightEvent(
                    FlightEvent.Type.SIMULATION_END, currentStatus.getSimulationTime()));
          }
        }

        // Check for launch guide clearance
        if (!currentStatus.isLaunchRodCleared()
            && relativePosition.length()
                > currentStatus.getSimulationConditions().getLaunchRodLength()) {
          addEvent(
              new FlightEvent(FlightEvent.Type.LAUNCHROD, currentStatus.getSimulationTime(), null));
        }

        // Check for apogee
        if (!currentStatus.isApogeeReached()
            && currentStatus.getRocketPosition().z < currentStatus.getMaxAlt() - 0.01) {
          currentStatus.setMaxAltTime(currentStatus.getSimulationTime());
          addEvent(
              new FlightEvent(
                  FlightEvent.Type.APOGEE,
                  currentStatus.getSimulationTime(),
                  currentStatus.getConfiguration().getRocket()));
        }

        //				//@Obsolete
        //				//@Redundant
        //				// Check for burnt out motors
        //				for( MotorClusterState state : currentStatus.getActiveMotors()){
        //					if ( state.isSpent()){
        //						addEvent(new FlightEvent(FlightEvent.Type.BURNOUT,
        // currentStatus.getSimulationTime(),
        //								(RocketComponent) state.getMount(), state));
        //					}
        //				}

        // Check for Tumbling
        // Conditions for transision are:
        //  apogee reached (if sustainer stage)
        // and is not already tumbling
        // and not stable (cg > cp)
        // and aoa > AOA_TUMBLE_CONDITION threshold
        // and thrust < THRUST_TUMBLE_CONDITION threshold

        if (!currentStatus.isTumbling()) {
          final double t = currentStatus.getFlightData().getLast(FlightDataType.TYPE_THRUST_FORCE);
          final double cp = currentStatus.getFlightData().getLast(FlightDataType.TYPE_CP_LOCATION);
          final double cg = currentStatus.getFlightData().getLast(FlightDataType.TYPE_CG_LOCATION);
          final double aoa = currentStatus.getFlightData().getLast(FlightDataType.TYPE_AOA);

          final boolean wantToTumble = (cg > cp && aoa > AOA_TUMBLE_CONDITION);

          if (wantToTumble) {
            final boolean tooMuchThrust = t > THRUST_TUMBLE_CONDITION;
            // final boolean isSustainer = status.getConfiguration().isStageActive(0);
            final boolean isApogee = currentStatus.isApogeeReached();
            if (tooMuchThrust) {
              currentStatus.getWarnings().add(Warning.TUMBLE_UNDER_THRUST);
            } else if (isApogee) {
              addEvent(new FlightEvent(FlightEvent.Type.TUMBLE, currentStatus.getSimulationTime()));
              currentStatus.setTumbling(true);
            }
          }
        }
      }

    } catch (SimulationException e) {
      SimulationListenerHelper.fireEndSimulation(currentStatus, e);
      // Add FlightEvent for Abort.
      currentStatus
          .getFlightData()
          .addEvent(
              new FlightEvent(
                  FlightEvent.Type.EXCEPTION,
                  currentStatus.getSimulationTime(),
                  currentStatus.getConfiguration().getRocket(),
                  e.getLocalizedMessage()));
      currentStatus.getWarnings().add(e.getLocalizedMessage());
    }

    return currentStatus.getFlightData();
  }
Пример #2
0
 public void setWindSpeedAverage(double windAverage) {
   if (MathUtil.equals(this.getDouble(WIND_AVERAGE, 2), windAverage)) return;
   this.putDouble(WIND_AVERAGE, MathUtil.max(windAverage, 0));
   fireChangeEvent();
 }
  @Override
  public FlightData simulate(SimulationConditions simulationConditions) throws SimulationException {
    Set<MotorId> motorBurntOut = new HashSet<MotorId>();

    // Set up flight data
    FlightData flightData = new FlightData();

    // Set up rocket configuration
    Configuration configuration = setupConfiguration(simulationConditions);
    MotorInstanceConfiguration motorConfiguration = setupMotorConfiguration(configuration);
    if (motorConfiguration.getMotorIDs().isEmpty()) {
      throw new MotorIgnitionException("No motors defined in the simulation.");
    }

    // Initialize the simulation
    currentStepper = flightStepper;
    status = initialStatus(configuration, motorConfiguration, simulationConditions, flightData);
    status = currentStepper.initialize(status);

    SimulationListenerHelper.fireStartSimulation(status);
    // Get originating position (in case listener has modified launch position)
    Coordinate origin = status.getRocketPosition();
    Coordinate originVelocity = status.getRocketVelocity();

    try {
      double maxAlt = Double.NEGATIVE_INFINITY;

      // Start the simulation
      while (handleEvents()) {

        // Take the step
        double oldAlt = status.getRocketPosition().z;

        if (SimulationListenerHelper.firePreStep(status)) {
          // Step at most to the next event
          double maxStepTime = Double.MAX_VALUE;
          FlightEvent nextEvent = status.getEventQueue().peek();
          if (nextEvent != null) {
            maxStepTime = MathUtil.max(nextEvent.getTime() - status.getSimulationTime(), 0.001);
          }
          log.verbose(
              "BasicEventSimulationEngine: Taking simulation step at t="
                  + status.getSimulationTime());
          currentStepper.step(status, maxStepTime);
        }
        SimulationListenerHelper.firePostStep(status);

        // Calculate values for custom expressions
        FlightDataBranch data = status.getFlightData();
        ArrayList<CustomExpression> allExpressions =
            status.getSimulationConditions().getSimulation().getCustomExpressions();
        for (CustomExpression expression : allExpressions) {
          data.setValue(expression.getType(), expression.evaluate(status));
        }

        // Check for NaN values in the simulation status
        checkNaN();

        // Add altitude event
        addEvent(
            new FlightEvent(
                FlightEvent.Type.ALTITUDE,
                status.getSimulationTime(),
                status.getConfiguration().getRocket(),
                new Pair<Double, Double>(oldAlt, status.getRocketPosition().z)));

        if (status.getRocketPosition().z > maxAlt) {
          maxAlt = status.getRocketPosition().z;
        }

        // Position relative to start location
        Coordinate relativePosition = status.getRocketPosition().sub(origin);

        // Add appropriate events
        if (!status.isLiftoff()) {

          // Avoid sinking into ground before liftoff
          if (relativePosition.z < 0) {
            status.setRocketPosition(origin);
            status.setRocketVelocity(originVelocity);
          }
          // Detect lift-off
          if (relativePosition.z > 0.02) {
            addEvent(new FlightEvent(FlightEvent.Type.LIFTOFF, status.getSimulationTime()));
          }

        } else {

          // Check ground hit after liftoff
          if (status.getRocketPosition().z < 0) {
            status.setRocketPosition(status.getRocketPosition().setZ(0));
            addEvent(new FlightEvent(FlightEvent.Type.GROUND_HIT, status.getSimulationTime()));
            addEvent(new FlightEvent(FlightEvent.Type.SIMULATION_END, status.getSimulationTime()));
          }
        }

        // Check for launch guide clearance
        if (!status.isLaunchRodCleared()
            && relativePosition.length() > status.getSimulationConditions().getLaunchRodLength()) {
          addEvent(new FlightEvent(FlightEvent.Type.LAUNCHROD, status.getSimulationTime(), null));
        }

        // Check for apogee
        if (!status.isApogeeReached() && status.getRocketPosition().z < maxAlt - 0.01) {
          addEvent(
              new FlightEvent(
                  FlightEvent.Type.APOGEE,
                  status.getSimulationTime(),
                  status.getConfiguration().getRocket()));
        }

        // Check for burnt out motors
        for (MotorId motorId : status.getMotorConfiguration().getMotorIDs()) {
          MotorInstance motor = status.getMotorConfiguration().getMotorInstance(motorId);
          if (!motor.isActive() && motorBurntOut.add(motorId)) {
            addEvent(
                new FlightEvent(
                    FlightEvent.Type.BURNOUT,
                    status.getSimulationTime(),
                    (RocketComponent) status.getMotorConfiguration().getMotorMount(motorId),
                    motorId));
          }
        }
      }

    } catch (SimulationException e) {
      SimulationListenerHelper.fireEndSimulation(status, e);
      throw e;
    }

    SimulationListenerHelper.fireEndSimulation(status, null);

    flightData.addBranch(status.getFlightData());

    if (!flightData.getWarningSet().isEmpty()) {
      log.info("Warnings at the end of simulation:  " + flightData.getWarningSet());
    }

    // TODO: HIGH: Simulate branches
    return flightData;
  }