Générer une couche d'itinéraires (Network Analyst)

Synthèse

Crée une couche de calcul de réseau d'itinéraires et définit ses propriétés d'analyse. Une couche d'analyse d'itinéraire est utile pour définir le meilleur itinéraire entre plusieurs localisations de réseau, en fonction d'un coût réseau spécifié.

Utilisation

  • Après avoir créé la couche d’analyse avec cet outil, vous pouvez ajouter des objets d’analyse de réseau à l’aide de l’outil Ajouter des localisations, résoudre l’analyse à l’aide de l’outil Calculer et enregistrer les résultats sur le disque à l’aide de l’outil Enregistrer dans un fichier de couche.

  • Lorsque vous utilisez cet outil dans des modèles de géotraitement, si le modèle est exécuté en tant qu’outil, la couche d’analyse de réseau en sortie doit être convertie en paramètre de modèle. Dans le cas contraire, la couche en sortie n’est pas ajoutée au contenu de la carte.

Paramètres

ÉtiquetteExplicationType de données
Réseau d'analyse en entrée

Jeu d'entités réseau sur lequel le calcul d'itinéraires est effectué.

Network Dataset Layer
Nom de la couche en sortie

Nom de la couche de calcul d'analyse de réseau d'itinéraires à créer.

String
Attribut d'impédance

L'attribut de coût à utiliser comme impédance dans l'analyse.

String
Réorganiser les arrêts pour trouver l'itinéraire optimal
(Facultatif)
  • Activé : les arrêts sont réorganisés pour trouver le meilleur itinéraire. Cette option transforme l'analyse des itinéraires d'un problème de plus court chemin en un problème du voyageur de commerce (TSP).
  • Désactivé : les arrêts sont visités dans l'ordre de saisie. Il s’agit de l’option par défaut.
Boolean
Conserver l'organisation des arrêts
(Facultatif)

Précise l'ordre des arrêts lorsque l'option Réorganiser les arrêts pour trouver l'itinéraire optimal est sélectionnée.

  • PRESERVE_BOTHLes premier et dernier arrêts selon l’ordre de saisie sont conservés comme les premier et dernier arrêts de l’itinéraire.
  • PRESERVE_FIRSTLe premier arrêt selon l’ordre de saisie est conservé comme le premier arrêt de l’itinéraire, mais le dernier arrêt peut être réorganisé.
  • PRESERVE_LASTLe dernier arrêt selon l’ordre de saisie est conservé comme le dernier arrêt de l’itinéraire, mais le premier arrêt peut être réorganisé.
  • PRESERVE_NONELes premier et dernier arrêts ne seront pas conservés et peuvent être réorganisés.
String
Utiliser les fenêtres horaires
(Facultatif)

Spécifie si des fenêtres horaires sont utilisées au niveau des arrêts.

  • Coché – L'itinéraire tient compte des fenêtres horaires au niveau des arrêts. Si un arrêt survient avant sa fenêtre horaire, un délai d'attente s'écoule avant l'affichage de la fenêtre horaire. Si un arrêt survient après sa fenêtre horaire, aucune infraction de fenêtre horaire ne se produit. L'infraction de fenêtre horaire totale est compensée par l'ajout d'impédance lors du calcul de l'itinéraire. Cette option s'applique uniquement lorsque l'impédance est exprimée en unités de temps.
  • Décoché – L'itinéraire ignore les fenêtres horaires au niveau des arrêts. Il s’agit de l’option par défaut.
Boolean
Accumulateurs
(Facultatif)

Liste des attributs de coût à cumuler lors de l’analyse. Ces attributs d’accumulation sont destinés à servir à titre de référence uniquement ; le solveur utilise uniquement l’attribut de coût spécifié par le paramètre Impedance Attribute (Attribut d’impédance) pour calculer l’itinéraire.

Pour chaque attribut de coût accumulé, une propriété Total_[Impédance] est ajoutée aux itinéraires générés en sortie par le solveur.

String
Règle de demi-tour
(Facultatif)

Spécifie la règle de demi-tour qui sera utilisée aux jonctions. L’autorisation des demi-tours implique que le solveur puisse faire demi-tour au niveau d’une jonction et revenir en arrière par la même rue. Étant donné que les jonctions représentent des intersections de rues et des voies sans issue, différents véhicules peuvent être en mesure de faire demi-tour à certaines jonctions mais pas à d’autres – selon que la jonction représente une intersection ou une voie sans issue. Pour en tenir compte, le paramètre de règle de demi-tour est spécifié implicitement par le nombre de tronçons connectés à la jonction, également connu sous le nom de « valence de jonction ». Les valeurs acceptables pour ce paramètre sont répertoriées ci-dessous ; chacune est suivie d'une description de sa signification en termes de valence de jonction.

  • ALLOW_UTURNSLes demi-tours sont autorisés aux jonctions comportant un nombre quelconque de tronçons connectés. Il s’agit de la valeur par défaut.
  • NO_UTURNSLes demi-tours sont interdits à toutes les jonctions, indépendamment de la valence de jonction. Les demi-tours restent toutefois autorisés aux localisations de réseau même lorsque ce paramètre est sélectionné ; vous pouvez cependant configurer la propriété CurbApproach de chaque localisation de réseau pour y interdire les demi-tours.
  • ALLOW_DEAD_ENDS_ONLYLes demi-tours sont interdits au niveau de toutes les jonctions, sauf celles ayant un seul tronçon adjacent (voie sans issue).
  • ALLOW_DEAD_ENDS_AND_INTERSECTIONS_ONLYLes demi-tours sont interdits au niveau des jonctions où exactement deux tronçons adjacents se rencontrent mais sont autorisés au niveau des intersections (jonctions ayant trois tronçons adjacents ou plus) et des voies sans issue (jonctions comportant exactement un tronçon adjacent). Souvent, les réseaux comportent des jonctions superflues au milieu de segments de route. Cette option empêche des véhicules de faire des demi-tours à ces emplacements.

Si la définition de votre règle de demi-tour n’est pas suffisamment précise, envisagez d’ajouter un évaluateur de délai de tournant global à un attribut de coût de réseau ou de modifier ses paramètres, le cas échéant, en veillant tout particulièrement à la configuration des tournants inversés. Vous pouvez également définir la propriété CurbApproach de vos localisations de réseau.

String
Restrictions
(Facultatif)

Liste des attributs de restriction à appliquer lors de l’analyse.

String
Use Hierarchy in Analysis (Utiliser la hiérarchie lors de l’analyse)
(Facultatif)
  • Activé: l’attribut de hiérarchie sera utilisé pour l’analyse. L'utilisation d'une hiérarchie implique une préférence du solveur pour les tronçons d'ordre supérieur par rapport aux tronçons d'ordre inférieur. Les recherches hiérarchiques sont plus rapides et permettent de simuler la préférence d’un chauffeur de circuler sur des autoroutes au lieu de routes locales si possible, même si cela implique un trajet plus long. Cette option est active uniquement si le jeu de données réseau en entrée comporte un attribut de hiérarchie.
  • Désactivé : l’attribut de hiérarchie n’est pas utilisé pour l’analyse. Si la hiérarchie n’est pas utilisée, un itinéraire exact est obtenu pour le jeu de données réseau.

Le paramètre est désactivé si aucun attribut de hiérarchie n’est défini dans le jeu de données réseau utilisé pour effectuer l’analyse.

Boolean
Paramètres de rang de hiérarchie
(Facultatif)

Héritage :

Avant la version 10, ce paramètre vous permettait de modifier les plages de hiérarchie de l’analyse afin de ne pas utiliser les plages de hiérarchie par défaut établies dans le jeu de données réseau. Ce paramètre n’est plus pris en charge dans la version 1010. Pour modifier les plages de hiérarchie de l’analyse, mettez à jour les plages de hiérarchie par défaut du jeu de données réseau.

Network Analyst Hierarchy Settings
Forme du trajet en sortie
(Facultatif)

Indique le type de forme qui sera utilisé pour les entités itinéraires générées par l’analyse.

  • TRUE_LINES_WITH_MEASURESLes itinéraires en sortie ont la forme exacte des sources de données du réseau sous-jacentes. La sortie comprend des mesures d’itinéraire pour le référencement linéaire. Les mesures augmentent à partir du premier arrêt et enregistrent l'impédance cumulée pour atteindre une position donnée.
  • TRUE_LINES_WITHOUT_MEASURESLes itinéraires en sortie ont la forme exacte des sources de données du réseau sous-jacentes.
  • STRAIGHT_LINESLa forme d'itinéraire en sortie est une ligne droite unique entre les arrêts.
  • NO_LINESAucune forme n’est créée pour les itinéraires en sortie.

Quel que soit le type de forme en sortie spécifié, le meilleur itinéraire est toujours déterminé par l’impédance du réseau, jamais par la distance euclidienne. Cela signifie que seules les formes d'itinéraire sont différentes, pas le parcours du réseau sous-jacent.

String
Heure de début
(Facultatif)

La date et l’heure de début de l’itinéraire. L'heure de début de l'itinéraire permet généralement de trouver des itinéraires selon l'attribut d'impédance qui varie avec l'heure du jour. Par exemple, une heure de début égale à 7 h permet de trouver un itinéraire tenant compte la circulation à l’heure de pointe. La valeur par défaut de ce paramètre est 8 h. Une date et une heure peuvent être spécifiées sous la forme 10/21/05 10:30 AM. Si l’itinéraire couvre plusieurs jours et que seule l’heure de début est indiquée, la date courante est utilisée.

Configurez votre analyse pour utiliser une des dates spéciales suivantes pour modéliser un jour de la semaine ou la date actuelle au lieu d’une date statique spécifique :

  • Aujourd’hui - 12/30/1899
  • Dimanche - 12/31/1899
  • Lundi - 1/1/1900
  • Mardi - 1/2/1900
  • Mercredi - 1/3/1900
  • Jeudi - 1/4/1900
  • Vendredi - 1/5/1900
  • Samedi - 1/6/1900

Par exemple, pour préciser que le trajet doit commencer mardi à 17 h, spécifiez la valeur de paramètre sous la forme 1/2/1900 5:00 PM.

Après le calcul, l’heure de début et l’heure de fin de l’itinéraire sont renseignées dans les itinéraires en sortie. Ces heures de début et de fin sont également utilisées lors de la génération de directions.

En savoir plus sur l’utilisation des dates et des heures et sur leur interprétation dans une analyse de réseau

Date

Sortie obtenue

ÉtiquetteExplicationType de données
Couche Network Analyst

La couche d’analyse de réseau nouvellement créée.

Couche Network Analyst

arcpy.management.MakeRouteLayer(in_network_dataset, out_network_analysis_layer, impedance_attribute, {find_best_order}, {ordering_type}, {time_windows}, {accumulate_attribute_name}, {UTurn_policy}, {restriction_attribute_name}, {hierarchy}, {hierarchy_settings}, {output_path_shape}, {start_date_time})
NomExplicationType de données
in_network_dataset

Jeu d'entités réseau sur lequel le calcul d'itinéraires est effectué.

Network Dataset Layer
out_network_analysis_layer

Nom de la couche de calcul d'analyse de réseau d'itinéraires à créer.

String
impedance_attribute

L'attribut de coût à utiliser comme impédance dans l'analyse.

String
find_best_order
(Facultatif)
  • FIND_BEST_ORDERLes arrêts sont réorganisés pour trouver le meilleur itinéraire. Cette option transforme l'analyse des itinéraires d'un problème de plus court chemin en un problème du voyageur de commerce (TSP).
  • USE_INPUT_ORDERLes arrêts sont visités dans l'ordre de saisie. Il s’agit de l’option par défaut.
Boolean
ordering_type
(Facultatif)

Précise l'ordre des arrêts lorsque FIND_BEST_ORDER est utilisé.

  • PRESERVE_BOTHLes premier et dernier arrêts selon l’ordre de saisie sont conservés comme les premier et dernier arrêts de l’itinéraire.
  • PRESERVE_FIRSTLe premier arrêt selon l’ordre de saisie est conservé comme le premier arrêt de l’itinéraire, mais le dernier arrêt peut être réorganisé.
  • PRESERVE_LASTLe dernier arrêt selon l’ordre de saisie est conservé comme le dernier arrêt de l’itinéraire, mais le premier arrêt peut être réorganisé.
  • PRESERVE_NONELes premier et dernier arrêts ne seront pas conservés et peuvent être réorganisés.
String
time_windows
(Facultatif)

Spécifie si des fenêtres horaires sont utilisées au niveau des arrêts.

  • USE_TIMEWINDOWSL'itinéraire tient compte des fenêtres horaires au niveau des arrêts. Si un arrêt survient avant sa fenêtre horaire, un délai d'attente s'écoule avant l'affichage de la fenêtre horaire. Si un arrêt survient après sa fenêtre horaire, aucune infraction de fenêtre horaire ne se produit. L'infraction de fenêtre horaire totale est comparée à l'impédance minimale lors du calcul de l'itinéraire. Cette option s'applique uniquement lorsque l'impédance est exprimée en unités de temps.
  • NO_TIMEWINDOWSL'itinéraire ignore les fenêtres horaires au niveau des arrêts. Il s’agit de l’option par défaut.
Boolean
accumulate_attribute_name
[accumulate_attribute_name,...]
(Facultatif)

Liste des attributs de coût à cumuler lors de l’analyse. Ces attributs d’accumulation sont destinés à servir à titre de référence uniquement ; le solveur utilise uniquement l’attribut de coût spécifié par le paramètre Impedance Attribute (Attribut d’impédance) pour calculer l’itinéraire.

Pour chaque attribut de coût accumulé, une propriété Total_[Impédance] est ajoutée aux itinéraires générés en sortie par le solveur.

String
UTurn_policy
(Facultatif)

Spécifie la règle de demi-tour qui sera utilisée aux jonctions. L’autorisation des demi-tours implique que le solveur puisse faire demi-tour au niveau d’une jonction et revenir en arrière par la même rue. Étant donné que les jonctions représentent des intersections de rues et des voies sans issue, différents véhicules peuvent être en mesure de faire demi-tour à certaines jonctions mais pas à d’autres – selon que la jonction représente une intersection ou une voie sans issue. Pour en tenir compte, le paramètre de règle de demi-tour est spécifié implicitement par le nombre de tronçons connectés à la jonction, également connu sous le nom de « valence de jonction ». Les valeurs acceptables pour ce paramètre sont répertoriées ci-dessous ; chacune est suivie d'une description de sa signification en termes de valence de jonction.

  • ALLOW_UTURNSLes demi-tours sont autorisés aux jonctions comportant un nombre quelconque de tronçons connectés. Il s’agit de la valeur par défaut.
  • NO_UTURNSLes demi-tours sont interdits à toutes les jonctions, indépendamment de la valence de jonction. Les demi-tours restent toutefois autorisés aux localisations de réseau même lorsque ce paramètre est sélectionné ; vous pouvez cependant configurer la propriété CurbApproach de chaque localisation de réseau pour y interdire les demi-tours.
  • ALLOW_DEAD_ENDS_ONLYLes demi-tours sont interdits au niveau de toutes les jonctions, sauf celles ayant un seul tronçon adjacent (voie sans issue).
  • ALLOW_DEAD_ENDS_AND_INTERSECTIONS_ONLYLes demi-tours sont interdits au niveau des jonctions où exactement deux tronçons adjacents se rencontrent mais sont autorisés au niveau des intersections (jonctions ayant trois tronçons adjacents ou plus) et des voies sans issue (jonctions comportant exactement un tronçon adjacent). Souvent, les réseaux comportent des jonctions superflues au milieu de segments de route. Cette option empêche des véhicules de faire des demi-tours à ces emplacements.

Si la définition de votre règle de demi-tour n’est pas suffisamment précise, envisagez d’ajouter un évaluateur de délai de tournant global à un attribut de coût de réseau ou de modifier ses paramètres, le cas échéant, en veillant tout particulièrement à la configuration des tournants inversés. Vous pouvez également définir la propriété CurbApproach de vos localisations de réseau.

String
restriction_attribute_name
[restriction_attribute_name,...]
(Facultatif)

Liste des attributs de restriction à appliquer lors de l’analyse.

String
hierarchy
(Facultatif)
  • USE_HIERARCHYAttribut de hiérarchie utilisé pour l’analyse. L'utilisation d'une hiérarchie implique une préférence du solveur pour les tronçons d'ordre supérieur par rapport aux tronçons d'ordre inférieur. Les recherches hiérarchiques sont plus rapides et permettent de simuler la préférence d’un chauffeur de circuler sur des autoroutes au lieu de routes locales si possible, même si cela implique un trajet plus long. Cette option est valide uniquement si le jeu de données réseau en entrée comporte un attribut de hiérarchie.
  • NO_HIERARCHYL’attribut de hiérarchie ne sera pas utilisée pour l’analyse. Si la hiérarchie n’est pas utilisée, un itinéraire exact est obtenu pour le jeu de données réseau.

Le paramètre n'est pas utilisé si aucun attribut de hiérarchie n'est défini dans le jeu de données réseau utilisé pour effectuer l'analyse.

Boolean
hierarchy_settings
(Facultatif)

Héritage :

Avant la version 10, ce paramètre vous permettait de modifier les plages de hiérarchie de l’analyse afin de ne pas utiliser les plages de hiérarchie par défaut établies dans le jeu de données réseau. Ce paramètre n’est plus pris en charge dans la version 10 et doit être spécifié comme une chaîne vide. Pour modifier les plages de hiérarchie de l’analyse, mettez à jour les plages de hiérarchie par défaut du jeu de données réseau.

Network Analyst Hierarchy Settings
output_path_shape
(Facultatif)

Indique le type de forme qui sera utilisé pour les entités itinéraires générées par l’analyse.

  • TRUE_LINES_WITH_MEASURESLes itinéraires en sortie ont la forme exacte des sources de données du réseau sous-jacentes. La sortie comprend des mesures d’itinéraire pour le référencement linéaire. Les mesures augmentent à partir du premier arrêt et enregistrent l'impédance cumulée pour atteindre une position donnée.
  • TRUE_LINES_WITHOUT_MEASURESLes itinéraires en sortie ont la forme exacte des sources de données du réseau sous-jacentes.
  • STRAIGHT_LINESLa forme d'itinéraire en sortie est une ligne droite unique entre les arrêts.
  • NO_LINESAucune forme n’est créée pour les itinéraires en sortie.

Quel que soit le type de forme en sortie spécifié, le meilleur itinéraire est toujours déterminé par l’impédance du réseau, jamais par la distance euclidienne. Cela signifie que seules les formes d'itinéraire sont différentes, pas le parcours du réseau sous-jacent.

String
start_date_time
(Facultatif)

La date et l’heure de début de l’itinéraire. L'heure de début de l'itinéraire permet généralement de trouver des itinéraires selon l'attribut d'impédance qui varie avec l'heure du jour. Par exemple, une heure de début égale à 7 h permet de trouver un itinéraire tenant compte la circulation à l’heure de pointe. La valeur par défaut de ce paramètre est 8 h. Une date et une heure peuvent être spécifiées sous la forme 10/21/05 10:30 AM. Si l’itinéraire couvre plusieurs jours et que seule l’heure de début est indiquée, la date courante est utilisée.

Configurez votre analyse pour utiliser une des dates spéciales suivantes pour modéliser un jour de la semaine ou la date actuelle au lieu d’une date statique spécifique :

  • Aujourd’hui - 12/30/1899
  • Dimanche - 12/31/1899
  • Lundi - 1/1/1900
  • Mardi - 1/2/1900
  • Mercredi - 1/3/1900
  • Jeudi - 1/4/1900
  • Vendredi - 1/5/1900
  • Samedi - 1/6/1900

Par exemple, pour préciser que le trajet doit commencer mardi à 17 h, spécifiez la valeur de paramètre sous la forme 1/2/1900 5:00 PM.

Après le calcul, l’heure de début et l’heure de fin de l’itinéraire sont renseignées dans les itinéraires en sortie. Ces heures de début et de fin sont également utilisées lors de la génération de directions.

En savoir plus sur l’utilisation des dates et des heures et sur leur interprétation dans une analyse de réseau

Date

Sortie obtenue

NomExplicationType de données
output_layer

La couche d’analyse de réseau nouvellement créée.

Couche Network Analyst

Exemple de code

Exemple 1 d'utilisation de l'outil Générer une couche d'itinéraires (fenêtre Python)

Exécute l’outil uniquement avec les paramètres requis.

network = "C:/Data/SanFrancisco.gdb/Transportation/Streets_ND"
arcpy.na.MakeRouteLayer(network, "WorkRoute", "TravelTime")
Exemple 2 d'utilisation de l'outil Générer une couche d'itinéraires (fenêtre Python)

Exécutez l’outil avec tous les paramètres.

network = "C:/Data/SanFrancisco.gdb/Transportation/Streets_ND"
arcpy.na.MakeRouteLayer(network, "InspectionRoute", "TravelTime",
                        "FIND_BEST_ORDER", "PRESERVE_BOTH", "USE_TIMEWINDOWS",
                        ["Meters", "TravelTime"],
                        "ALLOW_DEAD_ENDS_AND_INTERSECTIONS_ONLY", ["Oneway"],
                        "USE_HIERARCHY", "", "TRUE_LINES_WITH_MEASURES",
                        "1/1/1900 9:00 AM")
Exemple 3 d'utilisation de l'outil Générer une couche d'itinéraires (workflow)

Le script Python autonome suivant illustre l'utilisation de l'outil MakeRouteLayer pour trouver le meilleur itinéraire pour parcourir les emplacements d'arrêts géocodés.

# Name: MakeRouteLayer_Workflow.py
# Description: Find a best route to visit the stop locations and save the
#              route to a layer file. The stop locations are geocoded from a
#              text file containing the addresses.
# Requirements: Network Analyst Extension

#Import system modules
import arcpy
from arcpy import env
import os

try:
    #Set environment settings
    output_dir = "C:/Data"
    #The NA layer's data will be saved to the workspace specified here
    env.workspace = os.path.join(output_dir, "Output.gdb")
    env.overwriteOutput = True

    #Set local variables
    input_gdb = "C:/Data/SanFrancisco.gdb"
    network = os.path.join(input_gdb, "Transportation", "Streets_ND")
    layer_name = "BestRoute"
    impedance = "TravelTime"
    address_locator = os.path.join(input_gdb, "SanFranciscoLocator")
    address_table = "C:/Data/StopAddresses.csv"
    address_fields = "Street Address;City City;State State;ZIP <None>"
    out_stops = "GeocodedStops"
    output_layer_file = os.path.join(output_dir, layer_name + ".lyrx")

    #Create a new Route layer. For this scenario, the default values for all the
    #remaining parameters statisfy the analysis requirements
    result_object = arcpy.na.MakeRouteLayer(network, layer_name, impedance)

    #Get the layer object from the result object. The route layer can now be
    #referenced using the layer object.
    layer_object = result_object.getOutput(0)

    #Get the names of all the sublayers within the route layer.
    sublayer_names = arcpy.na.GetNAClassNames(layer_object)
    #Stores the layer names that we will use later
    stops_layer_name = sublayer_names["Stops"]

    #Geocode the stop locations from a csv file containing the addresses.
    #The Geocode Addresses tool can use a text or csv file as input table
    #as long as the first line in the file contains the field names.
    arcpy.geocoding.GeocodeAddresses(address_table, address_locator,
                                     address_fields, out_stops)

    #Load the geocoded address locations as stops mapping the address field from
    #geocoded stop features as Name property using field mappings.
    field_mappings = arcpy.na.NAClassFieldMappings(layer_object,
                                                            stops_layer_name)
    field_mappings["Name"].mappedFieldName = "Address"
    arcpy.na.AddLocations(layer_object, stops_layer_name, out_stops,
                            field_mappings, "",
                            exclude_restricted_elements="EXCLUDE")

    #Solve the route layer, ignoring any invalid locations such as those that
    #cannot be geocoded
    arcpy.na.Solve(layer_object, "SKIP")

    #Save the solved route layer as a layer file on disk
    layer_object.saveACopy(output_layer_file)

    print("Script completed successfully")

except Exception as e:
    # If an error occurred, print line number and error message
    import traceback, sys
    tb = sys.exc_info()[2]
    print("An error occurred on line %i" % tb.tb_lineno)
    print(str(e))
Exemple 4 d'utilisation de l'outil Générer une couche d'itinéraires (workflow)

Cet exemple permet de créer plusieurs itinéraires en une seule analyse qui permet souvent de calculer des distances ou des temps de trajet entre des paires origine-destination.

# Name: MakeRouteLayer_MultiRouteWorkflow.py
# Description: Calculate the home-work commutes for a set of people and save
#              the output to a feature class
# Requirements: Network Analyst Extension

#Import system modules
import arcpy
from arcpy import env
import datetime
import os

try:
    #Set environment settings
    output_dir = "C:/Data"
    #The NA layer's data will be saved to the workspace specified here
    env.workspace = os.path.join(output_dir, "Output.gdb")
    env.overwriteOutput = True

    #Set local variables
    input_gdb = "C:/data/SanFrancisco.gdb"
    network = os.path.join(input_gdb, "Transportation", "Streets_ND")
    stops_home = os.path.join(input_gdb, "Analysis", "Commuters_Home")
    stops_work = os.path.join(input_gdb, "Analysis", "Commuters_Work")
    layer_name = "Commuters"
    out_routes_featureclass = "Commuter_Routes"
    impedance = "TravelTime"

    #Set the time of day for the analysis to 8AM on a generic Monday.
    start_time = datetime.datetime(1900, 1, 1, 8, 0, 0)

    #Create a new Route layer.  Optimize on TravelTime, but compute the
    #distance traveled by accumulating the Meters attribute.
    result_object = arcpy.na.MakeRouteLayer(network, layer_name, impedance,
                                         accumulate_attribute_name=["Meters"],
                                         hierarchy="NO_HIERARCHY",
                                         start_date_time=start_time)

    #Get the layer object from the result object. The route layer can now be
    #referenced using the layer object.
    layer_object = result_object.getOutput(0)

    #Get the names of all the sublayers within the route layer.
    sublayer_names = arcpy.na.GetNAClassNames(layer_object)
    #Stores the layer names that we will use later
    stops_layer_name = sublayer_names["Stops"]
    routes_layer_name = sublayer_names["Routes"]

    #Before loading the commuters' home and work locations as route stops, set
    #up field mapping.  Map the "Commuter_Name" field from the input data to
    #the RouteName property in the Stops sublayer, which ensures that each
    #unique Commuter_Name will be placed in a separate route.  Matching
    #Commuter_Names from stops_home and stops_work will end up in the same
    #route.
    field_mappings = arcpy.na.NAClassFieldMappings(layer_object, stops_layer_name)
    field_mappings["RouteName"].mappedFieldName = "Commuter_Name"

    #Add the commuters' home and work locations as Stops. The same field mapping
    #works for both input feature classes because they both have a field called
    #"Commuter_Name"
    arcpy.na.AddLocations(layer_object, stops_layer_name, stops_home,
                        field_mappings, "",
                        exclude_restricted_elements = "EXCLUDE")
    arcpy.na.AddLocations(layer_object, stops_layer_name, stops_work,
                        field_mappings, "", append="APPEND",
                        exclude_restricted_elements = "EXCLUDE")

    #Solve the route layer.
    arcpy.na.Solve(layer_object)

    # Get the output Routes sublayer and save it to a feature class
    routes_sublayer = layer_object.listLayers(routes_layer_name)[0]
    arcpy.management.CopyFeatures(routes_sublayer, out_routes_featureclass)

    print("Script completed successfully")

except Exception as e:
    # If an error occurred, print line number and error message
    import traceback, sys
    tb = sys.exc_info()[2]
    print("An error occurred on line %i" % tb.tb_lineno)
    print(str(e))