1# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
2# Copyright (C) 2016-2019 German Aerospace Center (DLR) and others.
3# SUMOPy module
4# Copyright (C) 2012-2017 University of Bologna - DICAM
5# This program and the accompanying materials
6# are made available under the terms of the Eclipse Public License v2.0
7# which accompanies this distribution, and is available at
8# http://www.eclipse.org/legal/epl-v20.html
9# SPDX-License-Identifier: EPL-2.0
10
11# @file    origin_to_destination.py
12# @author  Joerg Schweizer
13# @date
14# @version $Id$
15
16
17import numpy as np
18from numpy import random
19import agilepy.lib_base.classman as cm
20import agilepy.lib_base.arrayman as am
21import agilepy.lib_base.xmlman as xm
22#from coremodules.modules_common import *
23from coremodules.network.network import SumoIdsConf, MODES
24from coremodules.network import routing
25from agilepy.lib_base.processes import Process, CmlMixin
26#import coremodules.demand.demand as dm
27import demand as dm
28import demandbase as db
29# print 'dir(dm)',dir(dm)
30#from demand import OPTIONMAP_POS_DEPARTURE
31# OPTIONMAP_POS_ARRIVAL
32# OPTIONMAP_SPEED_DEPARTURE
33# OPTIONMAP_SPEED_ARRIVAL
34# OPTIONMAP_LANE_DEPART
35# OPTIONMAP_LANE_ARRIVAL
36
37
38class OdTripgenerator(Process):
39    def __init__(self, odintervals, trips, logger=None, **kwargs):
40        """
41        CURRENTLY NOT IN USE!!
42        """
43        self._init_common('odtripgenerator', name='OD tripgenerator',
44                          logger=logger,
45                          info='Generates trips from OD demand .',
46                          )
47        self._odintervals = odintervals
48
49        attrsman = self.get_attrsman()
50        self.add_option('netfilepath', netfilepath,
51                        # this will make it show up in the dialog
52                        groupnames=['options'],
53                        cml='--sumo-net-file',
54                        perm='rw',
55                        name='Net file',
56                        wildcards='Net XML files (*.net.xml)|*.net.xml',
57                        metatype='filepath',
58                        info='SUMO Net file in XML format.',
59                        )
60
61        self.workdirpath = attrsman.add(cm.AttrConf('workdirpath', rootdirpath,
62                                                    # ['options'],#['_private'],
63                                                    groupnames=['_private'],
64                                                    perm='r',
65                                                    name='Workdir',
66                                                    metatype='dirpath',
67                                                    info='Working directory for this scenario.',
68                                                    ))
69
70        self.rootname = attrsman.add(cm.AttrConf('rootname', rootname,
71                                                 groupnames=['_private'],
72                                                 perm='r',
73                                                 name='Scenario shortname',
74                                                 info='Scenario shortname is also rootname of converted files.',
75                                                 ))
76
77        self.is_clean_nodes = attrsman.add(cm.AttrConf('is_clean_nodes', is_clean_nodes,
78                                                       groupnames=['options'],
79                                                       perm='rw',
80                                                       name='Clean Nodes',
81                                                       info='If set, then shapes around nodes are cleaned up.',
82                                                       ))
83
84    def update_params(self):
85        """
86        Make all parameters consistent.
87        example: used by import OSM to calculate/update number of tiles
88        from process dialog
89        """
90        pass
91        #self.workdirpath = os.path.dirname(self.netfilepath)
92        #bn =  os.path.basename(self.netfilepath).split('.')
93        # if len(bn)>0:
94        #    self.rootname = bn[0]
95
96    def do(self):
97        self.update_params()
98        cml = self.get_cml()+' --plain-output-prefix ' + \
99            filepathlist_to_filepathstring(
100                os.path.join(self.workdirpath, self.rootname))
101        # print 'SumonetImporter.do',cml
102        #import_xml(self, rootname, dirname, is_clean_nodes = True)
103        self.run_cml(cml)
104        if self.status == 'success':
105            self._net.import_xml(
106                self.rootname, self.workdirpath, is_clean_nodes=self.is_clean_nodes)
107            return True
108        else:
109            return False
110        # print 'do',self.newident
111        # self._scenario = Scenario(  self.newident,
112        #                                parent = None,
113        #                                workdirpath = self.workdirpath,
114        #                                logger = self.get_logger(),
115        #                                )
116
117    def get_net(self):
118        return self._net
119
120
121class OdFlowTable(am.ArrayObjman):
122    def __init__(self, parent, modes, zones, activitytypes=None, **kwargs):
123        self._init_objman(ident='odflowtab', parent=parent,
124                          name='OD flows',
125                          info='Table with intervals, modes, OD and respective number of trips.',
126                          #xmltag = ('odtrips','odtrip',None),
127                          **kwargs)
128
129        self.add_col(am.ArrayConf('times_start', 0,
130                                  groupnames=['parameters'],
131                                  perm='r',
132                                  name='Start time',
133                                  unit='s',
134                                  info='Start time of interval in seconds (no fractional seconds).',
135                                  xmltag='t_start',
136                                  ))
137
138        self.add_col(am.ArrayConf('times_end', 3600,
139                                  groupnames=['parameters'],
140                                  perm='r',
141                                  name='End time',
142                                  unit='s',
143                                  info='End time of interval in seconds (no fractional seconds).',
144                                  xmltag='t_end',
145                                  ))
146
147        self.add_col(am.IdsArrayConf('ids_mode', modes,
148                                     groupnames=['parameters'],
149                                     perm='r',
150                                     #choices = MODES,
151                                     name='ID mode',
152                                     xmltag='vClass',
153                                     info='ID of transport mode.',
154                                     ))
155
156        self.add_col(am.IdsArrayConf('ids_orig', zones,
157                                     groupnames=['parameters'],
158                                     name='Orig.',
159                                     perm='r',
160                                     #choices =  zones.ids_sumo.get_indexmap(),
161                                     info='traffic assignment zone of origin of trip.',
162                                     xmltag='id_orig',
163                                     ))
164
165        self.add_col(am.IdsArrayConf('ids_dest', zones,
166                                     groupnames=['parameters'],
167                                     name='Dest.',
168                                     perm='r',
169                                     #choices =  zones.ids_sumo.get_indexmap(),
170                                     info='ID of traffic assignment zone of destination of trip.',
171                                     xmltag='id_dest',
172                                     ))
173
174        self.add_col(am.ArrayConf('tripnumbers', 0,
175                                  groupnames=['state'],
176                                  perm='rw',
177                                  name='Trips',
178                                  info='Number of trips from zone with ID Orig to zone with ID Dest.',
179                                  xmltag='tripnumber',
180                                  ))
181
182        if activitytypes is not None:
183            self.add_col(am.IdsArrayConf('ids_activitytype_orig', activitytypes,
184                                         groupnames=['parameters'],
185                                         perm='rw',
186                                         #choices = activitytypes.names.get_indexmap(),
187                                         name='Activity type at orig.',
188                                         symbol='Act. orig.',
189                                         info='Type of activity performed at origin, before the trip.',
190                                         ))
191
192            self.add_col(am.IdsArrayConf('ids_activitytype_dest', activitytypes,
193                                         groupnames=['parameters'],
194                                         perm='rw',
195                                         #choices = activitytypes.names.get_indexmap(),
196                                         name='Activity type at dest.',
197                                         symbol='Act. dest.',
198                                         info='Type of activity performed at destination, after the trip.',
199                                         ))
200        #self.add( cm.ObjConf( zones, is_child = False,groups = ['_private']))
201
202    def add_flows(self,  time_start,
203                  time_end,
204                  id_mode,
205                  ids_orig,
206                  ids_dest,
207                  tripnumbers,
208                  id_activitytype_orig=1,
209                  id_activitytype_dest=1,
210                  ):
211        n = len(tripnumbers)
212        self.add_rows(n=n,
213                      times_start=time_start*np.ones(n),
214                      times_end=time_end*np.ones(n),
215                      ids_mode=id_mode*np.ones(n),
216                      ids_orig=ids_orig,
217                      ids_dest=ids_dest,
218                      tripnumbers=tripnumbers,
219                      ids_activitytype_orig=id_activitytype_orig*np.ones(n),
220                      ids_activitytype_dest=id_activitytype_dest*np.ones(n),
221                      )
222
223
224class OdTrips(am.ArrayObjman):
225    def __init__(self, ident, parent, zones, **kwargs):
226        self._init_objman(ident, parent=parent,
227                          name='OD trips',
228                          info='Contains the number of trips between an origin and a destination zone.',
229                          version=0.2,
230                          xmltag=('odtrips', 'odtrip', None), **kwargs)
231
232        self._init_attributes(zones)
233
234    def _init_attributes(self, zones=None):
235        # print '_init_attributes',self.ident
236        if not self.has_attrname('zones'):
237            self.add(cm.ObjConf(
238                zones, is_child=False, groups=['_private']))
239        else:
240            # zones is already an attribute
241            zones = self.zones.get_value()
242
243        if self.get_version() < 0.1:
244            # update attrs from previous
245            # IdsArrayConf not yet modifiable interactively, despite perm = 'rw',!!!
246            self.ids_orig.set_perm('rw')
247            self.ids_dest.set_perm('rw')
248
249        if hasattr(self, 'func_delete_row'):
250            self.func_make_row._is_returnval = False
251            self.func_delete_row._is_returnval = False
252
253        self.add_col(am.IdsArrayConf('ids_orig', zones,
254                                     groupnames=['state'],
255                                     perm='rw',
256                                     name='Orig.',
257                                     #choices =  zones.ids_sumo.get_indexmap(),
258                                     info='traffic assignment zone of origin of trip.',
259                                     xmltag='id_orig',
260                                     ))
261
262        self.add_col(am.IdsArrayConf('ids_dest', zones,
263                                     groupnames=['state'],
264                                     perm='rw',
265                                     name='Dest.',
266                                     #choices =  zones.ids_sumo.get_indexmap(),
267                                     info='ID of traffic assignment zone of destination of trip.',
268                                     xmltag='id_dest',
269                                     ))
270
271        self.add_col(am.ArrayConf('tripnumbers', 0,
272                                  groupnames=['state'],
273                                  perm='rw',
274                                  name='Trips',
275                                  info='Number of trips from zone with ID Orig to zone with ID Dest.',
276                                  xmltag='tripnumber',
277                                  ))
278
279        # print '  pre add func_make_row'
280        self.add(cm.FuncConf('func_make_row', 'on_add_row', None,
281                             groupnames=['rowfunctions', '_private'],
282                             name='New OD flow.',
283                             info='Add a new OD flow.',
284                             is_returnval=False,
285                             ))
286        # print '  post add func_make_row'
287        self.add(cm.FuncConf('func_delete_row', 'on_del_row', None,
288                             groupnames=['rowfunctions', '_private'],
289                             name='Del OD flow',
290                             info='Delete OD flow.',
291                             is_returnval=False,
292                             ))
293
294        # print '  _init_attributes done',self.ident
295
296    def _init_constants(self):
297        #self.edgeweights_orig = None
298        #self.edgeweights_dest = None
299        pass
300
301    def on_del_row(self, id_row=None):
302        if id_row is not None:
303            # print 'on_del_row', id_row
304            self.del_row(id_row)
305
306    def on_add_row(self, id_row=None):
307        print 'on_add_row'
308        if len(self) > 0:
309
310            # copy previous
311            od_last = self.get_row(self.get_ids()[-1])
312            #id_orig = self.odtab.ids_orig.get(id_last)
313            #id_dest = self.odtab.ids_dest.get(id_last)
314            #id = self.suggest_id()
315            self.add_row(**od_last)
316        else:
317            self.add_row(self.suggest_id())
318
319    def generate_odflows(self, odflowtab,  time_start, time_end, id_mode, **kwargs):
320        """
321        Insert all od flows in odflowtab.
322        """
323        # for id_od in self.get_ids():
324        odflowtab.add_flows(time_start,
325                            time_end,
326                            id_mode,
327                            self.ids_orig.get_value(),
328                            self.ids_dest.get_value(),
329                            self.tripnumbers.get_value(),
330                            **kwargs
331                            )
332
333    def generate_trips(self, demand, time_start, time_end, id_mode,
334                       pos_depart_default=db.OPTIONMAP_POS_DEPARTURE['random_free'],
335                       #pos_arrival_default = db.OPTIONMAP_POS_ARRIVAL['max'],
336                       pos_arrival_default=db.OPTIONMAP_POS_ARRIVAL['random'],
337                       speed_depart_default=0.0,
338                       speed_arrival_default=0.0,
339                       # pedestrians always depart on lane 0
340                       ind_lane_depart_default=db.OPTIONMAP_LANE_DEPART['allowed'],
341                       # pedestrians always arrive on lane 0
342                       ind_lane_arrival_default=db.OPTIONMAP_LANE_ARRIVAL['current'],
343                       n_trials_connect=5,
344                       is_make_route=True,
345                       ):
346        """
347        Generates trips in demand.trip table.
348        """
349        print 'generate_trips', time_start, time_end, id_mode
350        id_mode_ped = MODES['pedestrian']
351        #OPTIONMAP_POS_DEPARTURE = { -1:"random",-2:"free",-3:"random_free",-4:"base"}
352        #OPTIONMAP_POS_ARRIVAL = { -1:"random",-2:"max"}
353        #OPTIONMAP_SPEED_DEPARTURE = { -1:"random",-2:"max"}
354        #OPTIONMAP_SPEED_ARRIVAL = { -1:"current"}
355        #OPTIONMAP_LANE_DEPART = {-1:"random",-2:"free",-3:"departlane"}
356        #OPTIONMAP_LANE_ARRIVAL = { -1:"current"}
357
358        trips = demand.trips
359        #ids_vtype_mode = demand.vtypes.select_by_mode(id_mode)
360        ids_vtype_mode, prob_vtype_mode = demand.vtypes.select_by_mode(
361            id_mode, is_share=True)
362        # print '  ids_vtype_mode', ids_vtype_mode
363        n_vtypes = len(ids_vtype_mode)
364        zones = self.zones.get_value()
365        edges = zones.ids_edges_orig.get_linktab()
366        edgelengths = edges.lengths
367
368        if n_trials_connect > 0:
369            # initialize routing to verify connection
370            fstar = edges.get_fstar(is_ignor_connections=False)
371            times = edges.get_times(id_mode=id_mode, is_check_lanes=True)
372
373        n_trips_generated = 0
374        n_trips_failed = 0
375
376        is_nocon = False
377        route = []
378        for id_od in self.get_ids():
379            id_orig = self.ids_orig[id_od]
380            id_dest = self.ids_dest[id_od]
381            tripnumber = self.tripnumbers[id_od]
382
383            ids_edges_orig_raw = zones.ids_edges_orig[id_orig]
384            ids_edges_dest_raw = zones.ids_edges_dest[id_dest]
385
386            prob_edges_orig_raw = zones.probs_edges_orig[id_orig]
387            prob_edges_dest_raw = zones.probs_edges_dest[id_dest]
388
389            # check accessibility of origin edges
390            ids_edges_orig = []
391            prob_edges_orig = []
392            inds_lane_orig = []
393            for i in xrange(len(ids_edges_orig_raw)):
394                id_edge = ids_edges_orig_raw[i]
395                # if check accessibility...
396                ind_lane_depart = edges.get_laneindex_allowed(id_edge, id_mode)
397                # print '  get_laneindex_allowed',id_mode,id_edge,edges.ids_sumo[id_edge],ind_lane_depart
398                if ind_lane_depart >= 0:
399                    ids_edges_orig.append(id_edge)
400                    prob_edges_orig.append(prob_edges_orig_raw[i])
401                    inds_lane_orig.append(ind_lane_depart)
402
403            # check accessibility of destination edges
404            ids_edges_dest = []
405            prob_edges_dest = []
406            inds_lane_dest = []
407            for i in xrange(len(ids_edges_dest_raw)):
408                id_edge = ids_edges_dest_raw[i]
409                # if check accessibility...
410                ind_lane_arrival = edges.get_laneindex_allowed(
411                    id_edge, id_mode)
412                if ind_lane_arrival >= 0:
413                    ids_edges_dest.append(id_edge)
414                    prob_edges_dest.append(prob_edges_dest_raw[i])
415                    inds_lane_dest.append(ind_lane_arrival)
416
417            n_edges_orig = len(ids_edges_orig)
418            n_edges_dest = len(ids_edges_dest)
419
420            if (n_edges_orig > 0) & (n_edges_dest > 0) & (tripnumber > 0):
421                # renormalize weights
422                prob_edges_orig = np.array(prob_edges_orig, np.float)
423                prob_edges_orig = prob_edges_orig/np.sum(prob_edges_orig)
424                prob_edges_dest = np.array(prob_edges_dest, np.float)
425                prob_edges_dest = prob_edges_dest/np.sum(prob_edges_dest)
426
427                for d in xrange(int(tripnumber+0.5)):
428                    time_depart = random.uniform(time_start, time_end)
429
430                    if (n_trials_connect > 0) & (id_mode != id_mode_ped):
431                        # check if origin and destination edges are connected
432                        n = n_trials_connect
433                        is_nocon = True
434                        while (n > 0) & is_nocon:
435                            # this algorithm can be improved by calculating
436                            # the minimum cost tree and chacking all destinations
437                            i_orig = np.argmax(random.rand(
438                                n_edges_orig)*prob_edges_orig)
439                            id_edge_orig = ids_edges_orig[i_orig]
440                            i_dest = np.argmax(random.rand(
441                                n_edges_dest)*prob_edges_dest)
442                            id_edge_dest = ids_edges_dest[i_dest]
443
444                            cost, route = routing.get_mincostroute_edge2edge(id_edge_orig,
445                                                                             id_edge_dest,
446                                                                             weights=times,
447                                                                             fstar=fstar
448                                                                             )
449                            is_nocon = len(route) == 0
450                            n -= 1
451                        # print '  found route',len(route),n_trials_connect-n
452                        if not is_make_route:
453                            route = []
454                    else:
455                        # no check if origin and destination edges are connected
456                        i_orig = np.argmax(random.rand(
457                            n_edges_orig)*prob_edges_orig)
458                        id_edge_orig = ids_edges_orig[i_orig]
459
460                        i_dest = np.argmax(random.rand(
461                            n_edges_dest)*prob_edges_dest)
462                        id_edge_dest = ids_edges_dest[i_dest]
463
464                    if not is_nocon:
465                        ind_lane_orig = inds_lane_orig[i_orig]
466                        ind_lane_dest = inds_lane_dest[i_dest]
467
468                        pos_depart = pos_depart_default
469                        pos_arrival = pos_arrival_default
470                        # print '  bef:pos_depart,pos_arrival,id_mode,id_mode_ped',  pos_depart,pos_arrival,id_mode,id_mode_ped
471                        if id_mode_ped == id_mode:
472                            # persons do not understand "random", "max" etc
473                            # so produce a random number here
474
475                            #{ -1:"random",-2:"free",-3:"random_free",-4:"base"}
476                            edgelength = edgelengths[id_edge_orig]
477                            if pos_depart in (-1, -2, -3):
478                                pos_depart = random.uniform(
479                                    0.1*edgelength, 0.9*edgelength, 1)[0]
480                            else:
481                                pos_depart = 0.1*edgelength
482
483                            # { -1:"random",-2:"max"}
484                            edgelength = edgelengths[id_edge_dest]
485                            if pos_arrival == -1:
486                                pos_arrival = random.uniform(
487                                    0.1*edgelength, 0.9*edgelength, 1)[0]
488                            else:
489                                pos_arrival = 0.9*edgelength
490                        # print '  af:pos_depart,pos_arrival,id_mode,id_mode_ped',  pos_depart,pos_arrival,id_mode,id_mode_ped
491                        # print '  n_vtypes',n_vtypes
492                        # print '  random.randint(n_vtypes)',random.randint(n_vtypes)
493                        #id_vtype = ids_vtype_mode[random.randint(n_vtypes)]
494                        id_vtype = ids_vtype_mode[np.argmax(
495                            random.rand(n_vtypes)*prob_vtype_mode)]
496                        id_trip = trips.make_trip(id_vtype=id_vtype,
497                                                  time_depart=time_depart,
498                                                  id_edge_depart=id_edge_orig,
499                                                  id_edge_arrival=id_edge_dest,
500                                                  ind_lane_depart=ind_lane_orig,
501                                                  ind_lane_arrival=ind_lane_dest,
502                                                  position_depart=pos_depart,
503                                                  position_arrival=pos_arrival,
504                                                  speed_depart=speed_depart_default,
505                                                  speed_arrival=speed_arrival_default,
506                                                  route=route,
507                                                  )
508                        # print '  ',id_trip,id_edge_orig,edges.ids_sumo[id_edge_orig],ind_lane_depart
509                        # print '  ',id_trip,self.position_depart[id_trip],
510                        n_trips_generated += 1
511                    else:
512                        n_trips_failed += tripnumber
513            else:
514                n_trips_failed += tripnumber
515
516        print '  n_trips_generated', n_trips_generated
517        print '  n_trips_failed', n_trips_failed
518
519    def add_od_trips(self, scale, names_orig, names_dest, tripnumbers):
520        print 'OdTrips.add_od_trips'
521        # print '  scale, names_orig, names_dest, tripnumbers',scale, names_orig, names_dest, tripnumbers,len(tripnumbers)
522        zones = self.get_zones()
523
524        for name_orig, name_dest, tripnumber in zip(names_orig, names_dest, tripnumbers):
525            # print '  check',name_orig, name_dest, tripnumbers,zones.ids_sumo.has_index(name_orig),zones.ids_sumo.has_index(name_dest)
526            if (zones.ids_sumo.has_index(name_orig)) & (zones.ids_sumo.has_index(name_dest)):
527                print '  add', zones.ids_sumo.get_id_from_index(
528                    name_orig), zones.ids_sumo.get_id_from_index(name_dest)
529                self.add_row(ids_orig=zones.ids_sumo.get_id_from_index(name_orig),
530                             ids_dest=zones.ids_sumo.get_id_from_index(
531                                 name_dest),
532                             tripnumbers=scale * tripnumber)
533            else:
534                print '  WARNING: zone named %s or %s not known' % (
535                    name_orig, names_dest)
536                print '  zones indexmap', zones.get_indexmap()
537                print '  ids_sumo', zones.ids_sumo.get_value()
538                print '  ids_sumo._index_to_id', zones.ids_sumo._index_to_id
539
540    def get_zones(self):
541        return self.ids_dest.get_linktab()
542
543
544class OdModes(am.ArrayObjman):
545    def __init__(self, ident, parent, modes, zones, **kwargs):
546        self._init_objman(ident, parent=parent,
547                          name='Mode OD tables',
548                          info='Contains for each transport mode an OD trip table.',
549                          xmltag=('modesods', 'modeods', 'ids_mode'), **kwargs)
550
551        self.add_col(am.IdsArrayConf('ids_mode', modes,
552                                     groupnames=['state'],
553                                     choices=MODES,
554                                     name='ID mode',
555                                     xmltag='vClass',
556                                     info='ID of transport mode.',
557                                     ))
558
559        self.add_col(cm.ObjsConf('odtrips',
560                                 groupnames=['state'],
561                                 is_save=True,
562                                 name='OD matrix',
563                                 info='Matrix with trips from origin to destintion for a specific mode.',
564                                 ))
565
566        self.add(cm.ObjConf(zones, is_child=False, groups=['_private']))
567
568    def generate_trips(self, demand, time_start, time_end, **kwargs):
569        for id_od_mode in self.get_ids():
570            self.odtrips[id_od_mode].generate_trips(
571                demand, time_start, time_end, self.ids_mode[id_od_mode], **kwargs)
572
573    def generate_odflows(self, odflowtab, time_start, time_end, **kwargs):
574        for id_od_mode in self.get_ids():
575            self.odtrips[id_od_mode].generate_odflows(
576                odflowtab, time_start, time_end, self.ids_mode[id_od_mode], **kwargs)
577
578    def add_od_trips(self, id_mode, scale, names_orig, names_dest, tripnumbers):
579        # print 'OdModes.add_od_trips',id_mode, scale, names_orig, names_dest, tripnumbers
580        ids_mode = self.select_ids(self.ids_mode.get_value() == id_mode)
581        if len(ids_mode) == 0:
582            id_od_modes = self.add_row(ids_mode=id_mode)
583            # print '  create',id_od_modes
584            odtrips = OdTrips((self.odtrips.attrname, id_od_modes),
585                              self, self.zones.get_value())
586            self.odtrips[id_od_modes] = odtrips
587            odtrips.add_od_trips(scale, names_orig, names_dest, tripnumbers)
588            return odtrips
589        else:
590            id_od_modes = ids_mode[0]  # modes are unique
591            # print '  use',id_od_modes
592            self.odtrips[id_od_modes].add_od_trips(
593                scale, names_orig, names_dest, tripnumbers)
594            return self.odtrips[id_od_modes]
595
596
597class OdIntervals(am.ArrayObjman):
598    def __init__(self, ident='odintervals',  parent=None, net=None, zones=None, **kwargs):
599        self._init_objman(ident, parent=parent,  # = demand
600                          name='OD Demand',
601                          info='Contains origin-to-destination zone transport demand for different time intervals.',
602                          xmltag=('odintervals', 'odinteval', None), **kwargs)
603
604        self.add_col(am.ArrayConf('times_start', 0,
605                                  groupnames=['state'],
606                                  perm='rw',
607                                  name='Start time',
608                                  unit='s',
609                                  info='Start time of interval in seconds (no fractional seconds).',
610                                  xmltag='t_start',
611                                  ))
612
613        self.add_col(am.ArrayConf('times_end', 3600,
614                                  groupnames=['state'],
615                                  perm='rw',
616                                  name='End time',
617                                  unit='s',
618                                  info='End time of interval in seconds (no fractional seconds).',
619                                  xmltag='t_end',
620                                  ))
621
622        activitytypes = self.parent.activitytypes
623        self.add_col(am.IdsArrayConf('ids_activitytype_orig', activitytypes,
624                                     groupnames=['parameters'],
625                                     perm='rw',
626                                     #choices = activitytypes.names.get_indexmap(),
627                                     name='Activity type at orig.',
628                                     symbol='Act. orig.',
629                                     info='Type of activity performed at origin, before the trip.',
630                                     #xmltag = 'actType',
631                                     #xmlmap = get_inversemap( activitytypes.names.get_indexmap()),
632                                     ))
633
634        self.add_col(am.IdsArrayConf('ids_activitytype_dest', activitytypes,
635                                     groupnames=['parameters'],
636                                     perm='rw',
637                                     #choices = activitytypes.names.get_indexmap(),
638                                     name='Activity type at dest.',
639                                     symbol='Act. dest.',
640                                     info='Type of activity performed at destination, after the trip.',
641                                     #xmltag = 'actType',
642                                     #xmlmap = get_inversemap( activitytypes.names.get_indexmap()),
643                                     ))
644
645        self.add_col(cm.ObjsConf('odmodes',
646                                 groupnames=['state'],
647                                 is_save=True,
648                                 name='OD modes',
649                                 info='OD transport demand for all transport modes within the respective time interval.',
650                                 ))
651        self.add(cm.ObjConf(net, is_child=False, groups=['_private']))
652        self.add(cm.ObjConf(zones, is_child=False, groups=['_private']))
653        # print 'OdIntervals.__init__',self,dir(self)
654
655    def generate_trips(self, **kwargs):
656        """
657        Generates trips in trip table.
658        """
659        # make sure zone edges are up to date
660        self.get_zones().refresh_zoneedges()
661        demand = self.parent
662        for id_inter in self.get_ids():
663            self.odmodes[id_inter].generate_trips(demand,   self.times_start[id_inter],
664                                                  self.times_end[id_inter],
665                                                  **kwargs)
666
667    def generate_odflows(self, **kwargs):
668        """
669        Generates a flat table with all OD flows.
670        """
671        odflowtab = OdFlowTable(self, self.get_modes(),
672                                self.get_zones(), self.get_activitytypes())
673        for id_inter in self.get_ids():
674            self.odmodes[id_inter].generate_odflows(odflowtab,
675                                                    self.times_start[id_inter],
676                                                    self.times_end[id_inter],
677                                                    id_activitytype_orig=self.ids_activitytype_orig[id_inter],
678                                                    id_activitytype_dest=self.ids_activitytype_dest[id_inter],
679                                                    **kwargs)
680        return odflowtab
681
682    def clear_od_trips(self):
683        self.clear()
684
685    def add_od_flows(self, t_start, t_end, id_mode,
686                     id_activitytype_orig, id_activitytype_dest,
687                     scale, names_orig, names_dest, tripnumbers):
688
689        # print 'OdIntervals.add_od_flows',t_start, t_end, id_mode, scale
690        ids_inter = self.select_ids(
691            (self.times_start.get_value() == t_start)
692            & (self.times_end.get_value() == t_end)
693            & (self.ids_activitytype_orig.get_value() == id_activitytype_orig)
694            & (self.ids_activitytype_dest.get_value() == id_activitytype_dest)
695        )
696
697        if len(ids_inter) == 0:
698            # no existing interval found. Create a new one
699            id_inter = self.add_row(times_start=t_start, times_end=t_end,
700                                    ids_activitytype_orig=id_activitytype_orig,
701                                    ids_activitytype_dest=id_activitytype_dest,
702                                    )
703            # print '  create new',id_inter
704            #odintervals.add_rows(2, t_start=[0,3600], t_end=[3600, 7200])
705            odmodes = OdModes((self.odmodes.attrname, id_inter), parent=self,
706                              modes=self.get_net().modes, zones=self.get_zones())
707            # NO!! odmodes = OdModes( ('ODMs for modes', id_inter), parent = self, modes = self.get_net().modes, zones = self.get_zones())
708            self.odmodes[id_inter] = odmodes
709
710            odtrips = odmodes.add_od_trips(
711                id_mode, scale, names_orig, names_dest, tripnumbers)
712            return odtrips
713        else:
714
715            # there should be only one demand table found for a certain interval
716            id_inter = ids_inter[0]
717            # print '  use',id_inter
718            odtrips = self.odmodes[id_inter].add_od_trips(
719                id_mode, scale, names_orig, names_dest, tripnumbers)
720            return odtrips
721
722    def add_od_flow(self, t_start, t_end, id_mode,
723                    id_activitytype_orig, id_activitytype_dest,
724                    scale,
725                    name_orig, name_dest, tripnumber):
726
727        # print 'OdIntervals.add_od_flow',t_start, t_end, id_mode, scale, name_orig,name_dest,tripnumber
728        odtrips = self.add_od_flows(t_start, t_end, id_mode,
729                                    id_activitytype_orig, id_activitytype_dest,
730                                    scale,
731                                    [name_orig], [name_dest], [tripnumber])
732
733        return odtrips
734
735    def get_net(self):
736        return self.net.get_value()
737
738    def get_zones(self):
739        return self.zones.get_value()
740
741    def get_modes(self):
742        return self.net.get_value().modes
743
744    def get_activitytypes(self):
745        return self.parent.activitytypes
746