@Override public void optimize(Point initial, OptimizationController control) throws OptimizationException { if (initial.dim() != 1) { throw new IllegalArgumentException( "Only single-dimensional optimization supported, dim=" + initial.dim()); } log.info("Starting golden section search for optimization"); Point guessAC = null; Point guessBD = null; try { boolean guessedAC; Point previous = p(0); double previousValue = Double.NaN; current = previous; double currentValue = Double.NaN; /* * Initialize the points + computation. */ Point a = p(0); Point d = p(1.0); Point b = section1(a, d); Point c = section2(a, d); functionExecutor.compute(a); functionExecutor.compute(d); functionExecutor.compute(b); functionExecutor.compute(c); // Wait for points a and d, which normally are already precomputed functionExecutor.waitFor(a); functionExecutor.waitFor(d); boolean continueOptimization = true; while (continueOptimization) { /* * Get values at A & D for guessing. * These are pre-calculated except during the first step. */ double fa, fd; fa = functionExecutor.getValue(a); fd = functionExecutor.getValue(d); /* * Start calculating possible two next points. The order of evaluation * is selected based on the function values at A and D. */ guessAC = section1(a, c); guessBD = section2(b, d); if (Double.isNaN(fd) || fa < fd) { guessedAC = true; functionExecutor.compute(guessAC); functionExecutor.compute(guessBD); } else { guessedAC = false; functionExecutor.compute(guessBD); functionExecutor.compute(guessAC); } /* * Get values at B and C. */ double fb, fc; functionExecutor.waitFor(b); functionExecutor.waitFor(c); fb = functionExecutor.getValue(b); fc = functionExecutor.getValue(c); double min = MathUtil.min(fa, fb, fc, fd); if (Double.isNaN(min)) { throw new OptimizationException("Unable to compute initial function values"); } /* * Update previous and current values for step control. */ previousValue = currentValue; currentValue = min; previous = current; if (min == fa) { current = a; } else if (min == fb) { current = b; } else if (min == fc) { current = c; } else { current = d; } /* * Select next positions. These are already being calculated in the background * as guessAC and guessBD. */ if (min == fa || min == fb) { d = c; c = b; b = guessAC; functionExecutor.abort(guessBD); guessBD = null; log.debug("Selecting A-C region, a=" + a.get(0) + " c=" + c.get(0)); if (guessedAC) { guessSuccess++; } else { guessFailure++; } } else { a = b; b = c; c = guessBD; functionExecutor.abort(guessAC); guessAC = null; log.debug("Selecting B-D region, b=" + b.get(0) + " d=" + d.get(0)); if (!guessedAC) { guessSuccess++; } else { guessFailure++; } } /* * Check optimization control. */ continueOptimization = control.stepTaken(previous, previousValue, current, currentValue, c.get(0) - a.get(0)); if (Thread.interrupted()) { throw new InterruptedException(); } } } catch (InterruptedException e) { log.info("Optimization was interrupted with InterruptedException"); } if (guessAC != null) { functionExecutor.abort(guessAC); } if (guessBD != null) { functionExecutor.abort(guessBD); } log.info( "Finishing optimization at point " + getOptimumPoint() + " value " + getOptimumValue()); log.info("Optimization statistics: " + getStatistics()); }
@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; }