protected void scheduleRankReturn(Vehicle veh, double time, boolean charge, boolean home) {
      @SuppressWarnings("unchecked")
      Schedule<Task> sched = (Schedule<Task>) veh.getSchedule();
      TaxiStayTask last = (TaxiStayTask) Schedules.getLastTask(veh.getSchedule());
      if (last.getStatus() != TaskStatus.STARTED) throw new IllegalStateException();

      last.setEndTime(time);
      Link currentLink = last.getLink();
      Link nearestRank;
      if (charge) {
        nearestRank = optimizer.getNearestFreeCharger(currentLink.getId());
        log.info("veh" + veh.getId() + " to charge");
      } else if (home) {
        nearestRank = veh.getStartLink();
        //        log.info("start" + veh.getId()+ " at " + time + " t1 " + veh.getT1());
        optimizer.homebound++;
      } else nearestRank = optimizer.getNearestFreeRank(currentLink.getId());

      VrpPathWithTravelData path = calcPath(currentLink, nearestRank, time);
      if (path.getArrivalTime() > veh.getT1())
        return; // no rank return if vehicle is going out of service anyway
      sched.addTask(new TaxiDriveTask(path));
      sched.addTask(new TaxiStayTask(path.getArrivalTime(), veh.getT1(), nearestRank));
    }
    @Override
    protected void appendTasksAfterDropoff(Schedule<TaxiTask> schedule) {
      if (rankmode) {
        TaxiDropoffTask dropoffStayTask = (TaxiDropoffTask) Schedules.getLastTask(schedule);

        Link link = dropoffStayTask.getLink();
        Link startLink = schedule.getVehicle().getStartLink();

        if (link != startLink) {
          double t5 = dropoffStayTask.getEndTime();
          VrpPathWithTravelData path = calcPath(link, startLink, t5);
          schedule.addTask(new TaxiDriveTask(path));
        }
      }

      appendStayTask(schedule);
    }