void runSimulations()
        {
            if (TimeWarp.CurrentRate <= TimeWarp.MaxPhysicsRate &&
                    (nextSimulationDelayMs == 0 || nextSimulationTimer.ElapsedMilliseconds > nextSimulationDelayMs))
            {
                Stopwatch s = Stopwatch.StartNew();
                prediction = simulateReentryRK4(simulationTimeStep, Vector3d.zero);
                s.Stop();
                nextSimulationDelayMs = 10 * s.ElapsedMilliseconds;
                nextSimulationTimer.Reset();
                nextSimulationTimer.Start();

                if (autoLandAtTarget &&
                    (landStep == LandStep.COURSE_CORRECTIONS || landStep == LandStep.ON_COURSE || landStep == LandStep.DECELERATING))
                {
                    if (!velocityCorrectionSet) simCounter = 0;

                    if ((simCounter % 25) == 0)
                    {
                        if (courseCorrectionsAllowed())
                        {
                            velAUnit = chooseDownrangeVelocityVector();
                        }
                        else
                        {
                            velAUnit = vesselState.upNormalToVelSurface;
                        }
                        velBUnit = vesselState.leftSurface;
                    }
                    if ((simCounter % 5) == 0) computeVelocityCorrection();
                }
            }
        }
        //predict the reentry trajectory. uses the fourth order Runge-Kutta numerical integration scheme
        protected LandingPrediction simulateReentryRK4(Vector3d startPos, Vector3d startVel, double startTime, double dt, bool recurse)
        {
            LandingPrediction result = new LandingPrediction();

            //should change this to also account for hyperbolic orbits where we have passed periapsis
            //should also change this to use the orbit giv en by the parameters
            if (part.vessel.orbit.PeA > part.vessel.mainBody.maxAtmosphereAltitude)
            {
                result.outcome = LandingPrediction.Outcome.NO_REENTRY;
                return result;
            }

            //use the known orbit in vacuum to find the position and velocity when we first hit the atmosphere
            //or start decelerating with thrust:
            AROrbit freefallTrajectory = new AROrbit(startPos, startVel, startTime, part.vessel.mainBody);
            double initialT = projectFreefallEndTime(freefallTrajectory, startTime);
            //a hack to detect improperly initialized stuff and not try to do the simulation
            if (double.IsNaN(initialT))
            {
                result.outcome = LandingPrediction.Outcome.NO_REENTRY;
                return result;
            }

            Vector3d pos = freefallTrajectory.positionAtTime(initialT);
            Vector3d vel = freefallTrajectory.velocityAtTime(initialT);
            double initialAltitude = FlightGlobals.getAltitudeAtPos(pos);
            Vector3d initialPos = new Vector3d(pos.x, pos.y, pos.z);
            Vector3d initialVel = new Vector3d(vel.x, vel.y, vel.z); ;

            double dragCoeffOverMass = vesselState.massDrag / vesselState.mass;

            //now integrate the equations of motion until we hit the surface or we exit the atmosphere again:
            double t = initialT;
            result.maxGees = 0;
            bool beenInAtmosphere = false;
            while (true)
            {
                //one time step of RK4:
                Vector3d dv1 = dt * ARUtils.computeTotalAccel(pos, vel, dragCoeffOverMass, part.vessel.mainBody);
                Vector3d dx1 = dt * vel;

                Vector3d dv2 = dt * ARUtils.computeTotalAccel(pos + 0.5 * dx1, vel + 0.5 * dv1, dragCoeffOverMass, part.vessel.mainBody);
                Vector3d dx2 = dt * (vel + 0.5 * dv1);

                Vector3d dv3 = dt * ARUtils.computeTotalAccel(pos + 0.5 * dx2, vel + 0.5 * dv2, dragCoeffOverMass, part.vessel.mainBody);
                Vector3d dx3 = dt * (vel + 0.5 * dv2);

                Vector3d dv4 = dt * ARUtils.computeTotalAccel(pos + dx3, vel + dv3, dragCoeffOverMass, part.vessel.mainBody);
                Vector3d dx4 = dt * (vel + dv3);

                Vector3d dx = (dx1 + 2 * dx2 + 2 * dx3 + dx4) / 6.0;
                Vector3d dv = (dv1 + 2 * dv2 + 2 * dv3 + dv4) / 6.0;

                pos += dx;
                vel += dv;
                t += dt;

                double altitudeASL = FlightGlobals.getAltitudeAtPos(pos);

                if (altitudeASL < part.vessel.mainBody.maxAtmosphereAltitude) beenInAtmosphere = true;

                //We will thrust to reduce our speed if it is too high. However we have to
                //be aware that it's the *surface* frame speed that is controlled.
                Vector3d surfaceVel = vel - part.vessel.mainBody.getRFrmVel(pos);
                double maxSurfaceVel = decelerationSpeed(altitudeASL, vesselState.maxThrustAccel, part.vessel.mainBody);
                if (altitudeASL > decelerationEndAltitudeASL && surfaceVel.magnitude > maxSurfaceVel)
                {
                    surfaceVel = maxSurfaceVel * surfaceVel.normalized;
                    vel = surfaceVel + part.vessel.mainBody.getRFrmVel(pos);
                }

                //during reentry the gees you feel come from drag:
                double dragAccel = ARUtils.computeDragAccel(pos, vel, dragCoeffOverMass, part.vessel.mainBody).magnitude;
                result.maxGees = Math.Max(dragAccel / 9.81, result.maxGees);

                //detect landing
                if (altitudeASL < decelerationEndAltitudeASL)
                {
                    result.outcome = LandingPrediction.Outcome.LANDED;
                    result.landingLatitude = part.vessel.mainBody.GetLatitude(pos);
                    result.landingLongitude = part.vessel.mainBody.GetLongitude(pos);
                    result.landingLongitude -= (t - vesselState.time) * (360.0 / (part.vessel.mainBody.rotationPeriod)); //correct for planet rotation (360 degrees every 6 hours)
                    result.landingLongitude = ARUtils.clampDegrees(result.landingLongitude);
                    result.landingTime = t;
                    return result;
                }

                //detect the end of an aerobraking pass
                if (beenInAtmosphere
                    && part.vessel.mainBody.maxAtmosphereAltitude > 0
                    && altitudeASL > part.vessel.mainBody.maxAtmosphereAltitude + 1000
                    && Vector3d.Dot(vel, pos - part.vessel.mainBody.position) > 0)
                {
                    if (part.vessel.orbit.PeA > 0 || !recurse)
                    {
                        result.outcome = LandingPrediction.Outcome.AEROBRAKED;
                        result.aerobrakeApoapsis = ARUtils.computeApoapsis(pos, vel, part.vessel.mainBody);
                        result.aerobrakePeriapsis = ARUtils.computePeriapsis(pos, vel, part.vessel.mainBody);
                        return result;
                    }
                    else
                    {
                        //continue suborbital trajectories to a landing
                        return simulateReentryRK4(pos, vel, t, dt, false);
                    }
                }

                //Don't tie up the CPU by running forever. Some real reentry trajectories will time out, but that's
                //just too bad. It's possible to spend an arbitarily long time in the atmosphere before landing.
                //For example, a circular orbit just inside the edge of the atmosphere will decay
                //extremely slowly. So there's no reasonable timeout setting here that will simulate all valid reentry trajectories
                //to their conclusion.
                if (t > initialT + 1000)
                {
                    result.outcome = LandingPrediction.Outcome.TIMED_OUT;
                    print("MechJeb landing simulation timed out:");
                    print("current ship altitude ASL = " + vesselState.altitudeASL);
                    print("freefall end altitude ASL = " + initialAltitude);
                    print("freefall end position = " + initialPos);
                    print("freefall end vel = " + initialVel);
                    print("timeout position = " + pos);
                    print("timeout altitude ASL = " + altitudeASL);
                    return result;
                }
            }
        }
        //programmatic interface to land at a specific target.
        public void landAt(double latitude, double longitude)
        {
            this.enabled = true;

            core.controlClaim(this);

            autoLandAtTarget = true;
            deorbitBurnFirstMessage = false;
            gaveUpOnCourseCorrections = false;

            targetLatitude = latitude;
            targetLongitude = longitude;
            initializeDecimalStrings();
            initializeDMSStrings();

            if (targetLatitude == BEACH_LATITUDE && targetLongitude == BEACH_LONGITUDE) dmsInput = false;

            core.landDeactivate(this);
            landStep = LandStep.COURSE_CORRECTIONS;
            FlightInputHandler.SetNeutralControls();

            //run an initial landing simulation
            prediction = simulateReentryRK4(simulationTimeStep, Vector3d.zero);

            //initialize the state machine
            if (part.vessel.orbit.PeA < 0 || prediction.outcome == LandingPrediction.Outcome.LANDED)
            {
                landStep = LandStep.COURSE_CORRECTIONS;
            }
            else
            {
                landStep = LandStep.DEORBIT_BURN;
                deorbiting = false;
            }
        }