private void cleanSchedule() {
   for (TransitLine line : this.schedule.getTransitLines().values()) {
     Set<TransitRoute> toRemove = new HashSet<>();
     for (TransitRoute transitRoute : line.getRoutes().values()) {
       boolean removeRoute = false;
       NetworkRoute networkRoute = transitRoute.getRoute();
       if (networkRoute.getStartLinkId() == null || networkRoute.getEndLinkId() == null) {
         removeRoute = true;
       }
       for (Id<Link> linkId : transitRoute.getRoute().getLinkIds()) {
         if (linkId == null) {
           removeRoute = true;
         }
       }
       if (removeRoute) {
         log.error(
             "NetworkRoute for " + transitRoute.getId().toString() + " incomplete. Remove route.");
         toRemove.add(transitRoute);
       }
     }
     if (!toRemove.isEmpty()) {
       for (TransitRoute transitRoute : toRemove) {
         line.removeRoute(transitRoute);
       }
     }
   }
 }
  public static TransitSchedule removeAllRoutesWithMissingLinksFromSchedule(
      TransitSchedule transitSchedule, Network network) {
    log.info("Removing stops and routes with missing links from the schedule");
    TransitSchedule tS = TransitScheduleCleaner.makeTransitScheduleModifiable(transitSchedule);
    printStatistic(tS);
    int removedRoutes = 0;

    // Remove routes with missing links
    for (TransitLine transitLine : tS.getTransitLines().values()) {

      Set<TransitRoute> transitRouteToBeRemoved = new HashSet<TransitRoute>();

      for (TransitRoute transitRoute : transitLine.getRoutes().values()) {

        // Remove Route, when links are missing in the network
        if (network.getLinks().get(transitRoute.getRoute().getStartLinkId()) == null) {
          transitRouteToBeRemoved.add(transitRoute);
          continue;
        }

        for (Id linkId : transitRoute.getRoute().getLinkIds()) {
          if (network.getLinks().get(linkId) == null) {
            transitRouteToBeRemoved.add(transitRoute);
            break;
          }
        }

        if (network.getLinks().get(transitRoute.getRoute().getEndLinkId()) == null) {
          transitRouteToBeRemoved.add(transitRoute);
          continue;
        }

        // Remove route, if one of its stops, has a missing link
        for (TransitRouteStop transitRouteStop : transitRoute.getStops()) {
          if (network.getLinks().get(transitRouteStop.getStopFacility().getLinkId()) == null) {
            transitRouteToBeRemoved.add(transitRoute);
            break;
          }
        }
      }

      for (TransitRoute transitRoute : transitRouteToBeRemoved) {
        if (transitLine.removeRoute(transitRoute) == true) {
          removedRoutes++;
        }
      }
    }

    log.info("Removed " + removedRoutes + " routes due to missing links or stops");
    printStatistic(tS);

    return tS;
  }
  /**
   * Adding TransportMode.pt flags to all links referred by transit schedule
   *
   * @param transitSchedule The transit schedule.
   * @param network The network to be tagged.
   * @return
   */
  public static Network tagTransitLinksInNetwork(TransitSchedule transitSchedule, Network network) {

    log.info("Tagging pt network links");

    if (transitSchedule == null) {
      log.info("No transit schedule given. Returning unmodified network...");
      return network;
    }

    for (TransitStopFacility stopFacitlity : transitSchedule.getFacilities().values()) {
      Set<String> allowedModes =
          new TreeSet<String>(network.getLinks().get(stopFacitlity.getLinkId()).getAllowedModes());
      allowedModes.add(TransportMode.pt);
      network.getLinks().get(stopFacitlity.getLinkId()).setAllowedModes(allowedModes);
    }

    for (TransitLine transitLine : transitSchedule.getTransitLines().values()) {
      for (TransitRoute transitRoute : transitLine.getRoutes().values()) {
        NetworkRoute route = transitRoute.getRoute();

        Set<String> allowedModes;

        allowedModes =
            new TreeSet<String>(network.getLinks().get(route.getStartLinkId()).getAllowedModes());
        allowedModes.add(TransportMode.pt);
        network.getLinks().get(route.getStartLinkId()).setAllowedModes(allowedModes);

        for (Id linkId : route.getLinkIds()) {
          allowedModes = new TreeSet<String>(network.getLinks().get(linkId).getAllowedModes());
          allowedModes.add(TransportMode.pt);
          network.getLinks().get(linkId).setAllowedModes(allowedModes);
        }

        allowedModes =
            new TreeSet<String>(network.getLinks().get(route.getEndLinkId()).getAllowedModes());
        allowedModes.add(TransportMode.pt);
        network.getLinks().get(route.getEndLinkId()).setAllowedModes(allowedModes);
      }
    }

    int taggedLinks = 0;
    for (Link link : network.getLinks().values()) {
      if (link.getAllowedModes().contains(TransportMode.pt)) {
        taggedLinks++;
      }
    }

    log.info("Finished - " + taggedLinks + " links were tagged");

    return network;
  }
 /**
  * Add to any link that is passed by any route a "pt" in the modes, if it hasn't already one...
  */
 private void prepareNetwork() {
   Map<Id<Link>, ? extends Link> networkLinks = network.getLinks();
   Set<Id<Link>> transitLinks = new HashSet<>();
   for (TransitLine line : this.schedule.getTransitLines().values()) {
     for (TransitRoute transitRoute : line.getRoutes().values()) {
       NetworkRoute networkRoute = transitRoute.getRoute();
       transitLinks.add(networkRoute.getStartLinkId());
       for (Id<Link> linkId : transitRoute.getRoute().getLinkIds()) {
         transitLinks.add(linkId);
       }
       transitLinks.add(networkRoute.getEndLinkId());
     }
   }
   for (Id<Link> transitLinkId : transitLinks) {
     Link transitLink = networkLinks.get(transitLinkId);
     if (!transitLink.getAllowedModes().contains(TransportMode.pt)) {
       Set<String> modes = new HashSet<>();
       modes.addAll(transitLink.getAllowedModes());
       modes.add(TransportMode.pt);
       transitLink.setAllowedModes(modes);
     }
   }
 }
  public TransitRouteData(Network network, TransitRoute transitRoute) {

    this.transportMode = transitRoute.getTransportMode();

    this.firstDeparture = Double.MAX_VALUE;
    this.lastDeparture = -Double.MAX_VALUE;
    this.vehIds = new TreeSet<String>();
    this.numberOfDepartures = 0;

    for (Departure departure : transitRoute.getDepartures().values()) {
      this.firstDeparture = Math.min(this.firstDeparture, departure.getDepartureTime());
      this.lastDeparture = Math.max(this.lastDeparture, departure.getDepartureTime());
      this.vehIds.add(departure.getVehicleId().toString());
      this.numberOfDepartures++;
    }

    this.firstStop = transitRoute.getStops().get(0).getStopFacility();
    this.lastStop =
        transitRoute.getStops().get(transitRoute.getStops().size() - 1).getStopFacility();

    if (this.firstStop == this.lastStop) {
      // get the stop location of stop with the largest distance between first and last stop
      TransitStopFacility currentViaStop = null;
      double currentViaDistance = Double.NEGATIVE_INFINITY;
      for (TransitRouteStop stop : transitRoute.getStops()) {
        double distanceFirstPotentialVia =
            CoordUtils.calcDistance(this.firstStop.getCoord(), stop.getStopFacility().getCoord());
        double distanceLastProtenialVia =
            CoordUtils.calcDistance(this.lastStop.getCoord(), stop.getStopFacility().getCoord());
        double newDistance =
            Math.sqrt(
                Math.pow(distanceFirstPotentialVia, 2) + Math.pow(distanceLastProtenialVia, 2));

        if (newDistance > currentViaDistance) {
          // this one is farther away - keep it
          currentViaStop = stop.getStopFacility();
          currentViaDistance = newDistance;
        }
      }
      this.viaStop = currentViaStop;
    } else {
      // get the stop in the middle of the line
      this.viaStop =
          transitRoute.getStops().get((int) (transitRoute.getStops().size() / 2)).getStopFacility();
    }

    // calculate the length of the route
    double distance = 0.0;
    double freeSpeedTravelTime = 0.0;
    for (Id<Link> linkId : transitRoute.getRoute().getLinkIds()) {
      Link link = network.getLinks().get(linkId);
      distance += link.getLength();
      freeSpeedTravelTime += link.getLength() / link.getFreespeed();
    }
    // add last link but not the first link
    Link link = network.getLinks().get(transitRoute.getRoute().getEndLinkId());
    distance += link.getLength();
    freeSpeedTravelTime += link.getLength() / link.getFreespeed();

    this.distance = distance;
    this.freeSpeedTravelTime = freeSpeedTravelTime;

    this.travelTime =
        transitRoute.getStops().get(transitRoute.getStops().size() - 1).getArrivalOffset();

    this.avgSpeed = this.distance / this.travelTime;
  }