Path: blob/main/tools/contributed/sumopy/coremodules/simulation/simplaconfig.py
169689 views
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo1# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.2# SUMOPy module3# Copyright (C) 2012-2021 University of Bologna - DICAM4# This program and the accompanying materials are made available under the5# terms of the Eclipse Public License 2.0 which is available at6# https://www.eclipse.org/legal/epl-2.0/7# This Source Code may also be made available under the following Secondary8# Licenses when the conditions for such availability set forth in the Eclipse9# Public License 2.0 are satisfied: GNU General Public License, version 210# or later which is available at11# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html12# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later1314# @file simplaconfig.py15# @author Joerg Schweizer16# @date 20121718"""19simpla is a configurable, platooning plugin for the TraCI Python client. It manages the spontaneous formation of vehicle platoons and allows you to define specific behavior for vehicles that travel inside a platoon.2021This is achieved by defining additional vehicle types which represent platooning modes, and by providing information, which type (mode) to use for normal, solitary travel, and which one to use when platooning is activated. Further, 'catch-up' modes may be specified, which are used when a potential platooning partner is farther ahead downstream.2223For platooning up to four operational modes may be specified apart from the normal traveling mode (see section Configuration for the details):2425* Platoon leader mode (parametrization of a vehicle driving at the front of a platoon)26* Platoon follower mode (parametrization of a vehicle driving behind another vehicle within a platoon)27* Platoon catch-up mode (parametrization of a vehicle in range of a platoon, which is feasible for joining)28* Platoon catch-up follower mode (parametrization of a vehicle traveling in a platoon, with a platoon leader in catchup mode)29"""30import os31import sys32import numpy as np33# print 'module simplaconfig SUMO_HOME',os.environ['SUMO_HOME'],'SUMO_HOME' in os.environ34try:35if 'SUMO_HOME' in os.environ:36tools = os.path.join(os.environ['SUMO_HOME'], 'tools')37sys.path.append(tools)38else:39print("please declare environment variable 'SUMO_HOME'")4041import simpla4243except:44print 'WARNING: No module simpla in syspath. Please provide SUMO_HOME.'4546simpla = None4748# local simpla49#import simpla5051from agilepy.lib_base.processes import Process52#from xml.sax import saxutils, parse, handler5354import agilepy.lib_base.classman as cm55import agilepy.lib_base.arrayman as am56import agilepy.lib_base.xmlman as xm57from coremodules.demand.demandbase import DemandobjMixin585960class SimplaConfig(DemandobjMixin, cm.BaseObjman):61def __init__(self, simulation,62name='Simple Platooning configuration',63info='Configuration of simple platooning service. Simpla is a service that allows to crate platoons in any simulation. The platooning option must be enabled in the Traci micro simulation.',64xmltag='configuration',65version=0.2,66**kwargs):67# print 'SimplaConfig.__init__',name6869self._init_objman(ident='simplaconfig', parent=simulation,70name=name, info=info, xmltag=xmltag,71version=0.3,72**kwargs)7374attrsman = self.set_attrsman(cm.Attrsman(self))75self._init_attributes()76self._init_constants()7778# make PRTservice a demand object as link79self.get_scenario().demand.add_demandobject(obj=self)8081def get_scenario(self):82return self.parent.parent8384def _init_constants(self):85self._typemap = {}86self.get_attrsman().do_not_save_attrs(['_typemap', ])8788def _init_attributes(self):89# print 'PrtService._init_attributes',hasattr(self,'prttransit')90attrsman = self.get_attrsman()91scenario = self.get_scenario()9293is_update = False94if not hasattr(self, '_version'):95# crazy simpla has no version???96is_update = True97self._version = 0.09899elif self.get_version() < 0.2:100is_update = True101102if is_update:103# there were config errors in the 0.0 version104attrsman.delete('tau_follower')105if hasattr(self, 'dist_min_follower'):106attrsman.delete('dist_min_follower')107if hasattr(self, 'sigma_follower'):108attrsman.delete('sigma_follower')109110if self.get_version() < 0.3:111# this would remove _private entirely112# self.is_enabled.del_groupname('_private')113attrsman.delete('is_enabled')114115self.is_enabled = attrsman.add(cm.AttrConf('is_enabled', False,116groupnames=['options'],117name='Enabled',118info="""Enable platooning""",119), is_prepend=True)120121# here we ged classes not vehicle type122# specific vehicle type within a class will be generated later123# these are the mode choices which have a defined vehicle type124modechoices = scenario.demand.vtypes.get_modechoices()125126# print ' modechoices',modechoices127128self.ids_platoonmodes = attrsman.add(cm.ListConf('ids_platoonmodes', [scenario.net.modes.get_id_mode('passenger')],129groupnames=['options'],130choices=modechoices,131name='Platooned modes',132info="""Transport modes to platoon.133A vehicle is controlled by simpla if its vehicle type ID is part of the given mode IDs.134""",135#xmltag = 'vehicleSelectors',136))137138# self.testlist = attrsman.add(cm.ListConf( 'testlist', ['1','dd','cvc'],139# groupnames = ['state'],140# choices = ['1','dd','cvc','dddd','eeeee'],141# perm='rw',142# is_save = True,143# name = 'Test list',144# info = 'This is a test list',145# xmltag = 'testList',146# ))147148self.time_update = attrsman.add(cm.AttrConf('time_update', 1.0,149groupnames=['options'],150name='Man. update time',151info="Update time for vehicle management.",152unit='s',153xmltag='controlRate',154))155156self.platoongap_max = attrsman.add(cm.AttrConf('platoongap_max', 15.0,157groupnames=['options'],158name='Max. platoon gap',159info="""Gap (in m.) below which vehicles are considered as a platoon (if their vType parameters allow safe traveling for the actual situation).""",160unit='m',161xmltag='maxPlatoonGap',162))163164self.time_platoon_splitup = attrsman.add(cm.AttrConf('time_platoon_splitup', 3.0,165groupnames=['options'],166name='Platoon splitup time',167info="Time until a vehicle which maintains a distance larger than max Platoon Gap from its leader within the platoon (or travels on a different lane or behind a vehicle not belonging to its platoon) is split off. Defaults to 3.0 secs.",168unit='s',169xmltag='platoonSplitTime',170))171172self.dist_catchup = attrsman.add(cm.AttrConf('dist_catchup', 100.0,173groupnames=['options'],174name='catchup distance',175info="""If a catch-up mode was defined, vehicles switch their type to the corresponding catch-up vehicle type as soon as a platoon is ahead closer than the given value (in m.).""",176unit='m',177xmltag='catchupDist',178))179180self.factor_switch_impatience = attrsman.add(cm.AttrConf('factor_switch_impatience', -1.0,181groupnames=['options'],182name='switch impatience factor ',183info="""The switch impatience factor determines the magnitude of the effect that an increasing waiting time for a mode switch (due to safety constraints) has on the active speed factor of a vehicle. The active speed factor is calculated as activeSpeedFactor = modeSpecificSpeedFactor/(1+impatienceFactor*waitingTime). The default value for the switch impatience factor is 0.1. Providing values <= 0 will deactivate the impatience mechanism.""",184xmltag='switchImpatienceFactor',185))186187# self.lanechangemode_original = attrsman.add(cm.AttrConf( 'lanechangemode_original', 594,188# groupnames = ['options','lanechange-modes'],189# name = 'Lane-change mode original',190# info = """Specifies the binary lane-change mode to be used as original.""",191# ))192193self.lanechangemode_leader = attrsman.add(cm.AttrConf('lanechangemode_leader', 594,194groupnames=['options', 'lanechange-modes'],195name='Lane-change mode leader',196info="""Specifies the binary lane-change mode to be used as leader.""",197))198self.lanechangemode_follower = attrsman.add(cm.AttrConf('lanechangemode_follower', 514,199groupnames=['options', 'lanechange-modes'],200name='Lane-change mode follower',201info="""Specifies the binary lane-change mode to be used as follower.""",202))203self.lanechangemode_catchup = attrsman.add(cm.AttrConf('lanechangemode_catchup', 514,204groupnames=['options', 'lanechange-modes'],205name='Lane-change mode catchup',206info="""Specifies the binary lane-change mode to be used as catchup.""",207))208209self.lanechangemode_catchup_follower = attrsman.add(cm.AttrConf('lanechangemode_catchup_follower', 514,210groupnames=['options', 'lanechange-modes'],211name='Lane-change mode catchup-follower',212info="""Specifies the binary lane-change mode to be used as catchup-follower.""",213))214215self.speedfactor_original = attrsman.add(cm.AttrConf('speedfactor_original', 1.0,216groupnames=['options', 'speedfactors'],217name='Speed factor original',218info="""Specifies the speed factor to be used as original.""",219))220self.speedfactor_leader = attrsman.add(cm.AttrConf('speedfactor_leader', 1.0,221groupnames=['options', 'speedfactors'],222name='Speed factor leader',223info="""Specifies the speed factor to be used as leader.""",224))225self.speedfactor_follower = attrsman.add(cm.AttrConf('speedfactor_follower', 2.0,226groupnames=['options', 'speedfactors'],227name='Speed factor follower',228info="""Specifies the speed factor to be used as follower. Must be greater than one.""",229))230self.speedfactor_catchup = attrsman.add(cm.AttrConf('speedfactor_catchup', 2.5,231groupnames=['options', 'speedfactors'],232name='Speed factor catchup',233info="""Specifies the speed factor to be used as catchup. Must be greater than one.""",234))235self.speedfactor_catchup_follower = attrsman.add(cm.AttrConf('speedfactor_catchup_follower', 3.0,236groupnames=['options', 'speedfactors'],237name='Speed factor catchup follower',238info="""Specifies the speed factor to be used as follower. Must be greater than one.""",239))240241self.accelfactor_follower = attrsman.add(cm.AttrConf('accelfactor_follower', 1.0,242groupnames=['options', 'dynamics'],243name='Accel. factor follower',244info="""Specifies the acceleration factor to be used as follower.""",245))246247self.decelfactor_follower = attrsman.add(cm.AttrConf('decelfactor_follower', 1.0,248groupnames=['options', 'dynamics'],249name='Decel. factor follower',250info="""Specifies the deceleration factor to be used as follower.""",251))252253self.tau_follower = attrsman.add(cm.AttrConf('tau_follower', 0.2,254groupnames=['options', 'dynamics'],255name='Reaction time follower',256info="Follower's reaction time.",257unit='s',258))259260self.dist_min_follower = attrsman.add(cm.AttrConf('dist_min_follower', 0.3,261groupnames=['options', 'dynamics'],262name='Min. gap follower',263info="Follower's reaction time.",264unit='m',265))266267self.sigma_follower = attrsman.add(cm.AttrConf('sigma_follower', 0.0,268groupnames=['options', 'dynamics'],269name='Driver follower',270info="Follower's driver imperfection in driving (between 0 and 1). Used only in follower models SUMOKrauss, SKOrig.",271unit='s',272))273274self.is_keep_vtypes = attrsman.add(cm.AttrConf('is_keep_vtypes', False,275groupnames=['options', 'misc'],276name='Keep platoon vtypes',277info="Keep platoon specific vtypes after simulation in the vehicle type database. This for reviewing purpose and not required.",278))279self.set_version(0.3)280281def enable(self, is_enabled):282"""Enables simulation with platoons. Must be called before preparing simulation."""283self.is_enabled = is_enabled284285def prepare_sim(self):286if self.is_enabled:287# self.add_vtypes()# done in get_writexmlinfo means in get_vtypes()288self.export_config()289print 'Simplaconfig.prepare_sim', self.configfilepath, self.is_enabled290simpla.load(self.configfilepath)291292def finish_sim(self):293if self.is_enabled:294if not self.is_keep_vtypes:295self.del_vtypes()296297def export_config(self):298self.configfilepath = self.parent.get_scenario().get_rootfilepath()+'.simpla.xml'299xm.write_obj_to_xml(self, self.configfilepath)300301def write_xml(self, fd, indent=0):302"""303Write simpla xml config file304"""305print 'Simplaconfig.write_xml'306fd.write(xm.begin(self.xmltag, indent))307attrsman = self.get_attrsman()308vtypes = self.parent.get_scenario().demand.vtypes309ids_sumo_vtypes = vtypes.ids_sumo310# <controlRate value="0.5" />311# <maxPlatoonGap value="15.0" />312# <catchupDist value="100.0" />313# <switchImpatienceFactor value="0.1" />314# <platoonSplitTime value="3.0" />315# <lcMode original="597" leader="597" follower="514" catchup="514" catchupFollower="514" />316# <speedFactor original="1.0" leader="1.0" follower="2.0" catchup="2.5" catchupFollower="3.0" />317# <verbosity value="1" />318# <vTypeMap original="passenger1" leader="leaderVTypeID" follower="followerVTypeID" catchup="catchupVTypeID" catchupFollower="catchupFollowerVTypeID" />319320#ids_plattypes = ['catchup','follower','original']321#ids_plattypes = self._typemap.keys()322#ids_vtypes_plat_sumo = []323# for id_mode in self.ids_platoonmodes:324# ids_vtype_sumo= ids_sumo_vtypes[vtypes.select_by_mode(id_mode=id_mode)]325# #print ' id_mode',id_mode,'ids_vtype',ids_vtype.tolist()326# for id_vtype_sumo in ids_vtype_sumo:327# if id_vtype in ids_plattypes328# #if id_vtype_sumo.split('_')[-1] not in plattypes:329# ids_vtypes_plat_sumo.append(id_vtype_sumo)330331ids_vtypes_plat_sumo = ids_sumo_vtypes[self._typemap.keys()]332fd.write(xm.start('vehicleSelectors', indent+2))333fd.write(xm.arr('value', ids_vtypes_plat_sumo, sep=','))334fd.write(xm.stopit())335336fd.write(xm.start('lcMode', indent+2))337fd.write(xm.num('leader', self.lanechangemode_leader))338fd.write(xm.num('follower', self.lanechangemode_follower))339fd.write(xm.num('catchup', self.lanechangemode_catchup))340fd.write(xm.num('catchupFollower', self.lanechangemode_catchup_follower))341fd.write(xm.stopit())342343fd.write(xm.start('speedFactor', indent+2))344fd.write(xm.num('original', 1.0))345fd.write(xm.num('leader', self.speedfactor_leader))346fd.write(xm.num('follower', self.speedfactor_follower))347fd.write(xm.num('catchup', self.speedfactor_catchup))348fd.write(xm.num('catchupFollower', self.speedfactor_catchup_follower))349fd.write(xm.stopit())350351for plattypes in self._typemap.values():352fd.write(xm.start('vTypeMap', indent+2))353for plattype, id_vtype in plattypes.iteritems():354fd.write(xm.num(plattype, ids_sumo_vtypes[id_vtype]))355fd.write(xm.stopit())356357for attrconfig in attrsman.get_configs():358if attrconfig.xmltag is not None:359if (attrconfig.xmltag == 'switchImpatienceFactor') & (attrconfig.get_value() < 0):360pass361else:362fd.write(xm.start(attrconfig.xmltag, indent+2))363fd.write(xm.num('value', attrconfig.format_value()))364fd.write(xm.stopit())365366fd.write(xm.end(self.xmltag, indent))367368def add_vtypes(self):369"""370Add necessary vtypes.371This function is called before writing vtypes.372These vtypes should be deleted after the export.373"""374print 'Simplaconfig.add_vtypes'375self._typemap = {}376vtypes = self.get_scenario().demand.vtypes377for id_mode in self.ids_platoonmodes:378ids_vtype = vtypes.select_by_mode(id_mode=id_mode)379380# original is not created but points to the381#self._add_vtypes(vtypes, ids_vtype, 'original')382plattype_original = 'original'383for _id in ids_vtype:384self._typemap[_id] = {plattype_original: _id}385386co = 0.1 # default coloroffset387cf = 1.2 # default colorfactor388self._add_vtypes(vtypes, ids_vtype, 'leader',389coloroffset=np.array([co, 0, 0, 1], dtype=np.float32),390colorfactor=np.array([cf, 0, 0, 1], dtype=np.float32),391carfollowermodel='ACC',392)393394self._add_vtypes(vtypes, ids_vtype, 'follower',395accelfactor=self.accelfactor_follower,396decelfactor=self.decelfactor_follower,397tau=self.tau_follower,398sigma=self.sigma_follower,399dist_min=self.dist_min_follower,400coloroffset=np.array([0, co, 0, 1], dtype=np.float32),401colorfactor=np.array([0, cf, 0, 1], dtype=np.float32),402carfollowermodel='CACC',403)404405self._add_vtypes(vtypes, ids_vtype, 'catchup',406accelfactor=self.accelfactor_follower,407decelfactor=self.decelfactor_follower,408tau=self.tau_follower,409sigma=self.sigma_follower,410dist_min=self.dist_min_follower,411coloroffset=np.array([co, co, co, 1], dtype=np.float32),412colorfactor=np.array([0, 0, cf, 1], dtype=np.float32),413carfollowermodel='ACC',414)415416self._add_vtypes(vtypes, ids_vtype, 'catchupFollower',417accelfactor=self.accelfactor_follower,418decelfactor=self.decelfactor_follower,419tau=self.tau_follower,420sigma=self.sigma_follower,421dist_min=self.dist_min_follower,422coloroffset=np.array([0, co, 0, 1], dtype=np.float32),423colorfactor=np.array([0, cf, cf, 1], dtype=np.float32),424carfollowermodel='CACC',425)426427def get_vtypes(self):428"""429Returns used vtypes for export430"""431# ATTENTION: here the platoon vtypes are actually added432if not self.is_enabled:433return []434435print 'Simpla.get_vtypes'436plattype_original = 'original'437# add vtypes for platooning here438self.add_vtypes()439# here we return only the additional vtypes440ids_vtypes_plat = []441for plattypes in self._typemap.values():442for plattype, id_vtype in plattypes.iteritems():443if plattype != plattype_original:444ids_vtypes_plat.append(id_vtype)445# print ' ids_vtypes_plat',ids_vtypes_plat446return ids_vtypes_plat447448def del_vtypes(self):449"""Delete all necessary vtypes for platooning from vtype database."""450451vtypes = self.get_scenario().demand.vtypes452plattype_original = 'original'453ids_vtypes_plat = []454for plattypes in self._typemap.values():455for plattype, id_vtype in plattypes.iteritems():456if plattype != plattype_original:457ids_vtypes_plat.append(id_vtype)458459print 'del_vtypes', ids_vtypes_plat460vtypes.del_rows(ids_vtypes_plat)461self._typemap = {}462463def _add_vtypes(self, vtypes, ids, plattype,464accelfactor=1.0, decelfactor=1.0,465tau=np.nan, sigma=np.nan, dist_min=np.nan,466coloroffset=np.zeros(4, np.float32),467colorfactor=np.ones(4, np.float32),468carfollowermodel='Krauss'):469print '_add_vtypes', ids, plattype470n = len(ids)471ids_new = vtypes.add_rows(n=len(ids))472for colconfig in vtypes.get_attrsman()._colconfigs:473values = colconfig[ids].copy()474475attrname = colconfig.attrname476if attrname == 'ids_sumo':477values += '_'+plattype478elif attrname == 'accels':479values *= accelfactor480elif attrname == 'decels':481values *= decelfactor482483elif attrname == 'colors':484values = np.clip((values+coloroffset)*colorfactor, 0, 1)485486elif (not np.isnan(tau)) & (attrname == 'taus'):487values = np.ones(len(values), dtype=np.float32)*tau488489elif (not np.isnan(sigma)) & (attrname == 'sigmas'):490values = np.ones(len(values), dtype=np.float32)*sigma491492colconfig.set(ids_new, values=values)493494# adjust emergency breake deceleration to495# comfort deceleration496# this reduces headway497vtypes.decels_apparent[ids_new] = vtypes.decels[ids_new]+0.1498vtypes.decels_emergency[ids_new] = vtypes.decels[ids_new]+0.1499# update typemap database500for _id, _id_new in zip(ids, ids_new):501if self._typemap.has_key(_id):502self._typemap[_id][plattype] = _id_new503else:504self._typemap[_id] = {plattype: _id_new}505506return ids_new507508509