Script Example: Creating objects¶
Scripting is an effective tool for data modification but it can be used to create new data as well. This example shows how to import data following an example that creates a new traffic state using data from an external file.
Object Creation¶
Any object that derives from GKObject must be created (unless specifically indicated) using the GKSystem::newObject() call. This call will create a new object, will initialize it, and will add it to the current model catalog.
Creating a new object that derives from GKObject in any other way can corrupt the current model or make the system crash later on. Therefore to create a new traffic state (GKTrafficState) the code will be:
state = GKSystem.getSystem().newObject( "GKTrafficState", model )
and not:
state = GKTrafficState() # NEVER do this!!!
This call instructs the system to create a new object of a particular type in the supplied model. The new object will be untitled, so it is advisable to give it a name using the GKObject::setName() method:
state.setName( "New traffic state" )
New Command¶
For some objects, there is an option to create new object by using a New Command. These commands create and initialize new object references and simplify the code. For example:
cmd = GKTurningNewCmd()
cmd.setTurning( origin, destination )
cmd.setUndoable( False )
This example calls the constructor, sets the minimum information required for the object, and sets undoable to false to prevent the new command being undone in the GUI.
If the new command is include in the model commander, this guarantees the command execution instantaneously and, for undo/redo action purposes, it also keeps the command references:
model.getCommander().addCommand( cmd )
Once the command has been executed and we want to access the new object, New Command returns it from createdObject() method:
newTurn = cmd.createdObject()
Object Organization¶
Aimsun Next organizes objects in two ways depending on their type. Graphical objects are organized in layers and shown in the 2D and 3D views. Non-graphical objects are organized in folders and shown in the Project Window.
After creation, a new object must be added to a layer or to a folder, depending on whether it is graphical or non-graphical.
As the traffic state that we will create in this exercise is a non-graphical object it must be added to a folder. However this folder must be created if it does not already exist. The following code creates the folder:
folderName = "GKModel::trafficStates"
folder = model.getCreateRootFolder().findFolder( folderName )
if folder == None:
folder = GKSystem.getSystem().createFolder( model.getCreateRootFolder(), folderName )
First, this code looks for the folder using the GKFolder::findFolder() call. It searches in the root folder of the model which is the normal location. If the folder is not there then it will be created. Because the Traffic States folder is a system folder, we just need to pass the internal name of the folder for the system to create the correct structure. Refer to the table below for the internal name of the system folders.
Internal names of the system folders
External Name | Internal Name (unique) |
---|---|
Centroid Configurations | GKModel::centroidsConf |
Control | GKModel::top::control |
Control Plans | GKModel::controlPlans |
Data Analysis | GKModel::top::dataAnalysis |
Demand Data | GKModel::top::traffic |
Detector Locations | GKModel::detectorLocations |
Functions | GKModel::functions |
Infrastructure | GKModel::top::infrastructure |
Lane Types | GKModel::laneTypes |
Master Control Plans | GKModel::masterControlPlans |
OD Matrices | GKCentroidConfiguration::matrices |
OD Routes | GKCentroidConfiguration::routes |
Transit | GKModel::top::publicTransport |
Transit Lines | GKModel::publicLines |
Transit Plans | GKModel::publicPlans |
Real Data Sets | GKModel::realDataSets |
Road Types | GKModel::roadTypes |
Scenarios | GKModel::top::scenarios |
Scripts | GKModel::top::scripts |
Subpaths | GKModel::subPaths |
Strategies | GKModel::strategies |
Traffic Conditions | GKModel::trafficConditions |
Traffic Demands | GKModel::trafficDemand |
Traffic Management | GKModel::top::trafficmanagement |
Traffic States | GKModel::trafficStates |
Triggers | GKModel::triggers |
Vehicles | GKModel::vehicles |
View Modes | GKModel::viewModes |
View Styles | GKModel::viewStyles |
Finally, the new object must be added to the folder:
folder.append( state )
Graphical objects must be added to the GeoModel. Within the GeoModel objects must be assigned to a layer. In most cases, the active layer will be used. This is found using the getActiveLayer() call:
(model.getGeoModel().getActiveLayer()).
For example, to write a script that creates a detector in the middle of a section: First create the detector, then define its parameters(name, lanes, and length). Add it on the top of a section (a detector cannot exist on its own), and finally add it to the GeoModel, placing it on the same layer of the section. If the script is added to the Section context menu, then the variable target is used to refer to the section:
detector = GKSystem.getSystem().newObject( "GKDetector", model )
detector.setName( "A new detector" )
detector.setLanes( 0, 1 )
detector.setLength( 4.5 )
detector.setPosition( target.length2D() / 2.0 )
target.addTopObject( detector )
model.getGeoModel().add( target.getLayer(), detector )
Object Destruction¶
Objects are removed from the model in two stages:
- Get the delete command for the object calling GKObject::getDelCmd()
- Execute the command
For example:
myObjectToDelete = model.getCatalog().find(104) #retrieve object
if myObjectToDelete!=None:
cmd = myObjectToDelete.getDelCmd()
model.getCommander().addCommand(cmd)
Because the GKObjectDelCmd class is derived from GKCommand, it provides undo functionality. Therefore, to make the deletion permanent (non-undoable), add a null command:
model.getCommander().addCommand(None)
Reading a File¶
After creating a Traffic State, the next stage is set the input flows by reading them from a file. This will be an ASCII file with the information organized in two columns in comma separated format. The first column holds the identifier of the section, the second one holds the input flow.
First, open the file, and read it line by line. Next, split each line, using comma as separator.
Use the catalog to look for the section using its ID. If, instead of identifiers, external identifiers or names were used. The method can be changed to refer to these.
With the section, and the flow, we set the flow in the traffic state:
def importState( model, state, fileName ):
for line in open( fileName, "r" ).readlines():
# Separate the line in columns
columns = line.split( "," )
# First column contains the id of the section
section = model.getCatalog().find(int(columns[0]))
# Second column contains the flow
flow = float(columns[1])
# Set the value if the section is valid
if section != None:
state.setEntranceFlow( section, None, flow )
Error Handling¶
Suppose that the input file had an error in it and contained an identifier for a centroid instead of a section. The catalog will return the object with that identifier – a centroid – and when setEntranceFlow() is called using that centroid. Aimsun Next will report an error as shown here:
Python Error (exceptions.TypeError): argument 1 of GKTrafficState.setEntranceFlow() has an invalid type
An invalid type error is given as the function expects a section but has instead been passed a centroid. Note that the code already protects itself from None objects; None is returned when no object is found.
Therefore, when looking for an object in the catalog it is advisable to check first if it is found and second if it is of the correct type using the following code:
if section != None and section.isA( "GKSection" ):