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 a New Command. These commands create and initialize new object references, add the object to its layer or folder and reduces the code to be written. 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.
The new command needs to be included in the model commander to guarantee the command execution instantaneously and to keep the command references for undo/redo action purposes:
model.getCommander().addCommand( cmd )
Once the command has been executed and we want to access the new object, any New command returns it from createdObject() method:
newTurn = cmd.createdObject()
If the new command for the GKType you are looking for does not exist, there is an alternate way of creating objects that is 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 object from a type whose NewCmd is not available (GKMyType for instance) the code will be:
state = GKSystem.getSystem().newObject( "GKMyType", model )
and not:
state = GKMyType() # NEVER do this!!!
This call instructs the system to create a new object of a particular type (a GKMyType object in this example) 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 my type object" )
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 creating an object without using its New command, a new object must be added to a layer or to a folder, depending on whether it is graphical or non-graphical.
Imagine the GKMyType object created in the previous section is a non-graphical object. As a non-graphical object it must be added to a folder. Let's imagine we want to add it to the traffic states 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, if the New command to create a detector did not exist (the GKSectionObjectNewCmd is the one to use for it), the steps we would need to follow to write a script that created a detector in the middle of a section would be: 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 )
All the steps above for both non-graphical and graphical objects are automatically handled when using the New commands.
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" ):