Créer une couche d’analyse d’itinéraires (Network Analyst)

Synthèse

Crée une couche d’analyse de réseau d’itinéraires et définit ses propriétés d’analyse. Une couche d’analyse de réseau d’itinéraires 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é. La couche peut être créée à l’aide d’un jeu de données réseau local ou d’un service de calcul d’itinéraire hébergé en ligne ou sur un portail.

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.

  • Dans ArcGIS AllSource, les données des couches d’analyse de réseau sont stockées sur disque dans des classes d’entités de géodatabase fichier. Lorsque vous créez une couche d’analyse de réseau dans un projet, les données de cette couche sont créées dans un nouveau jeu de classes d’entités dans l’environnement Espace de travail courant. Lorsque vous créez une couche d’analyse de réseau dans un script Python, vous devez commencer par définir de façon explicite l’environnement de l’espace de travail sur une géodatabase fichier dans laquelle vous voulez stocker les données de la couche à l’aide de arcpy.env.workspace = "<path to file gdb>". Lorsque la couche est créée, un nouveau jeu de données d'entité contenant les classes d'entités de sous-couche appropriées est ajouté à cette géodatabase fichier.

Paramètres

ÉtiquetteExplicationType de données
Source de données réseau

Jeu de données réseau ou service sur lequel l'analyse du réseau est effectuée. Utilisez l'URL du portail pour un service.

Network Dataset Layer;String
Nom de la couche
(Facultatif)

Nom de la couche d’analyse de réseau à créer.

String
Mode de déplacement
(Facultatif)

Nom du mode de déplacement à utiliser dans l’analyse. Le mode de déplacement représente une collection de paramètres réseau, tels que des restrictions de circulation et des règles de demi-tour, qui détermine la façon dont un piéton, une voiture, un camion ou un autre mode de transport se déplace sur le réseau. Les modes de déplacement sont définis dans votre source de données de réseau.

Vous pouvez aussi utiliser un objet arcpy.na.TravelMode et une chaîne contenant la représentation JSON valide d’un mode de déplacement en entrée du paramètre.

String
Séquence
(Facultatif)

Spécifie si les arrêts en entrée doivent être parcourus dans un ordre spécifique lors du calcul de l'itinéraire optimal. 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).

  • Utiliser l'ordre existantLes arrêts sont visités dans l'ordre de saisie. Il s’agit de l’option par défaut.
  • Trouver le meilleur ordreLes 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).
  • Conserver le premier et le dernier arrêtsLes premier et dernier arrêts sont conservés dans l’ordre de saisie. Les autres sont réorganisés pour trouver le meilleur itinéraire.
  • Conserver le premier arrêtLe premier arrêt est conservé dans l’ordre de saisie. Les autres sont réorganisés pour trouver le meilleur itinéraire.
  • Conserver le dernier arrêtLe dernier arrêt est conservé dans l’ordre de saisie. Les autres sont réorganisés pour trouver le meilleur itinéraire.
String
Heure du jour
(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.

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.

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

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

Date
Fuseau horaire
(Facultatif)

Spécifie le fuseau horaire du paramètre Date/heure du jour.

  • Heure locale des localisationsLe paramètre Heure du jour se rapporte au fuseau horaire dans lequel se trouve le premier arrêt d’un itinéraire. Il s’agit de l’option par défaut.Si vous générez de nombreux itinéraires commençant dans plusieurs fuseaux horaires, les heures de départ sont échelonnées dans le temps universel coordonné, ou UTC (Universal Time Coordinated). Par exemple, une valeur Time of Day (Heure du jour) égale à 10 h 00, le 2 janvier, signifie une heure de départ fixée à 10 h 00 heure normale de l’Est (15 h 00 UTC) pour les itinéraires commençant dans le fuseau horaire de l’Est et 10 h 00 heure normale du Centre (16 h 00 UTC) pour les itinéraires commençant dans le fuseau horaire du Centre. Les heures de départ sont décalées d’une heure en temps universel coordonné (UTC).Les dates et heures de départ et d'arrivée enregistrées dans la classe d'entités des arrêts se rapportent au fuseau horaire local du premier arrêt de chaque itinéraire.
  • UTCLe paramètre Time of Day (Heure du jour) est exprimé en UTC (Temps Universel Coordonné). Choisissez cette option si vous souhaitez générer un itinéraire à une heure donnée (maintenant, par exemple), sans toutefois connaître avec certitude le fuseau horaire dans lequel se trouve le premier arrêt.Si vous générez plusieurs itinéraires qui couvrent différents fuseaux horaires, les heures de début en temps universel coordonné (UTC) sont simultanées. Par exemple, une valeur Time of Day (Heure du jour) égale à 10 h 00, le 2 janvier, indique une heure de début de 5 h 00 heure normale de l’Est (10 h 00 UTC) pour les itinéraires commençant dans le fuseau horaire Est, et de 4 h 00 heure normale du Centre (10 h 00 UTC) pour les itinéraires commençant dans le fuseau horaire du Centre. Les deux itinéraires commencent à 10 h 00 UTC.Les dates et heures de départ et d'arrivée enregistrées dans la classe d'entités des arrêts se rapportent au temps universel coordonnée (UTC).
String
Forme linéaire
(Facultatif)

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

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.

  • Le long du réseauLes 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.
  • Aucune ligneAucune forme n’est créée pour les itinéraires en sortie.
  • Lignes droitesLa forme d'itinéraire en sortie est une ligne droite unique entre les arrêts.
String
Attributs d'accumulation
(Facultatif)

Liste des attributs de coût à cumuler lors de l’analyse. Ces attributs accumulés servent uniquement de référence. Le solveur n’utilise que l’attribut de coût utilisé par le mode de déplacement désigné pour la réalisation de l’analyse.

Pour chaque attribut de coût accumulé, une propriété Total_[Impédance] est renseignée dans les entités en sortie de l’analyse du réseau.

Ce paramètre n’est pas disponible si la source de données réseau est un service ArcGIS Online ou si la source de données réseau est un service hébergé sur une version de Portal for ArcGIS qui ne prend pas en charge l’accumulation.

String
Générer des feuilles de route lors du calcul
(Facultatif)

Spécifie si une feuille de route sera générée lors de l’exécution de l’analyse.

  • Activé : une feuille de route détaillée sera générée lors de la résolution. Il s’agit de l’option par défaut.
  • Désactivé : aucune feuille de route détaillée ne sera générée lors de la résolution.

Dans le cas d’une analyse pour laquelle la création d’une feuille de route détaillée n’est pas nécessaire, laisser cette option désactivée permet de gagner du temps.

Boolean
Fuseau horaire des champs temporels
(Facultatif)

Indique le fuseau horaire qui sera utilisé pour interpréter les champs horaires inclus dans les tables en entrée, par exemple les champs utilisés pour les fenêtres horaires.

  • Heure locale des localisationsLes dates et heures dans les champs horaires pour l’arrêt seront interprétées conformément au fuseau horaire dans lequel se situe l’arrêt. Il s’agit de l’option par défaut.
  • UTCLes dates et heures dans les champs horaires pour l’arrêt sont exprimées en UTC (temps universel coordonné).
String
Ignorer les localisations non valides lors de l’analyse
(Facultatif)

Détermine si les emplacements en entrée non valides sont ignorés. En règle générale, les emplacements ne sont pas valides si ils ne peuvent pas être localisés sur le réseau. Lorsque les emplacements non valides sont ignorés, le solveur les ignore et tente de réaliser l’analyse avec les emplacements restants.

  • Activé : les emplacements en entrée non valides sont ignorés et seuls les emplacements valides sont utilisés. Il s’agit de l’option par défaut.
  • Activé : tous les emplacements en entrée sont utilisés. Les localisations non valides provoquent l’échec de l’analyse.
Boolean

Sortie obtenue

ÉtiquetteExplicationType de données
Couche Network Analyst

La couche d’analyse de réseau en sortie.

Network Analyst Layer

arcpy.management.MakeRouteAnalysisLayer(network_data_source, {layer_name}, {travel_mode}, {sequence}, {time_of_day}, {time_zone}, {line_shape}, {accumulate_attributes}, {generate_directions_on_solve}, {time_zone_for_time_fields}, {ignore_invalid_locations})
NomExplicationType de données
network_data_source

Jeu de données réseau ou service sur lequel l'analyse du réseau est effectuée. Utilisez l'URL du portail pour un service.

Network Dataset Layer;String
layer_name
(Facultatif)

Nom de la couche d’analyse de réseau à créer.

String
travel_mode
(Facultatif)

Nom du mode de déplacement à utiliser dans l’analyse. Le mode de déplacement représente une collection de paramètres réseau, tels que des restrictions de circulation et des règles de demi-tour, qui détermine la façon dont un piéton, une voiture, un camion ou un autre mode de transport se déplace sur le réseau. Les modes de déplacement sont définis dans votre source de données de réseau.

Vous pouvez aussi utiliser un objet arcpy.na.TravelMode et une chaîne contenant la représentation JSON valide d’un mode de déplacement en entrée du paramètre.

String
sequence
(Facultatif)

Spécifie si les arrêts en entrée doivent être parcourus dans un ordre spécifique lors du calcul de l'itinéraire optimal. 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_CURRENT_ORDERLes arrêts sont visités dans l'ordre de saisie. Il s’agit de l’option par défaut.
  • 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).
  • PRESERVE_BOTHLes premier et dernier arrêts sont conservés dans l’ordre de saisie. Les autres sont réorganisés pour trouver le meilleur itinéraire.
  • PRESERVE_FIRSTLe premier arrêt est conservé dans l’ordre de saisie. Les autres sont réorganisés pour trouver le meilleur itinéraire.
  • PRESERVE_LASTLe dernier arrêt est conservé dans l’ordre de saisie. Les autres sont réorganisés pour trouver le meilleur itinéraire.
String
time_of_day
(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.

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.

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

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

Date
time_zone
(Facultatif)

Indique le fuseau horaire du paramètre time_of_day.

  • LOCAL_TIME_AT_LOCATIONSLe paramètre time_of_day se rapporte au fuseau horaire dans lequel se trouve le premier arrêt d’un itinéraire. Il s’agit de l’option par défaut.Si vous générez de nombreux itinéraires commençant dans plusieurs fuseaux horaires, les heures de départ sont échelonnées dans le temps universel coordonné, ou UTC (Universal Time Coordinated). Par exemple, une valeur time_of_day de 10 h 00, le 2 janvier, signifie une heure de départ fixée à 10 h 00 heure normale de l’Est (15 h 00 UTC) pour les itinéraires commençant dans le fuseau horaire de l’Est et 10 h 00 heure normale du Centre (16 h 00 UTC) pour les itinéraires commençant dans le fuseau horaire du Centre. Les heures de départ sont décalées d’une heure en temps universel coordonné (UTC).Les dates et heures de départ et d'arrivée enregistrées dans la classe d'entités des arrêts se rapportent au fuseau horaire local du premier arrêt de chaque itinéraire.
  • UTCLe paramètre time_of_day est exprimé en temps universel coordonné (UTC). Choisissez cette option si vous souhaitez générer un itinéraire à une heure donnée (maintenant, par exemple), sans toutefois connaître avec certitude le fuseau horaire dans lequel se trouve le premier arrêt.Si vous générez plusieurs itinéraires qui couvrent différents fuseaux horaires, les heures de début en temps universel coordonné (UTC) sont simultanées. Par exemple, une valeur time_of_day de 10 h 00, le 2 janvier, indique une heure de début de 5 h 00 heure normale de l’Est (10 h 00 UTC) pour les itinéraires commençant dans le fuseau horaire Est, et de 4 h 00 heure normale du Centre (10 h 00 UTC) pour les itinéraires commençant dans le fuseau horaire du Centre. Les deux itinéraires commencent à 10 h 00 UTC.Les dates et heures de départ et d'arrivée enregistrées dans la classe d'entités des arrêts se rapportent au temps universel coordonnée (UTC).
String
line_shape
(Facultatif)

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

  • ALONG_NETWORKLes 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.
  • NO_LINESAucune forme n’est créée pour les itinéraires en sortie.
  • STRAIGHT_LINESLa forme d'itinéraire en sortie est une ligne droite unique entre les arrêts.

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
accumulate_attributes
[accumulate_attributes,...]
(Facultatif)

Liste des attributs de coût à cumuler lors de l’analyse. Ces attributs accumulés servent uniquement de référence. Le solveur n’utilise que l’attribut de coût utilisé par le mode de déplacement désigné pour la réalisation de l’analyse.

Pour chaque attribut de coût accumulé, une propriété Total_[Impédance] est renseignée dans les entités en sortie de l’analyse du réseau.

Ce paramètre n’est pas disponible si la source de données réseau est un service ArcGIS Online ou si la source de données réseau est un service hébergé sur une version de Portal for ArcGIS qui ne prend pas en charge l’accumulation.

String
generate_directions_on_solve
(Facultatif)

Spécifie si une feuille de route sera générée lors de l’exécution de l’analyse.

  • DIRECTIONSUne feuille de route détaillée sera générée lors de la résolution. Il s’agit de l’option par défaut.
  • NO_DIRECTIONSAucune feuille de route détaillée ne sera générée lors de la résolution.

Dans le cas d’une analyse pour laquelle la création d’une feuille de route détaillée n’est pas nécessaire, l’utilisation de l’option NO_DIRECTIONS permet de gagner du temps.

Boolean
time_zone_for_time_fields
(Facultatif)

Indique le fuseau horaire qui sera utilisé pour interpréter les champs horaires inclus dans les tables en entrée, par exemple les champs utilisés pour les fenêtres horaires.

  • LOCAL_TIME_AT_LOCATIONSLes dates et heures dans les champs horaires pour l’arrêt seront interprétées conformément au fuseau horaire dans lequel se situe l’arrêt. Il s’agit de l’option par défaut.
  • UTCLes dates et heures dans les champs horaires pour l’arrêt sont exprimées en UTC (temps universel coordonné).
String
ignore_invalid_locations
(Facultatif)

Détermine si les emplacements en entrée non valides sont ignorés. En règle générale, les emplacements ne sont pas valides si ils ne peuvent pas être localisés sur le réseau. Lorsque les emplacements non valides sont ignorés, le solveur les ignore et tente de réaliser l’analyse avec les emplacements restants.

  • SKIPLes emplacements en entrée non valides sont ignorés et seuls les emplacements valides sont utilisés. Il s’agit de l’option par défaut.
  • HALTTous les emplacements en entrée sont utilisés. Les localisations non valides provoquent l’échec de l’analyse.
Boolean

Sortie obtenue

NomExplicationType de données
out_network_analysis_layer

La couche d’analyse de réseau en sortie.

Network Analyst Layer

Exemple de code

Exemple 1 d'utilisation de l'outil Créer une couche d'analyse 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.MakeRouteAnalysisLayer(network, "WorkRoute")
Exemple 2 d'utilisation de l'outil Créer une couche d'analyse 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.MakeRouteAnalysisLayer(network, "InspectionRoute", "Driving Time",
                        "FIND_BEST_ORDER", "1/1/1900 9:00 AM", "UTC",
                        "ALONG_NETWORK", ["Meters", "TravelTime"])
Exemple 3 d'utilisation de l'outil MakeRouteAnalysisLayer (workflow)

Le script Python autonome suivant illustre l’utilisation de la fonction MakeRouteAnalysisLayer pour trouver le meilleur itinéraire pour parcourir les emplacements d’arrêts géocodés.

# Name: MakeRouteAnalysisLayer_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:
    #Check out Network Analyst license if available. Fail if the Network Analyst license is not available.
    if arcpy.CheckExtension("network") == "Available":
        arcpy.CheckOutExtension("network")
    else:
        raise arcpy.ExecuteError("Network Analyst Extension license is not available.")
    
    #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"
    travel_mode = "Driving Time"
    address_locator = "C:/Data/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.MakeRouteAnalysisLayer(network, layer_name,
                                                                    travel_mode)

    #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, "")

    #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 MakeRouteAnalysisLayer (workflow)

Cet exemple explique comment calculer plusieurs itinéraires en une seule analyse, méthode qui s'avère utile pour calculer des distances ou des temps de trajet entre des paires origine-destination.

Héritage :

La fonction GetNASublayer peut être utilisée pour extraire les sous-couches d’une couche d’analyse de réseau. Elle a été introduite dans ArcGIS Pro 2.7. Dans les versions précédentes, la meilleure manière d’extraire un objet de sous-couche d’une couche d’analyse de réseau consistait à utiliser la méthode listLayers de l’objet Layer d’analyse de réseau en utilisant le nom de la sous-couche en tant que caractère générique.

# Name: MakeRouteAnalysisLayer_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:
    #Check out Network Analyst license if available. Fail if the Network Analyst license is not available.
    if arcpy.CheckExtension("network") == "Available":
        arcpy.CheckOutExtension("network")
    else:
        raise arcpy.ExecuteError("Network Analyst Extension license is not available.")
    
    #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"
    travel_mode = "Driving Time"

    #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 driving time, but compute the
    #distance traveled by accumulating the Meters attribute.
    result_object = arcpy.na.MakeRouteAnalysisLayer(network, layer_name,
                                        travel_mode, time_of_day=start_time,
                                        accumulate_attributes=["Meters"])

    #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, "")
    arcpy.na.AddLocations(layer_object, stops_layer_name, stops_work,
                        field_mappings, "", append="APPEND")

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

    # Get the output Routes sublayer and save it to a feature class
    routes_sublayer = arcpy.na.GetNASublayer(layer_object, "Routes")
    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))