OperationalPlanBuilder.java

  1. package org.opentrafficsim.core.gtu.plan.operational;

  2. import java.util.ArrayList;

  3. import org.djunits.unit.AccelerationUnit;
  4. import org.djunits.unit.DurationUnit;
  5. import org.djunits.value.ValueRuntimeException;
  6. import org.djunits.value.vdouble.scalar.Acceleration;
  7. import org.djunits.value.vdouble.scalar.Duration;
  8. import org.djunits.value.vdouble.scalar.Length;
  9. import org.djunits.value.vdouble.scalar.Speed;
  10. import org.djunits.value.vdouble.scalar.Time;
  11. import org.opentrafficsim.core.geometry.OTSGeometryException;
  12. import org.opentrafficsim.core.geometry.OTSLine3D;
  13. import org.opentrafficsim.core.gtu.GTU;
  14. import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan.SpeedSegment;
  15. import org.opentrafficsim.core.math.Solver;

  16. /**
  17.  * Builder for several often used operational plans. E.g., decelerate to come to a full stop at the end of a shape; accelerate
  18.  * to reach a certain speed at the end of a curve; drive constant on a curve; decelerate or accelerate to reach a given end
  19.  * speed at the end of a curve, etc.<br>
  20.  * TODO driving with negative speeds (backward driving) is not yet supported.<br>
  21.  * TODO plan with a constant speed.
  22.  * <p>
  23.  * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  24.  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  25.  * </p>
  26.  * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
  27.  * initial version Nov 15, 2015 <br>
  28.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  29.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  30.  */
  31. public final class OperationalPlanBuilder
  32. {
  33.     /** The maximum acceleration for unbounded accelerations: 1E12 m/s2. */
  34.     private static final Acceleration MAX_ACCELERATION = new Acceleration(1E12, AccelerationUnit.SI);

  35.     /** The maximum deceleration for unbounded accelerations: -1E12 m/s2. */
  36.     private static final Acceleration MAX_DECELERATION = new Acceleration(-1E12, AccelerationUnit.SI);

  37.     /** Private constructor prevents instantiation. */
  38.     private OperationalPlanBuilder()
  39.     {
  40.         // class should not be instantiated
  41.     }

  42.     /**
  43.      * Build a plan with a path and a given speed.
  44.      * @param gtu GTU; the GTU for debugging purposes
  45.      * @param path OTSLine3D; the path to drive (provides the length)
  46.      * @param startTime Time; the current time or a time in the future when the plan should start
  47.      * @param speed Speed; the speed at the start of the path
  48.      * @return the operational plan to accomplish the given end speed
  49.      * @throws OperationalPlanException when the length of the path and the calculated driven distance implied by the
  50.      *             constructed segment list differ more than a given threshold
  51.      */
  52.     public static OperationalPlan buildConstantSpeedPlan(final GTU gtu, final OTSLine3D path, final Time startTime,
  53.             final Speed speed) throws OperationalPlanException
  54.     {
  55.         Length length = path.getLength();
  56.         OperationalPlan.Segment segment;
  57.         segment = new SpeedSegment(length.divide(speed));
  58.         ArrayList<OperationalPlan.Segment> segmentList = new ArrayList<>();
  59.         segmentList.add(segment);
  60.         return new OperationalPlan(gtu, path, startTime, speed, segmentList);
  61.     }

  62.     /**
  63.      * Build a plan with a path and a given start speed to try to reach a provided end speed, exactly at the provided
  64.      * <code>endTime</code>. The acceleration (and deceleration) are capped by maxAcceleration and maxDeceleration. Therefore,
  65.      * there is no guarantee that the end speed is actually reached by this plan. <p>
  66.      * TODO: rename this method buildConstantAccelerationPlan.
  67.      * @param gtu GTU; the GTU for debugging purposes
  68.      * @param path OTSLine3D; the path to drive (provides the length)
  69.      * @param startTime Time; the current time or a time in the future when the plan should start
  70.      * @param startSpeed Speed; the speed at the start of the path
  71.      * @param endSpeed Speed; the required end speed
  72.      * @param maximumAcceleration Acceleration; the maximum acceleration that can be applied, provided as a POSITIVE number
  73.      * @param maximumDeceleration Acceleration; the maximum deceleration that can be applied, provided as a NEGATIVE number
  74.      * @return the operational plan to accomplish the given end speed
  75.      * @throws OperationalPlanException when the length of the path and the calculated driven distance implied by the
  76.      *             constructed segment list differ more than a given threshold
  77.      */
  78.     public static OperationalPlan buildGradualAccelerationPlan(final GTU gtu, final OTSLine3D path, final Time startTime,
  79.             final Speed startSpeed, final Speed endSpeed, final Acceleration maximumAcceleration,
  80.             final Acceleration maximumDeceleration) throws OperationalPlanException
  81.     {
  82.         Length length = path.getLength();
  83.         OperationalPlan.Segment segment;
  84.         if (startSpeed.eq(endSpeed))
  85.         {
  86.             segment = new SpeedSegment(length.divide(startSpeed));
  87.         }
  88.         else
  89.         {
  90.             // t = 2x / (vt + v0); a = (vt - v0) / t
  91.             Duration duration = length.times(2.0).divide(endSpeed.plus(startSpeed));
  92.             Acceleration acceleration = endSpeed.minus(startSpeed).divide(duration);
  93.             try
  94.             {
  95.                 if (acceleration.si < 0.0 && acceleration.lt(maximumDeceleration))
  96.                 {
  97.                     acceleration = maximumDeceleration;
  98.                     // duration = new Duration(abc(acceleration.si / 2, startSpeed.si, -length.si), DurationUnit.SI);
  99.                     duration = new Duration(Solver.firstSolutionAfter(0, acceleration.si / 2, startSpeed.si, -length.si),
  100.                             DurationUnit.SI);
  101.                 }
  102.                 if (acceleration.si > 0.0 && acceleration.gt(maximumAcceleration))
  103.                 {
  104.                     acceleration = maximumAcceleration;
  105.                     // duration = new Duration(abc(acceleration.si / 2, startSpeed.si, -length.si), DurationUnit.SI);
  106.                     duration = new Duration(Solver.firstSolutionAfter(0, acceleration.si / 2, startSpeed.si, -length.si),
  107.                             DurationUnit.SI);
  108.                 }
  109.             }
  110.             catch (ValueRuntimeException exception)
  111.             {
  112.                 throw new OperationalPlanException("Caught unexpected exception: " + exception);
  113.             }
  114.             segment = new OperationalPlan.AccelerationSegment(duration, acceleration);
  115.         }
  116.         ArrayList<OperationalPlan.Segment> segmentList = new ArrayList<>();
  117.         segmentList.add(segment);
  118.         return new OperationalPlan(gtu, path, startTime, startSpeed, segmentList);
  119.     }

  120.     /**
  121.      * Build a plan with a path and a given start speed to reach a provided end speed, exactly at the end of the curve.
  122.      * Acceleration and deceleration are virtually unbounded (1E12 m/s2) to reach the end speed (e.g., to come to a complete
  123.      * stop).
  124.      * @param gtu GTU; the GTU for debugging purposes
  125.      * @param path OTSLine3D; the path to drive (provides the length)
  126.      * @param startTime Time; the current time or a time in the future when the plan should start
  127.      * @param startSpeed Speed; the speed at the start of the path
  128.      * @param endSpeed Speed; the required end speed
  129.      * @return the operational plan to accomplish the given end speed
  130.      * @throws OperationalPlanException when the length of the path and the calculated driven distance implied by the
  131.      *             constructed segment list differ more than a given threshold
  132.      */
  133.     public static OperationalPlan buildGradualAccelerationPlan(final GTU gtu, final OTSLine3D path, final Time startTime,
  134.             final Speed startSpeed, final Speed endSpeed) throws OperationalPlanException
  135.     {
  136.         return buildGradualAccelerationPlan(gtu, path, startTime, startSpeed, endSpeed, MAX_ACCELERATION, MAX_DECELERATION);
  137.     }

  138.     /**
  139.      * Build a plan with a path and a given start speed to try to reach a provided end speed. Acceleration or deceleration is as
  140.      * provided, until the end speed is reached. After this, constant end speed is used to reach the end point of the path.
  141.      * There is no guarantee that the end speed is actually reached by this plan. If the end speed is zero, and it is reached
  142.      * before completing the path, a truncated path that ends where the GTU stops is used instead. The maximum acceleration and
  143.      * deceleration is limited by the provided values. If these prevent the <code>endSpeed</code> from being reached, the
  144.      * generated plan is a constant acceleration plan using the limiting value.
  145.      * @param gtu GTU; the GTU for debugging purposes
  146.      * @param path OTSLine3D; the path to drive (provides the length)
  147.      * @param startTime Time; the current time or a time in the future when the plan should start
  148.      * @param startSpeed Speed; the speed at the start of the path
  149.      * @param endSpeed Speed; the required end speed
  150.      * @param maximumAcceleration Acceleration; the acceleration to use if endSpeed &gt; startSpeed, provided as a POSITIVE
  151.      *            number
  152.      * @param maximumDeceleration Acceleration; the deceleration to use if endSpeed &lt; startSpeed, provided as a NEGATIVE
  153.      *            number
  154.      * @return the operational plan to accomplish the given end speed
  155.      * @throws OperationalPlanException when the length of the path and the calculated driven distance implied by the
  156.      *             constructed segment list differ more than a given threshold
  157.      */
  158.     public static OperationalPlan buildMaximumAccelerationPlan(final GTU gtu, final OTSLine3D path, final Time startTime,
  159.             final Speed startSpeed, final Speed endSpeed, final Acceleration maximumAcceleration,
  160.             final Acceleration maximumDeceleration) throws OperationalPlanException
  161.     {
  162.         Length length = path.getLength();
  163.         ArrayList<OperationalPlan.Segment> segmentList = new ArrayList<>();
  164.         if (startSpeed.eq(endSpeed))
  165.         {
  166.             segmentList.add(new OperationalPlan.SpeedSegment(length.divide(startSpeed)));
  167.         }
  168.         else
  169.         {
  170.             try
  171.             {
  172.                 if (endSpeed.gt(startSpeed))
  173.                 {
  174.                     Duration t = endSpeed.minus(startSpeed).divide(maximumAcceleration);
  175.                     Length x = startSpeed.times(t).plus(maximumAcceleration.times(0.5).times(t).times(t));
  176.                     if (x.ge(length))
  177.                     {
  178.                         // we cannot reach the end speed in the given distance with the given acceleration
  179.                         // Duration duration = new Duration(abc(acceleration.si / 2, startSpeed.si, -length.si),
  180.                         // DurationUnit.SI);
  181.                         Duration duration = new Duration(
  182.                                 Solver.firstSolutionAfter(0, maximumAcceleration.si / 2, startSpeed.si, -length.si),
  183.                                 DurationUnit.SI);
  184.                         segmentList.add(new OperationalPlan.AccelerationSegment(duration, maximumAcceleration));
  185.                     }
  186.                     else
  187.                     {
  188.                         // we reach the (higher) end speed before the end of the segment. Make two segments.
  189.                         segmentList.add(new OperationalPlan.AccelerationSegment(t, maximumAcceleration));
  190.                         Duration duration = length.minus(x).divide(endSpeed);
  191.                         segmentList.add(new OperationalPlan.SpeedSegment(duration));
  192.                     }
  193.                 }
  194.                 else
  195.                 {
  196.                     Duration t = endSpeed.minus(startSpeed).divide(maximumDeceleration);
  197.                     Length x = startSpeed.times(t).plus(maximumDeceleration.times(0.5).times(t).times(t));
  198.                     if (x.ge(length))
  199.                     {
  200.                         // we cannot reach the end speed in the given distance with the given deceleration
  201.                         // Duration duration = new Duration(abc(deceleration.si / 2, startSpeed.si, -length.si),
  202.                         // DurationUnit.SI);
  203.                         Duration duration =
  204.                                 new Duration(Solver.firstSolutionAfter(0, maximumDeceleration.si / 2, startSpeed.si, -length.si),
  205.                                         DurationUnit.SI);
  206.                         segmentList.add(new OperationalPlan.AccelerationSegment(duration, maximumDeceleration));
  207.                     }
  208.                     else
  209.                     {
  210.                         if (endSpeed.si == 0.0)
  211.                         {
  212.                             // if endSpeed == 0, we cannot reach the end of the path. Therefore, build a partial path.
  213.                             OTSLine3D partialPath = path.truncate(x.si);
  214.                             segmentList.add(new OperationalPlan.AccelerationSegment(t, maximumDeceleration));
  215.                             return new OperationalPlan(gtu, partialPath, startTime, startSpeed, segmentList);
  216.                         }
  217.                         // we reach the (lower) end speed, larger than zero, before the end of the segment. Make two segments.
  218.                         segmentList.add(new OperationalPlan.AccelerationSegment(t, maximumDeceleration));
  219.                         Duration duration = length.minus(x).divide(endSpeed);
  220.                         segmentList.add(new OperationalPlan.SpeedSegment(duration));
  221.                     }
  222.                 }
  223.             }
  224.             catch (ValueRuntimeException | OTSGeometryException exception)
  225.             {
  226.                 throw new OperationalPlanException("Caught unexpected exception: " + exception);
  227.             }
  228.         }
  229.         return new OperationalPlan(gtu, path, startTime, startSpeed, segmentList);
  230.     }

  231.     /**
  232.      * Build a plan with a path and a given start speed to try to come to a stop with a given deceleration. If the GTU can stop
  233.      * before completing the given path, a truncated path that ends where the GTU stops is used instead. There is no guarantee
  234.      * that the OperationalPlan will lead to a complete stop.
  235.      * @param gtu GTU; the GTU for debugging purposes
  236.      * @param path OTSLine3D; the path to drive (provides the length)
  237.      * @param startTime Time; the current time or a time in the future when the plan should start
  238.      * @param startSpeed Speed; the speed at the start of the path
  239.      * @param deceleration Acceleration; the deceleration to use if endSpeed &lt; startSpeed, provided as a NEGATIVE number
  240.      * @return the operational plan to accomplish the given end speed
  241.      * @throws OperationalPlanException when the length of the path and the calculated driven distance implied by the
  242.      *             constructed segment list differ more than a given threshold
  243.      */
  244.     public static OperationalPlan buildStopPlan(final GTU gtu, final OTSLine3D path, final Time startTime,
  245.             final Speed startSpeed, final Acceleration deceleration) throws OperationalPlanException
  246.     {
  247.         return buildMaximumAccelerationPlan(gtu, path, startTime, startSpeed, Speed.ZERO,
  248.                 new Acceleration(1.0, AccelerationUnit.SI), deceleration);
  249.     }

  250. }