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    virtualpop.py
12# @author  Joerg Schweizer
13# @date
14# @version $Id$
15
16import numpy as np
17from numpy import random
18import agilepy.lib_base.classman as cm
19import agilepy.lib_base.arrayman as am
20import agilepy.lib_base.xmlman as xm
21from agilepy.lib_base.misc import random_choice, get_inversemap
22from agilepy.lib_base.processes import Process
23
24# from coremodules.modules_common import *
25from coremodules.network.network import SumoIdsConf, MODES
26from coremodules.network import routing
27from coremodules.simulation import results as res
28from coremodules.demand.demandbase import *
29import virtualpop_results as res
30
31
32GENDERS = {'male': 0, 'female': 1, 'unknown': -1}
33
34OCCUPATIONS = {'unknown': -1,
35               'worker': 1,
36               'student': 2,
37               'employee': 3,
38               'public employee': 4,
39               'selfemployed': 5,
40               'pensioneer': 6,
41               'other': 7
42               }
43
44
45class Activities(am.ArrayObjman):
46    # http://www.sumo.dlr.de/userdoc/Networks/Building_Networks_from_own_XML-descriptions.html#Edge_Descriptions
47    def __init__(self, ident, virtualpop, **kwargs):
48
49        self._init_objman(ident=ident, parent=virtualpop, name='Activities',
50                          info='Activity database of persons contains type, time, duration and location of activities.',
51                          version=0.0,
52                          **kwargs)
53
54        self._init_attributes()
55
56    def _init_attributes(self):
57
58        # activy types now in demand
59        activitytypes = self.parent.get_demand().activitytypes
60        self.add_col(am.IdsArrayConf('ids_activitytype', activitytypes,
61                                     groupnames=['parameters'],
62                                     choices=activitytypes.names.get_indexmap(),
63                                     name='Type',
64                                     info='Type of activity performed during the stop.',
65                                     #xmltag = 'actType',
66                                     #xmlmap = get_inversemap( activitytypes.names.get_indexmap()),
67                                     ))
68
69        # attention, this may cause trouble durung init if
70        # facilities are not yet initialized
71        self.add_col(am.IdsArrayConf('ids_facility', self.parent.get_scenario().landuse.facilities,
72                                     groupnames=['parameters'],
73                                     name='ID fac.',
74                                     info='Facility ID where activity takes place.',
75                                     #activitytype = 'home',
76                                     ))
77
78        # self.add_col(am.ArrayConf( 'descriptions', '',
79        #                            dtype = np.object,
80        #                            perm='rw',
81        #                            is_index = True,
82        #                            name = 'Description',
83        #                            info = 'Description of activity.',
84        #                            ))
85
86        # self.add_col(am.IdlistsArrayConf( 'ids_landusetypes', self.parent.get_landuse().landusetypes,
87        #                                name = 'Landuse types',
88        #                                info = "Landuse type IDs, eher this activity type can take place.",
89        #                                ))
90
91        self.add_col(am.ArrayConf('hours_begin_earliest', 0.0,
92                                  dtype=np.float32,
93                                  groupnames=['parameters'],
94                                  perm='rw',
95                                  name='Earliest hour begin',
96                                  unit='h',
97                                  info='Earliest hour when this activity can begin.',
98                                  ))
99
100        self.add_col(am.ArrayConf('hours_begin_latest', 1.0,
101                                  dtype=np.float32,
102                                  groupnames=['parameters'],
103                                  perm='rw',
104                                  name='Latest begin hour',
105                                  unit='h',
106                                  info='Latest hour when this activity can begin.',
107                                  ))
108
109        self.add_col(am.ArrayConf('durations_min', 6.0,
110                                  dtype=np.float32,
111                                  groupnames=['parameters'],
112                                  perm='rw',
113                                  name='Min. Duration',
114                                  unit='h',
115                                  info='Minimum activity duration for a person within a day.',
116                                  ))
117
118        self.add_col(am.ArrayConf('durations_max', 8.0,
119                                  dtype=np.float32,
120                                  groupnames=['parameters'],
121                                  perm='rw',
122                                  name='Max. Duration',
123                                  unit='h',
124                                  info='Maximum activity duration for a person within a day.',
125                                  ))
126
127    def get_hours_end_earliest(self, ids):
128        return self.hours_begin_earliest[ids]+self.durations_min[ids]
129
130    def get_hours_end_latest(self, ids):
131        return self.hours_begin_latest[ids]+self.durations_max[ids]
132
133    def get_durations(self, ids, pdf='unit'):
134        durations = np.zeros(len(ids), dtype=np.float32)
135        i = 0
136        for time_start, time_end in zip(
137                np.array(self.durations_min[ids]*3600, dtype=np.int32),
138                np.array(self.durations_max[ids]*3600, dtype=np.int32)):
139
140            durations[i] = np.random.randint(time_start, time_end, 1)
141            i += 1
142        return durations
143
144    def get_times_end(self, ids, pdf='unit'):
145        """
146        Returns an array with activity ending time for the
147        given activity IDs.
148        The ending time is calculated by drawing random samples
149        from the departure interval.
150        The random samples are drawn according to the given probability
151        density function, pdf.
152
153        Input arguments:
154            ids: integer array with activity IDs
155            pdf: probability density function 'unit'|'normal'
156
157        Returned arguments:
158            times_end: integer array with departure times
159        """
160        times_end = np.zeros(len(ids), dtype=np.float32)
161        i = 0
162        for time_start, time_end in zip(
163                np.array(self.get_hours_end_earliest(ids)*3600, dtype=np.int32),
164                np.array(self.get_hours_end_latest(ids)*3600, dtype=np.int32)):
165
166            times_end[i] = np.random.randint(time_start, time_end, 1)
167            i += 1
168
169        return times_end
170
171    def get_times_begin(self, ids, pdf='unit'):
172        """
173        Returns an array with beginning time for the
174        given activity IDs.
175        The begin time is calculated by drawing random samples
176        from the departure interval.
177        The random samples are drawn according to the given probability
178        density function, pdf.
179
180        Input arguments:
181            ids: integer array with activity IDs
182            pdf: probability density function 'unit'|'normal'
183
184        Returned arguments:
185            times_begin: integer array with departure times
186        """
187        times_begin = np.zeros(len(ids), dtype=np.float32)
188        i = 0
189        for time_start, time_end in zip(
190                np.array(self.get_hours_begin_earliest(ids)*3600, dtype=np.int32),
191                np.array(self.get_hours_begin_latest(ids)*3600, dtype=np.int32)):
192
193            times_begin[i] = np.random.randint(time_start, time_end, 1)
194            i += 1
195
196        return times_begin
197
198
199class IndividualAutos(am.ArrayObjman):
200
201    def __init__(self, ident, population, **kwargs):
202        # print 'individualvehicle vtype id_default',vtypes.ids_sumo.get_id_from_index('passenger1')
203        self._init_objman(ident=ident,
204                          parent=population,
205                          name='Indiv. Autos',
206                          info='Individual auto database. These are privately owned autos.',
207                          **kwargs)
208
209        self._init_attributes()
210        self._init_constants()
211
212    def _init_constants(self):
213
214        self.do_not_save_attrs(['mode', 'mode_prefix',
215                                '_edges', '_lanes', '_individualvehicle', '_ids_vtype_sumo', '_ids_edge_sumo',
216                                '_id_mode', '_get_laneid_allowed', '_get_sumoinfo_from_id_lane',
217                                '_space_access', '_parking', '_time_after_unboarding',
218                                ])
219
220    def def_mode(self):
221        self.mode = 'passenger'
222        self.mode_prefix = 'iauto'
223
224    def _init_attributes(self):
225        vtypes = self.parent.get_demand().vtypes
226        self.def_mode()
227
228        ids_vtype = vtypes.select_by_mode(mode=self.mode)
229
230        self.add(cm.AttrConf('space_access', 0.5,
231                             groupnames=['options'],
232                             perm='rw',
233                             name='Space access',
234                             unit='m',
235                             info='Space to access vehicles at parkings. This is typically less than the vehicle length.',
236                             ))
237
238        self.add(cm.AttrConf('time_after_unboarding', 5,
239                             groupnames=['options'],
240                             perm='rw',
241                             name='time after unboarding',
242                             unit='s',
243                             info='Time the vehicle waits before disappearing after unboarding.',
244                             ))
245
246        self.add_col(am.IdsArrayConf('ids_vtype', vtypes,
247                                     id_default=ids_vtype[0],
248                                     groupnames=['state'],
249                                     name='Veh. type',
250                                     info='Vehicle type.',
251                                     #xmltag = 'type',
252                                     ))
253
254        self.add_col(am.IdsArrayConf('ids_person', self.parent,
255                                     groupnames=['state'],
256                                     name='ID person',
257                                     info='ID of person who ownes the vehicle.',
258                                     ))
259
260        self.add_col(am.ArrayConf('times_exec', 0.0,
261                                  name='Exec time',
262                                  info='Total route execution time from simulation run of last plan.',
263                                  unit='s',
264                                  ))
265
266    def get_virtualpop(self):
267        return self.parent
268
269    def get_ids_veh_pop(self):
270        """
271        To be overridden by other individual vehicle types.
272        """
273        return self.get_virtualpop().ids_iauto
274
275    def get_share(self, is_abs=False):
276        n_veh = len(self)
277        if is_abs:
278            return n_veh
279        else:
280            return float(n_veh)/float(len(self.get_virtualpop()))
281
282    def get_stagetable(self):
283        return self.parent.get_plans().get_stagetable('autorides')
284
285    def get_demand(self):
286        return self.parent.parent
287
288    def clear_vehicles(self):
289        self.get_ids_veh_pop()[self.ids_person.get_value()] = -1
290        self.clear()
291
292    def assign_to_persons(self, ids_person):
293        # print 'assign_to_persons',len(ids_person),self.mode
294        # self.clear_vehicles()
295        #ids_person_noveh = set(ids_person).difference(set(self.ids_person))
296        n_new = len(ids_person)
297        #
298        # this call is selecting a veh id aof the specific mode
299        # according to its share within this mode
300        ids_vtype = self.get_demand().vtypes.generate_vtypes_for_mode(n_new, mode=self.mode)
301
302        # print '  ids_vtype',ids_vtype
303        ids_veh = self.add_rows(n=n_new,
304                                ids_person=ids_person,
305                                ids_vtype=ids_vtype,
306                                )
307        self.get_ids_veh_pop()[ids_person] = ids_veh
308        return ids_veh
309
310    def get_vtypes(self):
311        """
312        Returns a set with all used vehicle types.
313        """
314        # print 'Vehicles_individual.get_vtypes',self.cols.vtype
315        return set(self.ids_vtype.get_value())
316
317    def get_id_veh_xml(self, id_veh, id_stage):
318        return self.mode_prefix + '.%s.%s' % (id_veh, id_stage)
319
320    def get_id_line_xml(self, id_veh):
321        return self.mode_prefix + '.%s' % (id_veh)
322
323    def get_id_from_id_sumo(self, id_veh_sumo):
324        # print 'get_id_from_id_sumo',id_veh_sumo,id_veh_sumo.split('.'),self.mode_prefix
325        if len(id_veh_sumo.split('.')) == 3:
326            prefix, id_veh, id_stage = id_veh_sumo.split('.')
327            if prefix == self.mode_prefix:
328                return int(id_veh)
329            else:
330                return -1
331        return -1
332
333    # def append_ride(self, id_veh, id_ride):
334    #    ids_ride = self.ids_rides[id_veh]
335    #    if ids_ride  is None:
336    #        self.ids_rides[id_veh] = [id_ride]
337    #    else:
338    #        ids_ride.append(id_ride)
339    def prepare_write_xml(self):
340        """
341        Prepare xml export. Must return export function.
342        """
343        virtualpop = self.get_virtualpop()
344        scenario = virtualpop.get_scenario()
345        #plans = virtualpop.get_plans()
346
347        self._rides = self.get_stagetable()
348        self._edges = scenario.net.edges
349        self._lanes = scenario.net.lanes
350        #self._individualvehicle = virtualpop.get_ibikes()
351        self._ids_vtype_sumo = scenario.demand.vtypes.ids_sumo
352        self._ids_edge_sumo = self._edges.ids_sumo
353        self._id_mode = scenario.net.modes.get_id_mode(self.mode)
354        self._get_laneid_allowed = self._edges.get_laneid_allowed
355        self._get_sumoinfo_from_id_lane = scenario.net.lanes.get_sumoinfo_from_id_lane
356        self._space_access = self.space_access.get_value()
357        #self._time_veh_wait_after_stop = 3600
358        self._parking = virtualpop.get_landuse().parking
359        self._time_after_unboarding = self.time_after_unboarding.get_value()
360        return self.write_xml
361
362    def get_id_veh(self, id_stage):
363        return self._rides.ids_iauto[id_stage]
364
365    def write_xml(self,  fd, id_stage, time_begin, indent=2):
366
367        # TODO: actually this should go in individualvehicle
368        #time_veh_wait_after_stop = 3600
369        #plans = self.get_plans()
370        #walkstages = plans.get_stagetable('walks')
371        #rides = plans.get_stagetable('autorides')
372        #activitystages = plans.get_stagetable('activities')
373
374        rides = self._rides
375        #lanes = self._lanes
376        parking = self._parking
377        #net = self.get_net()
378        #lanes = net.lanes
379        #edges = net.edges
380        #ind_ride = rides.get_inds(id_stage)
381        id_veh = self.get_id_veh(id_stage)
382        #individualvehicle = self._iveh
383        id_vtype = self.ids_vtype[id_veh]
384
385        # id_veh_ride,
386        #                            ids_vtypes_iveh[id_veh],
387        #                            ids_edges_rides_arr[ind_ride],
388        #                            ids_parking_from_rides_arr[ind_ride],
389        #                            ids_parking_to_rides_arr[ind_ride],
390
391        id_parking_from = rides.ids_parking_from[id_stage]
392        id_lane_from = parking.ids_lane[id_parking_from]
393        #laneindex_from =  self._lanes.indexes[id_lane_from]
394        pos_from = parking.positions[id_parking_from]
395
396        id_parking_to = rides.ids_parking_to[id_stage]
397        id_lane_to = parking.ids_lane[id_parking_to]
398        #laneindex_to =  self._lanes.indexes[id_lane_to]
399        pos_to = parking.positions[id_parking_to]
400
401        # write unique veh ID to prevent confusion with other veh declarations
402        fd.write(xm.start('vehicle id="%s"' % self.get_id_veh_xml(id_veh, id_stage), indent+2))
403
404        # get start time of first stage of the plan
405        #id_plan = rides.ids_plan[id_stage]
406        #stages0, id_stage0 = self.get_plans().stagelists[id_plan][0]
407
408        # this is the time when the vehicle appers in the scenario
409        fd.write(xm.num('depart', '%.d' % rides.times_init[id_stage]))
410        #fd.write(xm.num('depart', '%.d'%stages0.times_start[id_stage0]))
411
412        fd.write(xm.num('type', self._ids_vtype_sumo[id_vtype]))
413        fd.write(xm.num('line', self.get_id_line_xml(id_veh)))
414        fd.write(xm.num('departPos', pos_from))
415        fd.write(xm.num('departLane', self._lanes.indexes[id_lane_from]))
416
417        fd.write(xm.stop())
418
419        # write route
420        fd.write(xm.start('route', indent+4))
421        # print '  edgeindex[ids_edge]',edgeindex[ids_edge]
422        fd.write(xm.arr('edges', self._ids_edge_sumo[rides.ids_edges[id_stage]]))
423
424        # does not seem to have an effect, always starts at base????
425        #fd.write(xm.num('departPos', pos_from))
426        #fd.write(xm.num('departLane', laneindex_from ))
427        fd.write(xm.stopit())
428
429        # write depart stop
430        fd.write(xm.start('stop', indent+4))
431        #id_lane = self._lanes.ids_edge[id_lane_from]
432        fd.write(xm.num('lane', self._get_sumoinfo_from_id_lane(id_lane_from)))
433        # in 0.31 the vehicle will wait until after this duration
434        # so it will be removed unless it will get a timeout function
435        #fd.write(xm.num('duration', time_veh_wait_after_stop))
436        fd.write(xm.num('startPos', pos_from - parking.lengths[id_parking_from]))
437        fd.write(xm.num('endPos', pos_from))
438        fd.write(xm.num('triggered', "True"))
439
440        # chrashes with parking=True in 0.30!
441        # however if not parked the vhcle is blocking the traffic
442        # while waiting: workaround: delay departure to be shure that person already arrived
443
444        fd.write(xm.num('parking', "True"))  # in windows 0.30 parked vehicles do not depart!!
445        #fd.write(xm.num('parking', "False"))
446        fd.write(xm.stopit())
447
448        # write arrival stop
449        fd.write(xm.start('stop', indent+4))
450        fd.write(xm.num('lane', self._get_sumoinfo_from_id_lane(id_lane_to)))
451        fd.write(xm.num('duration', self._time_after_unboarding))  # for unboarding only
452        fd.write(xm.num('startPos', pos_to - parking.lengths[id_parking_to]))
453        fd.write(xm.num('endPos', pos_to))
454        #fd.write(xm.num('triggered', "True"))
455        fd.write(xm.stopit())
456
457        fd.write(xm.end('vehicle', indent+2))
458
459
460class IndividualBikes(IndividualAutos):
461
462    def __init__(self, ident, population, **kwargs):
463        # print 'individualvehicle vtype id_default',vtypes.ids_sumo.get_id_from_index('passenger1')
464        self._init_objman(ident=ident,
465                          parent=population,
466                          name='Indiv. Bikes',
467                          info='Individual bike database. These are privately owned bikes.',
468                          **kwargs)
469        self._init_attributes()
470        self._init_constants()
471
472    def _init_attributes(self):
473
474        IndividualAutos._init_attributes(self)
475
476    def _init_constants(self):
477
478        self.do_not_save_attrs(['mode', 'mode_prefix',
479                                '_edges', '_ids_vtype_sumo', '_ids_edge_sumo',
480                                '_id_mode', '_get_laneid_allowed', '_get_sumoinfo_from_id_lane',
481                                '_space_access',
482                                ])
483
484    def def_mode(self):
485        self.mode = 'bicycle'
486        self.mode_prefix = 'ibike'
487
488    def get_ids_veh_pop(self):
489        """
490        To be overridden by other individual vehicle types.
491        """
492        return self.parent.ids_ibike
493
494    def get_stagetable(self):
495        return self.parent.get_plans().get_stagetable('bikerides')
496
497    def get_id_veh(self, id_stage):
498        return self._rides.ids_ibike[id_stage]
499
500    def prepare_write_xml(self):
501        """
502        Prepare xml export. Must return export function.
503        """
504        virtualpop = self.get_virtualpop()
505        scenario = virtualpop.get_scenario()
506        #plans = virtualpop.get_plans()
507        self._rides = self.get_stagetable()
508        self._edges = scenario.net.edges
509        #self._individualvehicle = virtualpop.get_ibikes()
510        self._ids_vtype_sumo = scenario.demand.vtypes.ids_sumo
511        self._ids_edge_sumo = self._edges.ids_sumo
512        self._id_mode = scenario.net.modes.get_id_mode(self.mode)
513        self._get_laneid_allowed = self._edges.get_laneid_allowed
514        self._get_sumoinfo_from_id_lane = scenario.net.lanes.get_sumoinfo_from_id_lane
515        self._space_access = self.space_access.get_value()
516        return self.write_xml
517
518    # def _limit_pos(self,pos,id_edge):
519
520    def write_xml(self,  fd, id_stage, time_begin, indent=2):
521        rides = self._rides
522        id_veh = self.get_id_veh(id_stage)
523        # print 'write_xml',id_stage, time_begin,self.get_id_veh_xml(id_veh, id_stage)
524        # print '  ids_edge_from,ids_edge_to',rides.ids_edge_from[id_stage],rides.ids_edge_to[id_stage],self._get_laneid_allowed( rides.ids_edge_from[id_stage], self._id_mode),self._get_laneid_allowed( rides.ids_edge_to[id_stage], self._id_mode)
525
526        # TODO: actually this should go in individualvehicle
527        #time_veh_wait_after_stop = 3600
528        #plans = self.get_plans()
529        #walkstages = plans.get_stagetable('walks')
530        #rides = plans.get_stagetable('bikerides')
531        #activitystages = plans.get_stagetable('activities')
532
533        # for debug only:
534        #virtualpop = self.get_virtualpop()
535        #ids_edge_sumo = virtualpop.get_net().edges.ids_sumo
536
537        #parking = self.get_landuse().parking
538        #net = self.get_net()
539        #lanes = net.lanes
540        #edges = net.edges
541
542        #ind_ride = rides.get_inds(id_stage)
543
544        #individualvehicle = self.get_ibikes()
545        id_vtype = self.ids_vtype[id_veh]
546
547        # id_veh_ride,
548        #                            ids_vtypes_iveh[id_veh],
549        #                            ids_edges_rides_arr[ind_ride],
550        #                            ids_parking_from_rides_arr[ind_ride],
551        #                            ids_parking_to_rides_arr[ind_ride],
552
553        #id_parking_from = rides.ids_parking_from[id_stage]
554        #id_lane_from = parking.ids_lane[id_parking_from]
555        #laneindex_from =  lanes.indexes[id_lane_from]
556        #pos_from = parking.positions[id_parking_from]
557
558        #id_parking_to = rides.ids_parking_to[id_stage]
559        #id_lane_to = parking.ids_lane[id_parking_to]
560        #laneindex_to =  lanes.indexes[id_lane_to]
561        #pos_to = parking.positions[id_parking_to]
562
563        # write unique veh ID to prevent confusion with other veh declarations
564        fd.write(xm.start('vehicle id="%s"' % self.get_id_veh_xml(id_veh, id_stage), indent+2))
565
566        # get start time of first stage of the plan
567        #id_plan = rides.ids_plan[id_stage]
568        #stages0, id_stage0 = self.get_plans().stagelists[id_plan][0]
569
570        # this is the time when the vehicle appers in the scenario
571        #fd.write(xm.num('depart', '%.d'%rides.times_init[id_stage]))
572        fd.write(xm.num('depart', '%.d' % time_begin))
573        fd.write(xm.num('type', self._ids_vtype_sumo[id_vtype]))
574        fd.write(xm.num('line', self.get_id_line_xml(id_veh)))
575        #fd.write(xm.num('departPos', pos_from))
576        #fd.write(xm.num('departLane', laneindex_from ))
577        fd.write(xm.num('from', self._ids_edge_sumo[rides.ids_edge_from[id_stage]]))
578        pos_from = rides.positions_from[id_stage]
579        pos_to = rides.positions_to[id_stage]
580        fd.write(xm.num('departPos', pos_from))
581        fd.write(xm.num('arrivalPos', pos_to))
582        fd.write(xm.num('departLane', 'best'))
583
584        fd.write(xm.stop())
585
586        # write route
587        fd.write(xm.start('route', indent+4))
588        # print '  ids_edges',rides.ids_edges[id_stage]
589        # print '  ids_sumo',self._ids_edge_sumo[rides.ids_edges[id_stage]]
590        fd.write(xm.arr('edges', self._ids_edge_sumo[rides.ids_edges[id_stage]]))
591        # fd.write(xm.arr('edges',edges.ids_sumo[rides.ids_edges[id_stage]]))
592
593        # does not seem to have an effect, always starts at base????
594
595        #id_edge = rides.ids_edge_from[id_stage]
596        # print '  id_lane',id_lane,self._get_sumoinfo_from_id_lane(id_lane),'id_edge',id_edge,ids_edge_sumo[id_edge]
597
598        fd.write(xm.stopit())
599
600        # write depart stop
601        fd.write(xm.start('stop', indent+4))
602        id_lane = self._get_laneid_allowed(rides.ids_edge_from[id_stage], self._id_mode)
603        fd.write(xm.num('lane', self._get_sumoinfo_from_id_lane(id_lane)))
604        # in 0.31 the vehicle will wait until after this duration
605        # so it will be removed unless it will get a timeout function
606        #fd.write(xm.num('duration', time_veh_wait_after_stop))
607        if pos_from > self._space_access:
608            fd.write(xm.num('startPos', pos_from - self._space_access))
609            fd.write(xm.num('endPos', pos_from+self._space_access))
610        else:
611            fd.write(xm.num('startPos', 0.1*pos_from))
612            fd.write(xm.num('endPos', pos_from+self._space_access))
613
614        fd.write(xm.num('triggered', "True"))
615
616        # chrashes with parking=True in 0.30!
617        # however if not parked the vhcle is blocking the traffic
618        # while waiting: workaround: delay departure to be shure that person already arrived
619
620        fd.write(xm.num('parking', 'True'))  # in windows 0.30 parked vehicles do not depart!!
621        #fd.write(xm.num('parking', "False"))
622        fd.write(xm.stopit())
623
624        # write arrival stop
625        fd.write(xm.start('stop', indent+4))
626
627        id_lane = self._get_laneid_allowed(rides.ids_edge_to[id_stage], self._id_mode)
628        #id_edge = rides.ids_edge_to[id_stage]
629        # print '  id_lane',id_lane,self._get_sumoinfo_from_id_lane(id_lane),'id_edge',id_edge,ids_edge_sumo[id_edge]
630
631        fd.write(xm.num('lane', self._get_sumoinfo_from_id_lane(id_lane)))
632        fd.write(xm.num('duration', 5))  # for unboarding only
633        if pos_to > self._space_access:
634            fd.write(xm.num('startPos', pos_to - self._space_access))
635            fd.write(xm.num('endPos', pos_to))
636        else:
637            fd.write(xm.num('startPos', 0.1*pos_to))
638            fd.write(xm.num('endPos', pos_to))
639        #fd.write(xm.num('triggered', "True"))
640        fd.write(xm.stopit())
641
642        fd.write(xm.end('vehicle', indent+2))
643
644
645class IndividualMotorcycles(IndividualBikes):
646
647    def __init__(self, ident, population, **kwargs):
648        # print 'individualvehicle vtype id_default',vtypes.ids_sumo.get_id_from_index('passenger1')
649        self._init_objman(ident=ident,
650                          parent=population,
651                          name='Indiv. Moto',
652                          info='Individual Motorcycle/moped database. These are privately owned motorcycles.',
653                          **kwargs)
654        IndividualBikes._init_attributes(self)
655        IndividualBikes._init_constants(self)
656
657    def def_mode(self):
658        self.mode = 'moped'
659        self.mode_prefix = 'imoto'
660
661    def get_ids_veh_pop(self):
662        """
663        To be overridden by other individual vehicle types.
664        """
665        return self.parent.ids_imoto
666
667    def get_stagetable(self):
668        return self.parent.get_plans().get_stagetable('motorides')
669
670    def get_id_veh(self, id_stage):
671        return self._rides.ids_imoto[id_stage]
672
673
674class StrategyMixin(cm.BaseObjman):
675    def __init__(self, ident, parent=None,
676                 name='Strategy mixin', info='Info on strategy.',
677                 **kwargs):
678        """
679        To be overridden.
680        """
681        # attention parent is the Strategies table
682        self._init_objman(ident, parent, **kwargs)
683        attrsman = self.set_attrsman(cm.Attrsman(self))
684
685    def _init_attributes(self, **kwargs):
686        # print 'StrategyMixin._init_attributes'
687        attrsman = self.get_attrsman()
688
689    def get_id_strategy(self):
690        return self.parent.names.get_id_from_index(self.get_ident())
691
692    def get_scenario(self):
693        return self.parent.parent.get_scenario()
694
695    def get_activities(self):
696        return self.parent.parent.get_activities()
697
698    def get_virtualpop(self):
699        return self.parent.parent
700
701    def get_plans(self):
702        return self.parent.parent.plans
703
704    def clip_positions(self, positions, ids_edge):
705        lengths = self.get_scenario().net.edges.lengths[ids_edge]
706        # print 'clip_positions',positions.shape,ids_edge.shape,lengths.shape
707        positions_clip = np.clip(positions, self.dist_node_min*np.ones(len(positions),
708                                                                       dtype=np.float32), lengths-self.dist_node_min)
709        inds = lengths < 2*self.dist_node_min
710        # print '  inds.shape',inds.shape,positions_clip.shape
711        positions_clip[inds] = 0.5*lengths[inds]
712        return positions_clip
713
714    def _init_attributes_strategy(self, **kwargs):
715        attrsman = self.get_attrsman()
716        self.dist_node_min = attrsman.add(cm.AttrConf('dist_node_min', kwargs.get('dist_node_min', 40.0),
717                                                      groupnames=['options'],
718                                                      perm='rw',
719                                                      name='Min. dist to nodes',
720                                                      unit='m',
721                                                      info='Minimum distance between starting position and node center.',
722                                                      ))
723    # def _init_constants_strategy(self):
724    #    #print '_init_constants_strategy'
725    #    modes = self.get_virtualpop().get_scenario().net.modes
726    #    self._id_mode_bike = modes.get_id_mode('bicycle')
727    #    self._id_mode_auto = modes.get_id_mode('passenger')
728    #    self._id_mode_moto = modes.get_id_mode('motorcycle')
729    #   self.get_attrsman().do_not_save_attrs([
730    #                '_id_mode_bike','_id_mode_auto','_id_mode_moto',
731    #                        ])
732    # print '  _id_mode_auto',self._id_mode_auto
733
734    # def are_feasible(self, ids_person):
735    #    """
736    #    Returns a bool vector, with True values for
737    #    persons where this strategy can be applied.
738    #    """
739    #    return []
740
741    # def is_feasible(self, id_person):
742    #    """
743    #    Returns True if this strategy is feasible for this person.
744    #    Overriden by specific strategy.
745    #    """
746    #    return False
747
748    def preevaluate(self, ids_person):
749        """
750        Preevaluation strategies for person IDs in vector ids_person.
751
752        Returns a preevaluation vector with a preevaluation value
753        for each person ID. The values of the preevaluation vector are as follows:
754            -1 : Strategy cannot be applied
755            0  : Stategy can be applied, but the preferred mode is not used
756            1  : Stategy can be applied, and preferred mode is part of the strategy
757            2  : Strategy uses predomunantly preferred mode
758
759        """
760        return zeros(len(ids_person), dtype=np.int32)
761
762    def plan(self, ids_person, logger=None):
763        """
764        Generates a plan for these person according to this strategie.
765        Overriden by specific strategy.
766        """
767        pass
768
769
770class NoneStrategy(StrategyMixin):
771    def __init__(self, ident, parent=None,
772                 name='None strategy',
773                 info='With this strategy, no mobility plan is generated.',
774                 **kwargs):
775
776        self._init_objman(ident, parent, name=name, info=info, **kwargs)
777        attrsman = self.set_attrsman(cm.Attrsman(self))
778
779
780class TransitStrategy(StrategyMixin):
781    def __init__(self, ident, parent=None,
782                 name='Public Transport Strategy',
783                 info='With this strategy, the person uses his private auto as main transport mode. He may accept passengers or public transport with P&R',
784                 **kwargs):
785
786        self._init_objman(ident, parent, name=name, info=info, **kwargs)
787        attrsman = self.set_attrsman(cm.Attrsman(self))
788        # specific init
789        self._init_attributes()
790        self._init_constants()
791
792    def _init_attributes(self):
793        # print 'StrategyMixin._init_attributes'
794        pass
795
796    def _init_constants(self):
797        #virtualpop = self.get_virtualpop()
798        #stagetables = virtualpop.get_stagetables()
799
800        #self._walkstages = stagetables.get_stagetable('walks')
801        #self._ridestages = stagetables.get_stagetable('rides')
802        #self._activitystages = stagetables.get_stagetable('activities')
803
804        #self._plans = virtualpop.get_plans()
805        #
806        # print 'AutoStrategy._init_constants'
807        # print dir(self)
808        # self.get_attrsman().do_not_save_attrs(['_activitystages','_ridestages','_walkstages','_plans'])
809
810        modes = self.get_virtualpop().get_scenario().net.modes
811        self._id_mode_bike = modes.get_id_mode('bicycle')
812        self._id_mode_auto = modes.get_id_mode('passenger')
813        self._id_mode_moto = modes.get_id_mode('motorcycle')
814        self._id_mode_bus = modes.get_id_mode('bus')
815        self.get_attrsman().do_not_save_attrs([
816            '_id_mode_bike', '_id_mode_auto', '_id_mode_moto', '_id_mode_bus'
817        ])
818
819    def preevaluate(self, ids_person):
820        """
821        Preevaluation strategies for person IDs in vector ids_person.
822
823        Returns a preevaluation vector with a preevaluation value
824        for each person ID. The values of the preevaluation vector are as follows:
825            -1 : Strategy cannot be applied
826            0  : Stategy can be applied, but the preferred mode is not used
827            1  : Stategy can be applied, and preferred mode is part of the strategy
828            2  : Strategy uses predomunantly preferred mode
829
830        """
831        n_pers = len(ids_person)
832        persons = self.get_virtualpop()
833        preeval = np.zeros(n_pers, dtype=np.int32)
834
835        # TODO: here we could exclude by age or distance facilities-stops
836
837        # put 0 for persons whose preference is not public transport
838        preeval[persons.ids_mode_preferred[ids_person] != self._id_mode_bus] = 0
839
840        # put 2 for persons with car access and who prefer cars
841        preeval[persons.ids_mode_preferred[ids_person] == self._id_mode_bus] = 2
842
843        print '  TransitStrategy.preevaluate', len(np.flatnonzero(preeval))
844        return preeval
845
846    def plan(self, ids_person, logger=None):
847        """
848        Generates a plan for these person according to this strategie.
849        Overriden by specific strategy.
850        """
851        print 'TransitStrategy.pan', len(ids_person)
852        #make_plans_private(self, ids_person = None, mode = 'passenger')
853        # routing necessary?
854        virtualpop = self.get_virtualpop()
855        plans = virtualpop.get_plans()  # self._plans
856        demand = virtualpop.get_demand()
857        ptlines = demand.ptlines
858
859        walkstages = plans.get_stagetable('walks')
860        transitstages = plans.get_stagetable('transits')
861        activitystages = plans.get_stagetable('activities')
862
863        activities = virtualpop.get_activities()
864        activitytypes = demand.activitytypes
865        landuse = virtualpop.get_landuse()
866        facilities = landuse.facilities
867        parking = landuse.parking
868
869        scenario = virtualpop.get_scenario()
870        net = scenario.net
871        edges = net.edges
872        lanes = net.lanes
873        modes = net.modes
874
875        ptstops = net.ptstops
876
877        # print '   demand',demand
878        # print '   demand.ptlines',demand.ptlines,dir(demand.ptlines)
879        # print '   demand.ptlines.get_ptlinks()',demand.ptlines.get_ptlinks()
880        # print '   demand.virtualpop',demand.virtualpop,dir(demand.virtualpop)
881        # print '   demand.trips',demand.trips,dir(demand.trips)
882        if len(ptlines) == 0:
883            print 'WARNING in TrasitStrategy.plan: no transit services available.'
884            return False
885
886        ptlinks = ptlines.get_ptlinks()
887        ptlinktypes = ptlinks.types.choices
888        type_enter = ptlinktypes['enter']
889        type_transit = ptlinktypes['transit']
890        type_board = ptlinktypes['board']
891        type_alight = ptlinktypes['alight']
892        type_transfer = ptlinktypes['transfer']
893        type_walk = ptlinktypes['walk']
894        type_exit = ptlinktypes['exit']
895
896        ptfstar = ptlinks.get_fstar()
897        pttimes = ptlinks.get_times()
898        stops_to_enter, stops_to_exit = ptlinks.get_stops_to_enter_exit()
899
900        ids_stoplane = ptstops.ids_lane
901        ids_laneedge = net.lanes.ids_edge
902
903        times_est_plan = plans.times_est
904        # here we can determine edge weights for different modes
905
906        # this could be centralized to avoid redundance
907        plans.prepare_stagetables(['walks', 'transits', 'activities'])
908
909        ids_person_act, ids_act_from, ids_act_to\
910            = virtualpop.get_activities_from_pattern(0, ids_person=ids_person)
911
912        if len(ids_person_act) == 0:
913            print 'WARNING in TrasitStrategy.plan: no eligible persons found.'
914            return False
915
916        # temporary maps from ids_person to other parameters
917        nm = np.max(ids_person_act)+1
918        map_ids_plan = np.zeros(nm, dtype=np.int32)
919        #ids_plan_act = virtualpop.add_plans(ids_person_act, id_strategy = self.get_id_strategy())
920        map_ids_plan[ids_person_act] = virtualpop.add_plans(ids_person_act, id_strategy=self.get_id_strategy())
921
922        map_times = np.zeros(nm, dtype=np.int32)
923        map_times[ids_person_act] = activities.get_times_end(ids_act_from, pdf='unit')
924
925        # set start time to plans (important!)
926        plans.times_begin[map_ids_plan[ids_person_act]] = map_times[ids_person_act]
927
928        map_ids_fac_from = np.zeros(nm, dtype=np.int32)
929        map_ids_fac_from[ids_person_act] = activities.ids_facility[ids_act_from]
930
931        n_plans = len(ids_person_act)
932        print 'TrasitStrategy.plan n_plans=', n_plans
933
934        # make initial activity stage
935        ids_edge_from = facilities.ids_roadedge_closest[map_ids_fac_from[ids_person_act]]
936        poss_edge_from = facilities.positions_roadedge_closest[map_ids_fac_from[ids_person_act]]
937        # this is the time when first activity starts
938        # first activity is normally not simulated
939
940        names_acttype_from = activitytypes.names[activities.ids_activitytype[ids_act_from]]
941        durations_act_from = activities.get_durations(ids_act_from)
942        times_from = map_times[ids_person_act]-durations_act_from
943        #times_from = activities.get_times_end(ids_act_from, pdf = 'unit')
944
945        for id_plan,\
946            time,\
947            id_act_from,\
948            name_acttype_from,\
949            duration_act_from,\
950            id_edge_from,\
951            pos_edge_from  \
952            in zip(map_ids_plan[ids_person_act],
953                   times_from,
954                   ids_act_from,
955                   names_acttype_from,
956                   durations_act_from,
957                   ids_edge_from,
958                   poss_edge_from):
959
960            id_stage_act, time = activitystages.append_stage(
961                id_plan, time,
962                ids_activity=id_act_from,
963                names_activitytype=name_acttype_from,
964                durations=duration_act_from,
965                ids_lane=edges.ids_lanes[id_edge_from][0],
966                positions=pos_edge_from,
967            )
968
969        ##
970
971        ind_act = 0
972
973        # main loop while there are persons performing
974        # an activity at index ind_act
975        while len(ids_person_act) > 0:
976            ids_plan = map_ids_plan[ids_person_act]
977
978            times_from = map_times[ids_person_act]
979
980            names_acttype_to = activitytypes.names[activities.ids_activitytype[ids_act_to]]
981            durations_act_to = activities.get_durations(ids_act_to)
982
983            ids_fac_from = map_ids_fac_from[ids_person_act]
984            ids_fac_to = activities.ids_facility[ids_act_to]
985
986            centroids_from = facilities.centroids[ids_fac_from]
987            centroids_to = facilities.centroids[ids_fac_to]
988
989            # origin edge and position
990            ids_edge_from = facilities.ids_roadedge_closest[ids_fac_from]
991            poss_edge_from = facilities.positions_roadedge_closest[ids_fac_from]
992
993            # destination edge and position
994            ids_edge_to = facilities.ids_roadedge_closest[ids_fac_to]
995            poss_edge_to = facilities.positions_roadedge_closest[ids_fac_to]
996
997            ids_stop_from = ptstops.get_closest(centroids_from)
998            ids_stop_to = ptstops.get_closest(centroids_to)
999
1000            ids_stopedge_from = ids_laneedge[ids_stoplane[ids_stop_from]]
1001            ids_stopedge_to = ids_laneedge[ids_stoplane[ids_stop_to]]
1002
1003            # do random pos here
1004            poss_stop_from = 0.5*(ptstops.positions_from[ids_stop_from]
1005                                  + ptstops.positions_to[ids_stop_from])
1006
1007            poss_stop_to = 0.5*(ptstops.positions_from[ids_stop_to]
1008                                + ptstops.positions_to[ids_stop_to])
1009
1010            i = 0.0
1011            for id_person, id_plan, time_from, id_act_from, id_act_to, name_acttype_to, duration_act_to, id_edge_from, pos_edge_from, id_edge_to, pos_edge_to, id_stop_from, id_stopedge_from, pos_stop_from, id_stop_to, id_stopedge_to, pos_stop_to\
1012                    in zip(ids_person_act, ids_plan, times_from, ids_act_from, ids_act_to, names_acttype_to, durations_act_to,  ids_edge_from, poss_edge_from, ids_edge_to, poss_edge_to, ids_stop_from, ids_stopedge_from, poss_stop_from, ids_stop_to, ids_stopedge_to, poss_stop_to):
1013                n_pers = len(ids_person_act)
1014                if logger:
1015                    logger.progress(i/n_pers*100)
1016                i += 1.0
1017                print 79*'_'
1018                print '  id_plan=%d, id_person=%d, ' % (id_plan, id_person)
1019
1020                id_stage_walk1, time = walkstages.append_stage(id_plan, time_from,
1021                                                               id_edge_from=id_edge_from,
1022                                                               position_edge_from=pos_edge_from,
1023                                                               id_edge_to=id_stopedge_from,
1024                                                               position_edge_to=pos_stop_from,  # -7.0,
1025                                                               )
1026
1027                # print '    id_stopedge_from',id_stopedge_from
1028                # print '    pos_stop_from',pos_stop_from
1029
1030                # print
1031                # print '    id_stopedge_to',id_stopedge_to
1032                # print '    pos_stop_to',pos_stop_to
1033                # print
1034                # print '    id_stop_from',id_stop_from
1035                # print '    id_stop_to',id_stop_to
1036
1037                durations, linktypes, ids_line, ids_fromstop, ids_tostop =\
1038                    ptlinks.route(id_stop_from, id_stop_to,
1039                                  fstar=ptfstar, times=pttimes,
1040                                  stops_to_enter=stops_to_enter,
1041                                  stops_to_exit=stops_to_exit)
1042
1043                # print '  routing done. make plan..'
1044
1045                if len(linktypes) > 0:
1046                    if linktypes[-1] == type_walk:  # is last stage a walk?
1047                        # remove it, because will go directly to destination
1048                        linktypes = linktypes[:-1]
1049                        ids_line = ids_line[:-1]
1050                        durations = durations[:-1]
1051                        ids_fromstop = ids_fromstop[:-1]
1052                        ids_tostop = ids_tostop[:-1]
1053
1054                # print '  ids_line    ',ids_line
1055                # print '  ids_fromstop',ids_fromstop
1056                # print '  ids_tostop  ',ids_tostop
1057
1058                if len(linktypes) > 0:  # is there any public transport line to take?
1059
1060                    # go though PT links and generate transits and walks to trasfer
1061                    ids_stopedge_from = ids_laneedge[ids_stoplane[ids_fromstop]]
1062                    ids_stopedge_to = ids_laneedge[ids_stoplane[ids_tostop]]
1063                    poss_stop_from = 0.5*(ptstops.positions_from[ids_fromstop]
1064                                          + ptstops.positions_to[ids_fromstop])
1065                    poss_stop_to = 0.5*(ptstops.positions_from[ids_tostop]
1066                                        + ptstops.positions_to[ids_tostop])
1067
1068                    # this is wait time buffer to be added to the successive stage
1069                    # as waiting is currently not modelled as an extra stage
1070                    duration_wait = 0.0
1071
1072                    # create stages for PT
1073                    for linktype, id_line, duration,\
1074                        id_stopedge_from, pos_fromstop,\
1075                        id_stopedge_to, pos_tostop in\
1076                            zip(linktypes,
1077                                ids_line,
1078                                durations,
1079                                ids_stopedge_from, poss_stop_from,
1080                                ids_stopedge_to, poss_stop_to,
1081                                ):
1082                        print '    stage for linktype %2d fromedge %s toedge %s' % (
1083                            linktype, edges.ids_sumo[id_stopedge_from], edges.ids_sumo[id_stopedge_to])
1084
1085                        print '    id_stopedge_from,id_stopedge_to', id_stopedge_from, id_stopedge_to
1086                        if linktype == type_transit:  # transit!
1087                            print '    add transit'
1088                            id_stage_transit, time = transitstages.append_stage(
1089                                id_plan, time,
1090                                id_line=id_line,
1091                                duration=duration+duration_wait,
1092                                id_fromedge=id_stopedge_from,
1093                                id_toedge=id_stopedge_to,
1094                            )
1095                            duration_wait = 0.0
1096
1097                        elif linktype == type_walk:  # walk to transfer
1098                            print '    add transfer'
1099                            id_stage_transfer, time = walkstages.append_stage(
1100                                id_plan, time,
1101                                id_edge_from=id_stopedge_from,
1102                                position_edge_from=pos_fromstop,
1103                                id_edge_to=id_stopedge_to,
1104                                position_edge_to=pos_tostop,
1105                                duration=duration+duration_wait,
1106                            )
1107                            duration_wait = 0.0
1108
1109                        else:  # all other link time are no modelld
1110                            # do not do anything , just add wait time to next stage
1111                            print '    add duration', duration
1112                            duration_wait += duration
1113
1114                    # walk from final stop to activity
1115                    # print '    Stage for linktype %2d fromedge %s toedge %s'%(linktype, edges.ids_sumo[id_stopedge_to],edges.ids_sumo[id_edge_to] )
1116                    id_stage_walk2, time = walkstages.append_stage(id_plan, time,
1117                                                                   id_edge_from=id_stopedge_to,
1118                                                                   position_edge_from=pos_tostop,
1119                                                                   id_edge_to=id_edge_to,
1120                                                                   position_edge_to=pos_edge_to,
1121                                                                   )
1122
1123                else:
1124                    # there is no public transport line linking these nodes.
1125                    # Modify walk directly from home to activity
1126                    time = walkstages.modify_stage(id_stage_walk1, time_from,
1127                                                   id_edge_from=id_edge_from,
1128                                                   position_edge_from=pos_edge_from,
1129                                                   id_edge_to=id_edge_to,
1130                                                   position_edge_to=pos_edge_to,
1131                                                   )
1132
1133                # update time for trips estimation for this plan
1134                plans.times_est[id_plan] += time-time_from
1135
1136                # define current end time without last activity duration
1137                plans.times_end[id_plan] = time
1138
1139                id_stage_act, time = activitystages.append_stage(
1140                    id_plan, time,
1141                    ids_activity=id_act_to,
1142                    names_activitytype=name_acttype_to,
1143                    durations=duration_act_to,
1144                    ids_lane=edges.ids_lanes[id_edge_to][0],
1145                    positions=pos_edge_to,
1146                )
1147
1148                # store time for next iteration in case other activities are
1149                # following
1150                map_times[id_person] = time
1151
1152            # select persons and activities for next setp
1153            ind_act += 1
1154            ids_person_act, ids_act_from, ids_act_to\
1155                = virtualpop.get_activities_from_pattern(ind_act, ids_person=ids_person_act)
1156
1157
1158class WalkStrategy(StrategyMixin):
1159    def __init__(self, ident, parent=None,
1160                 name='Walk Strategy',
1161                 info='With this strategy, the person walks to all destinations.',
1162                 **kwargs):
1163
1164        self._init_objman(ident, parent, name=name, info=info, **kwargs)
1165        attrsman = self.set_attrsman(cm.Attrsman(self))
1166        # specific init
1167        self._init_attributes()
1168        self._init_constants()
1169
1170    def _init_attributes(self):
1171        # print 'StrategyMixin._init_attributes'
1172        pass
1173
1174    def _init_constants(self):
1175        #virtualpop = self.get_virtualpop()
1176        #stagetables = virtualpop.get_stagetables()
1177
1178        #self._walkstages = stagetables.get_stagetable('walks')
1179        #self._ridestages = stagetables.get_stagetable('rides')
1180        #self._activitystages = stagetables.get_stagetable('activities')
1181
1182        #self._plans = virtualpop.get_plans()
1183        #
1184        # print 'AutoStrategy._init_constants'
1185        # print dir(self)
1186        # self.get_attrsman().do_not_save_attrs(['_activitystages','_ridestages','_walkstages','_plans'])
1187
1188        modes = self.get_virtualpop().get_scenario().net.modes
1189        self._id_mode_bike = modes.get_id_mode('bicycle')
1190        self._id_mode_auto = modes.get_id_mode('passenger')
1191        self._id_mode_moto = modes.get_id_mode('motorcycle')
1192        self._id_mode_bus = modes.get_id_mode('bus')
1193        self._id_mode_ped = modes.get_id_mode('pedestrian')
1194        self.get_attrsman().do_not_save_attrs([
1195            '_id_mode_bike', '_id_mode_auto', '_id_mode_moto',
1196            '_id_mode_bus', '_id_mode_ped',
1197        ])
1198
1199    def preevaluate(self, ids_person):
1200        """
1201        Preevaluation strategies for person IDs in vector ids_person.
1202
1203        Returns a preevaluation vector with a preevaluation value
1204        for each person ID. The values of the preevaluation vector are as follows:
1205            -1 : Strategy cannot be applied
1206            0  : Stategy can be applied, but the preferred mode is not used
1207            1  : Stategy can be applied, and preferred mode is part of the strategy
1208            2  : Strategy uses predomunantly preferred mode
1209
1210        """
1211        n_pers = len(ids_person)
1212        persons = self.get_virtualpop()
1213        preeval = np.zeros(n_pers, dtype=np.int32)
1214
1215        # TODO: here we could exclude by age or distance facilities-stops
1216
1217        # put 0 for persons whose preference is not public transport
1218        preeval[persons.ids_mode_preferred[ids_person] != self._id_mode_ped] = 0
1219
1220        # put 2 for persons with car access and who prefer cars
1221        preeval[persons.ids_mode_preferred[ids_person] == self._id_mode_ped] = 2
1222
1223        print '  WalkStrategy.preevaluate', len(np.flatnonzero(preeval))
1224        return preeval
1225
1226    def plan(self, ids_person, logger=None):
1227        """
1228        Generates a plan for these person according to this strategie.
1229        Overriden by specific strategy.
1230        """
1231        print 'WalkStrategy.pan', len(ids_person)
1232        #make_plans_private(self, ids_person = None, mode = 'passenger')
1233        # routing necessary?
1234        virtualpop = self.get_virtualpop()
1235        plans = virtualpop.get_plans()  # self._plans
1236        demand = virtualpop.get_demand()
1237        #ptlines = demand.ptlines
1238
1239        walkstages = plans.get_stagetable('walks')
1240        #transitstages = plans.get_stagetable('transits')
1241        activitystages = plans.get_stagetable('activities')
1242
1243        activities = virtualpop.get_activities()
1244        activitytypes = demand.activitytypes
1245        landuse = virtualpop.get_landuse()
1246        facilities = landuse.facilities
1247        #parking = landuse.parking
1248
1249        scenario = virtualpop.get_scenario()
1250        net = scenario.net
1251        edges = net.edges
1252        lanes = net.lanes
1253        modes = net.modes
1254
1255        #ptstops = net.ptstops
1256
1257        ids_laneedge = net.lanes.ids_edge
1258
1259        times_est_plan = plans.times_est
1260        # here we can determine edge weights for different modes
1261
1262        # this could be centralized to avoid redundance
1263        plans.prepare_stagetables(['walks', 'activities'])
1264
1265        ids_person_act, ids_act_from, ids_act_to\
1266            = virtualpop.get_activities_from_pattern(0, ids_person=ids_person)
1267
1268        if len(ids_person_act) == 0:
1269            print 'WARNING in WalkStrategy.plan: no eligible persons found.'
1270            return False
1271
1272        # temporary maps from ids_person to other parameters
1273        nm = np.max(ids_person_act)+1
1274        map_ids_plan = np.zeros(nm, dtype=np.int32)
1275        #ids_plan_act = virtualpop.add_plans(ids_person_act, id_strategy = self.get_id_strategy())
1276        map_ids_plan[ids_person_act] = virtualpop.add_plans(ids_person_act, id_strategy=self.get_id_strategy())
1277
1278        map_times = np.zeros(nm, dtype=np.int32)
1279        map_times[ids_person_act] = activities.get_times_end(ids_act_from, pdf='unit')
1280
1281        # set start time to plans (important!)
1282        plans.times_begin[map_ids_plan[ids_person_act]] = map_times[ids_person_act]
1283
1284        map_ids_fac_from = np.zeros(nm, dtype=np.int32)
1285        map_ids_fac_from[ids_person_act] = activities.ids_facility[ids_act_from]
1286
1287        n_plans = len(ids_person_act)
1288        print 'TrasitStrategy.plan n_plans=', n_plans
1289
1290        # make initial activity stage
1291        ids_edge_from = facilities.ids_roadedge_closest[map_ids_fac_from[ids_person_act]]
1292        poss_edge_from = facilities.positions_roadedge_closest[map_ids_fac_from[ids_person_act]]
1293        # this is the time when first activity starts
1294        # first activity is normally not simulated
1295
1296        names_acttype_from = activitytypes.names[activities.ids_activitytype[ids_act_from]]
1297        durations_act_from = activities.get_durations(ids_act_from)
1298        times_from = map_times[ids_person_act]-durations_act_from
1299        #times_from = activities.get_times_end(ids_act_from, pdf = 'unit')
1300
1301        for id_plan,\
1302            time,\
1303            id_act_from,\
1304            name_acttype_from,\
1305            duration_act_from,\
1306            id_edge_from,\
1307            pos_edge_from  \
1308            in zip(map_ids_plan[ids_person_act],
1309                   times_from,
1310                   ids_act_from,
1311                   names_acttype_from,
1312                   durations_act_from,
1313                   ids_edge_from,
1314                   poss_edge_from):
1315
1316            id_stage_act, time = activitystages.append_stage(
1317                id_plan, time,
1318                ids_activity=id_act_from,
1319                names_activitytype=name_acttype_from,
1320                durations=duration_act_from,
1321                ids_lane=edges.ids_lanes[id_edge_from][0],
1322                positions=pos_edge_from,
1323            )
1324
1325        ##
1326
1327        ind_act = 0
1328
1329        # main loop while there are persons performing
1330        # an activity at index ind_act
1331        while len(ids_person_act) > 0:
1332            ids_plan = map_ids_plan[ids_person_act]
1333
1334            times_from = map_times[ids_person_act]
1335
1336            names_acttype_to = activitytypes.names[activities.ids_activitytype[ids_act_to]]
1337            durations_act_to = activities.get_durations(ids_act_to)
1338
1339            ids_fac_from = map_ids_fac_from[ids_person_act]
1340            ids_fac_to = activities.ids_facility[ids_act_to]
1341
1342            centroids_from = facilities.centroids[ids_fac_from]
1343            centroids_to = facilities.centroids[ids_fac_to]
1344
1345            # origin edge and position
1346            ids_edge_from = facilities.ids_roadedge_closest[ids_fac_from]
1347            poss_edge_from = facilities.positions_roadedge_closest[ids_fac_from]
1348
1349            # destination edge and position
1350            ids_edge_to = facilities.ids_roadedge_closest[ids_fac_to]
1351            poss_edge_to = facilities.positions_roadedge_closest[ids_fac_to]
1352
1353            #ids_stop_from = ptstops.get_closest(centroids_from)
1354            #ids_stop_to = ptstops.get_closest(centroids_to)
1355
1356            #ids_stopedge_from = ids_laneedge[ids_stoplane[ids_stop_from]]
1357            #ids_stopedge_to = ids_laneedge[ids_stoplane[ids_stop_to]]
1358
1359            # do random pos here
1360            # poss_stop_from = 0.5*(  ptstops.positions_from[ids_stop_from]\
1361            #                        +ptstops.positions_to[ids_stop_from])
1362
1363            # poss_stop_to = 0.5*(  ptstops.positions_from[ids_stop_to]\
1364            #                            +ptstops.positions_to[ids_stop_to])
1365
1366            i = 0.0
1367            for id_person, id_plan, time_from, id_act_from, id_act_to, name_acttype_to, duration_act_to, id_edge_from, pos_edge_from, id_edge_to, pos_edge_to, \
1368                    in zip(ids_person_act, ids_plan, times_from, ids_act_from, ids_act_to, names_acttype_to, durations_act_to,  ids_edge_from, poss_edge_from, ids_edge_to, poss_edge_to):
1369                n_pers = len(ids_person_act)
1370                if logger:
1371                    logger.progress(i/n_pers*100)
1372                i += 1.0
1373                print 79*'_'
1374                print '  id_plan=%d, id_person=%d, ' % (id_plan, id_person)
1375
1376                id_stage_walk1, time = walkstages.append_stage(id_plan, time_from,
1377                                                               id_edge_from=id_edge_from,
1378                                                               position_edge_from=pos_edge_from,
1379                                                               id_edge_to=id_edge_to,
1380                                                               position_edge_to=pos_edge_to,  # -7.0,
1381                                                               )
1382
1383                # update time for trips estimation for this plan
1384                plans.times_est[id_plan] += time-time_from
1385
1386                # define current end time without last activity duration
1387                plans.times_end[id_plan] = time
1388
1389                id_stage_act, time = activitystages.append_stage(
1390                    id_plan, time,
1391                    ids_activity=id_act_to,
1392                    names_activitytype=name_acttype_to,
1393                    durations=duration_act_to,
1394                    ids_lane=edges.ids_lanes[id_edge_to][0],
1395                    positions=pos_edge_to,
1396                )
1397
1398                # store time for next iteration in case other activities are
1399                # following
1400                map_times[id_person] = time
1401
1402            # select persons and activities for next setp
1403            ind_act += 1
1404            ids_person_act, ids_act_from, ids_act_to\
1405                = virtualpop.get_activities_from_pattern(ind_act, ids_person=ids_person_act)
1406
1407
1408class AutoStrategy(StrategyMixin):
1409    def __init__(self, ident, parent=None,
1410                 name='Auto strategy',
1411                 info='With this strategy, the person uses his private auto as main transport mode.',
1412                 **kwargs):
1413
1414        self._init_objman(ident, parent, name=name, info=info, **kwargs)
1415        attrsman = self.set_attrsman(cm.Attrsman(self))
1416        # specific init
1417        self._init_attributes()
1418        self._init_constants()
1419
1420    def _init_attributes(self):
1421        # print 'StrategyMixin._init_attributes'
1422        pass
1423
1424    def _init_constants(self):
1425        #virtualpop = self.get_virtualpop()
1426        #stagetables = virtualpop.get_stagetables()
1427
1428        #self._walkstages = stagetables.get_stagetable('walks')
1429        #self._ridestages = stagetables.get_stagetable('rides')
1430        #self._activitystages = stagetables.get_stagetable('activities')
1431
1432        #self._plans = virtualpop.get_plans()
1433        #
1434        # print 'AutoStrategy._init_constants'
1435        # print dir(self)
1436        # self.get_attrsman().do_not_save_attrs(['_activitystages','_ridestages','_walkstages','_plans'])
1437
1438        modes = self.get_virtualpop().get_scenario().net.modes
1439        self._id_mode_bike = modes.get_id_mode('bicycle')
1440        self._id_mode_auto = modes.get_id_mode('passenger')
1441        self._id_mode_moto = modes.get_id_mode('motorcycle')
1442        self.get_attrsman().do_not_save_attrs([
1443            '_id_mode_bike', '_id_mode_auto', '_id_mode_moto',
1444        ])
1445
1446    def preevaluate(self, ids_person):
1447        """
1448        Preevaluation strategies for person IDs in vector ids_person.
1449
1450        Returns a preevaluation vector with a preevaluation value
1451        for each person ID. The values of the preevaluation vector are as follows:
1452            -1 : Strategy cannot be applied
1453            0  : Stategy can be applied, but the preferred mode is not used
1454            1  : Stategy can be applied, and preferred mode is part of the strategy
1455            2  : Strategy uses predomunantly preferred mode
1456
1457        """
1458        n_pers = len(ids_person)
1459        print 'Autostrategy.preevaluate', n_pers, 'persons'
1460        persons = self.get_virtualpop()
1461        preeval = np.zeros(n_pers, dtype=np.int32)
1462
1463        # put -1 for persons without car access
1464        preeval[persons.ids_iauto[ids_person] == -1] = -1
1465        print '  persons having no auto', len(np.flatnonzero(persons.ids_iauto[ids_person] == -1))
1466
1467        # put 0 for persons with car but with a different preferred mode
1468        preeval[(persons.ids_iauto[ids_person] > -1)
1469                & (persons.ids_mode_preferred[ids_person] != self._id_mode_auto)] = 0
1470
1471        print '  persons with car but with a different preferred mode', len(np.flatnonzero(
1472            (persons.ids_iauto[ids_person] > -1) & (persons.ids_mode_preferred[ids_person] != self._id_mode_auto)))
1473
1474        # put 2 for persons with car access and who prefer the car
1475        preeval[(persons.ids_iauto[ids_person] > -1)
1476                & (persons.ids_mode_preferred[ids_person] == self._id_mode_auto)] = 2
1477        print '  persons  with car access and who prefer the car', len(np.flatnonzero(
1478            (persons.ids_iauto[ids_person] > -1) & (persons.ids_mode_preferred[ids_person] == self._id_mode_auto)))
1479
1480        return preeval
1481
1482    # def are_feasible(self, ids_person):
1483    #    """
1484    #    Returns a bool vector, with True values for
1485    #    persons where this strategy can be applied.
1486    #    """
1487    #    persons = self.get_virtualpop()
1488    #
1489    #    # check if person has a car
1490    #    # one may also check if there is parking available
1491    #    # at all desinations
1492    #    return persons.ids_iautos[ids_person] >= 0
1493
1494    def plan(self, ids_person, logger=None):
1495        """
1496        Generates a plan for these person according to this strategie.
1497        Overriden by specific strategy.
1498        """
1499        #make_plans_private(self, ids_person = None, mode = 'passenger')
1500        # routing necessary?
1501        virtualpop = self.get_virtualpop()
1502        plans = virtualpop.get_plans()  # self._plans
1503        walkstages = plans.get_stagetable('walks')
1504        ridestages = plans.get_stagetable('autorides')
1505        activitystages = plans.get_stagetable('activities')
1506
1507        activities = virtualpop.get_activities()
1508        activitytypes = virtualpop.get_demand().activitytypes
1509        landuse = virtualpop.get_landuse()
1510        facilities = landuse.facilities
1511        parking = landuse.parking
1512
1513        scenario = virtualpop.get_scenario()
1514        edges = scenario.net.edges
1515        lanes = scenario.net.lanes
1516        modes = scenario.net.modes
1517
1518        #times_est_plan = plans.times_est
1519
1520        # here we can determine edge weights for different modes
1521        plans.prepare_stagetables(['walks', 'autorides', 'activities'])
1522
1523        # get initial travel times for persons.
1524        # initial travel times depend on the initial activity
1525
1526        landuse.parking.clear_booking()
1527
1528        ids_person_act, ids_act_from, ids_act_to\
1529            = virtualpop.get_activities_from_pattern(0, ids_person=ids_person)
1530
1531        if len(ids_person_act) == 0:
1532            print 'WARNING in Autostrategy.plan: no eligible persons found.'
1533            return False
1534
1535        # ok
1536
1537        # temporary maps from ids_person to other parameters
1538        nm = np.max(ids_person_act)+1
1539        map_ids_plan = np.zeros(nm, dtype=np.int32)
1540        #ids_plan_act = virtualpop.add_plans(ids_person_act, id_strategy = self.get_id_strategy())
1541        map_ids_plan[ids_person_act] = virtualpop.add_plans(ids_person_act, id_strategy=self.get_id_strategy())
1542
1543        # err
1544        map_times = np.zeros(nm, dtype=np.int32)
1545        map_times[ids_person_act] = activities.get_times_end(ids_act_from, pdf='unit')
1546
1547        # set start time to plans (important!)
1548        plans.times_begin[map_ids_plan[ids_person_act]] = map_times[ids_person_act]
1549
1550        map_ids_fac_from = np.zeros(nm, dtype=np.int32)
1551        map_ids_fac_from[ids_person_act] = activities.ids_facility[ids_act_from]
1552
1553        # err
1554        map_ids_parking_from = np.zeros(nm, dtype=np.int32)
1555        ids_parking_from, inds_vehparking = parking.get_closest_parkings(virtualpop.ids_iauto[ids_person_act],
1556                                                                         facilities.centroids[activities.ids_facility[ids_act_from]])
1557        if len(ids_parking_from) == 0:
1558            return False
1559
1560        # err
1561
1562        map_ids_parking_from[ids_person_act] = ids_parking_from
1563
1564        n_plans = len(ids_person_act)
1565        print 'AutoStrategy.plan n_plans=', n_plans
1566        # print '  map_ids_parking_from[ids_person_act].shape',map_ids_parking_from[ids_person_act].shape
1567        # set initial activity
1568        # this is because the following steps start with travel
1569        # and set the next activity
1570        #names_acttype_from = activitytypes.names[activities.ids_activitytype[ids_act_from]]
1571        # for id_plan
1572
1573        ind_act = 0
1574
1575        # make initial activity stage
1576        ids_edge_from = facilities.ids_roadedge_closest[map_ids_fac_from[ids_person_act]]
1577        poss_edge_from = facilities.positions_roadedge_closest[map_ids_fac_from[ids_person_act]]
1578        # this is the time when first activity starts
1579        # first activity is normally not simulated
1580
1581        names_acttype_from = activitytypes.names[activities.ids_activitytype[ids_act_from]]
1582        durations_act_from = activities.get_durations(ids_act_from)
1583        times_from = map_times[ids_person_act]-durations_act_from
1584        #times_from = activities.get_times_end(ids_act_from, pdf = 'unit')
1585
1586        for id_plan,\
1587            time,\
1588            id_act_from,\
1589            name_acttype_from,\
1590            duration_act_from,\
1591            id_edge_from,\
1592            pos_edge_from  \
1593            in zip(map_ids_plan[ids_person_act],
1594                   times_from,
1595                   ids_act_from,
1596                   names_acttype_from,
1597                   durations_act_from,
1598                   ids_edge_from,
1599                   poss_edge_from):
1600
1601            id_stage_act, time = activitystages.append_stage(
1602                id_plan, time,
1603                ids_activity=id_act_from,
1604                names_activitytype=name_acttype_from,
1605                durations=duration_act_from,
1606                ids_lane=edges.ids_lanes[id_edge_from][0],
1607                positions=pos_edge_from,
1608            )
1609
1610        # main loop while there are persons performing
1611        # an activity at index ind_act
1612        while len(ids_person_act) > 0:
1613            ids_plan = map_ids_plan[ids_person_act]
1614            ids_veh = virtualpop.ids_iauto[ids_person_act]
1615            #inds_pers = virtualpop.get_inds(ids_person)
1616            # self.persons.cols.mode_preferred[inds_pers]='private'
1617
1618            times_from = map_times[ids_person_act]
1619
1620            names_acttype_to = activitytypes.names[activities.ids_activitytype[ids_act_to]]
1621            durations_act_to = activities.get_durations(ids_act_to)
1622
1623            ids_fac_from = map_ids_fac_from[ids_person_act]
1624            ids_fac_to = activities.ids_facility[ids_act_to]
1625
1626            centroids_to = facilities.centroids[ids_fac_to]
1627
1628            # origin edge and position
1629            ids_edge_from = facilities.ids_roadedge_closest[ids_fac_from]
1630            poss_edge_from = facilities.positions_roadedge_closest[ids_fac_from]
1631
1632            # this method will find and occupy parking space
1633            ids_parking_from = map_ids_parking_from[ids_person_act]
1634
1635            # print '  ids_veh.shape',ids_veh.shape
1636            # print '  centroids_to.shape',centroids_to.shape
1637            ids_parking_to, inds_vehparking = parking.get_closest_parkings(ids_veh, centroids_to)
1638
1639            ids_lane_parking_from = parking.ids_lane[ids_parking_from]
1640            ids_edge_parking_from = lanes.ids_edge[ids_lane_parking_from]
1641            poss_edge_parking_from = parking.positions[ids_parking_from]
1642
1643            # print '  ids_parking_to.shape',ids_parking_to.shape
1644            # print '  np.max(parking.get_ids()), np.max(ids_parking_to)',np.max(parking.get_ids()), np.max(ids_parking_to)
1645            ids_lane_parking_to = parking.ids_lane[ids_parking_to]
1646            ids_edge_parking_to = lanes.ids_edge[ids_lane_parking_to]
1647            poss_edge_parking_to = parking.positions[ids_parking_to]
1648
1649            # destination edge and position
1650            ids_edge_to = facilities.ids_roadedge_closest[ids_fac_to]
1651            poss_edge_to = facilities.positions_roadedge_closest[ids_fac_to]
1652
1653            i = 0.0
1654            n_pers = len(ids_person_act)
1655            for id_person, id_plan, time_from, id_act_from, id_act_to, name_acttype_to, duration_act_to, id_veh, id_edge_from, pos_edge_from, id_edge_parking_from, pos_edge_parking_from, id_parking_from, id_parking_to, id_edge_parking_to, pos_edge_parking_to, id_edge_to, pos_edge_to\
1656                    in zip(ids_person_act, ids_plan, times_from, ids_act_from, ids_act_to, names_acttype_to, durations_act_to, ids_veh, ids_edge_from, poss_edge_from, ids_edge_parking_from, poss_edge_parking_from, ids_parking_from, ids_parking_to, ids_edge_parking_to, poss_edge_parking_to, ids_edge_to, poss_edge_to):
1657                if logger:
1658                    logger.progress(i/n_pers*100)
1659                i += 1.0
1660                #plans.set_row(id_plan, ids_person = id_person, ids_strategy = self.get_id_strategy())
1661
1662                #times_est_plan[id_plan] = time-time_start
1663                # map_times[id_person] = self.plan_activity(\
1664                #                id_person, id_plan, time_from,
1665                #                id_act_from, id_act_to,
1666                #                name_acttype_to, duration_act_to,
1667                #                id_veh,
1668                #                id_edge_from, pos_edge_from,
1669                #                id_parking_from, id_edge_parking_from, pos_edge_parking_from,
1670                #                id_parking_to, id_edge_parking_to, pos_edge_parking_to,
1671                #                id_edge_to, pos_edge_to, edges.ids_lanes[id_edge_to][0])
1672
1673                # start creating stages for activity
1674                id_stage_walk1, time = walkstages.append_stage(
1675                    id_plan, time_from,
1676                    id_edge_from=id_edge_from,
1677                    position_edge_from=pos_edge_from,
1678                    id_edge_to=id_edge_parking_from,
1679                    position_edge_to=pos_edge_parking_from-1.5,  # wait 1.5 m before nose of parked car
1680                )
1681
1682                # ride from  car parking to road edge near activity
1683                id_stage_car, time = ridestages.append_stage(
1684                    id_plan, time,
1685                    id_veh=id_veh,
1686                    # delay to be sure that person arrived!(workaround in combination with parking=False)
1687                    time_init=time+30,  # time_from,
1688                    id_parking_from=id_parking_from,
1689                    id_parking_to=id_parking_to,
1690                    # TODO: here we could use id_edge_to as via edge to emulate search for parking
1691                )
1692                if id_stage_car >= 0:
1693                    # print '  car ride successful'
1694                    id_stage_walk2, time = walkstages.append_stage(
1695                        id_plan, time,
1696                        id_edge_from=id_edge_parking_to,
1697                        position_edge_from=pos_edge_parking_to-1.5,  # ecessary?
1698                        id_edge_to=id_edge_to,
1699                        position_edge_to=pos_edge_to,
1700                    )
1701                else:
1702                    # print '  parking not connected or distance too short, modify first walk and go directly to activity'
1703                    # print '  id_stage_walk1',id_stage_walk1,type(id_stage_walk1)
1704                    # print '  id_edge_from',id_edge_from
1705                    # print '  position_edge_from',position_edge_from
1706                    # print '  id_edge_to',id_edge_to
1707                    # print '  position_edge_to',position_edge_to
1708
1709                    time = walkstages.modify_stage(
1710                        id_stage_walk1, time_from,
1711                        id_edge_from=id_edge_from,
1712                        position_edge_from=pos_edge_from,
1713                        id_edge_to=id_edge_to,
1714                        position_edge_to=pos_edge_to,
1715                    )
1716
1717                # store time estimation for this plan
1718                # note that these are the travel times, no activity time
1719                plans.times_est[id_plan] += time-time_from
1720
1721                # define current end time without last activity duration
1722                plans.times_end[id_plan] = time
1723
1724                # finally add activity and respective duration
1725
1726                id_stage_act, time = activitystages.append_stage(
1727                    id_plan, time,
1728                    ids_activity=id_act_to,
1729                    names_activitytype=name_acttype_to,
1730                    durations=duration_act_to,
1731                    ids_lane=edges.ids_lanes[id_edge_to][0],
1732                    positions=pos_edge_to,
1733                )
1734
1735                map_times[id_person] = time
1736                # return time
1737                ##
1738
1739            # select persons and activities for next setp
1740            ind_act += 1
1741            ids_person_act, ids_act_from, ids_act_to\
1742                = virtualpop.get_activities_from_pattern(ind_act, ids_person=ids_person_act)
1743            # update timing with (random) activity duration!!
1744
1745        return True
1746
1747    def plan_activity(self, id_person, id_plan, time_start,
1748                      id_act_from, id_act_to,
1749                      name_acttype_to, duration_act_to,
1750                      id_veh,
1751                      id_edge_from, pos_edge_from,
1752                      id_parking_from, id_edge_parking_from, pos_edge_parking_from,
1753                      id_parking_to, id_edge_parking_to, pos_edge_parking_to,
1754                      id_edge_to, pos_edge_to, id_lane_to):
1755        print 79*'_'
1756        print '  id_plan=%d, id_person=%d, ids_veh=%d' % (id_plan, id_person,  id_veh)
1757
1758        plans = self.get_virtualpop().get_plans()
1759        #stagetables = virtualpop.get_stagetables()
1760        walkstages = plans.get_stagetable('walks')
1761        ridestages = plans.get_stagetable('autorides')
1762        activitystages = plans.get_stagetable('activities')
1763
1764        id_stage_walk1, time = walkstages.append_stage(
1765            id_plan, time_start,
1766            id_edge_from=id_edge_from,
1767            position_edge_from=pos_edge_from,
1768            id_edge_to=id_edge_parking_from,
1769            position_edge_to=pos_edge_parking_from-1.5,  # wait 1.5 m before nose of parked car
1770        )
1771
1772        # ride from  car parking to road edge near activity
1773        id_stage_car, time = ridestages.append_stage(
1774            id_plan, time,
1775            id_veh=id_veh,
1776            # delay to be sure that person arrived!(workaround in combination with parking=False)
1777            time_init=time+30,  # time_start,
1778            id_parking_from=id_parking_from,
1779            id_parking_to=id_parking_to,
1780            # TODO: here we could use id_edge_to as via edge to emulate search for parking
1781        )
1782        if id_stage_car >= 0:
1783                # print '  car ride successful'
1784            id_stage_walk2, time = walkstages.append_stage(
1785                id_plan, time,
1786                id_edge_from=id_edge_parking_to,
1787                position_edge_from=pos_edge_parking_to-1.5,  # ecessary?
1788                id_edge_to=id_edge_to,
1789                position_edge_to=pos_edge_to,
1790            )
1791        else:
1792            # print '  parking not connected or distance too short, modify first walk and go directly to activity'
1793            # print '  id_stage_walk1',id_stage_walk1,type(id_stage_walk1)
1794            # print '  id_edge_from',id_edge_from
1795            # print '  position_edge_from',position_edge_from
1796            # print '  id_edge_to',id_edge_to
1797            # print '  position_edge_to',position_edge_to
1798
1799            time = walkstages.modify_stage(
1800                id_stage_walk1, time_start,
1801                id_edge_from=id_edge_from,
1802                position_edge_from=pos_edge_from,
1803                id_edge_to=id_edge_to,
1804                position_edge_to=pos_edge_to,
1805            )
1806
1807        # store time estimation for this plan
1808        # note that these are the travel times, no activity time
1809        plans.times_est[id_plan] += time-time_start
1810
1811        # define current end time without last activity duration
1812        plans.times_end[id_plan] = time
1813
1814        # finally add activity and respective duration
1815        id_stage_act, time = activitystages.append_stage(
1816            id_plan, time,
1817            ids_activity=id_act_to,
1818            names_activitytype=name_acttype_to,
1819            durations=duration_act_to,
1820            ids_lane=id_lane_to,
1821            positions=pos_edge_to,
1822        )
1823
1824        return time
1825
1826
1827class BikeStrategy(StrategyMixin):
1828    def __init__(self, ident, parent=None,
1829                 name='Bike strategy',
1830                 info='With this strategy, the person uses his private bike as main transport mode.',
1831                 **kwargs):
1832
1833        self._init_objman(ident, parent, name=name, info=info, **kwargs)
1834        attrsman = self.set_attrsman(cm.Attrsman(self))
1835        # specific init
1836        self._init_attributes(**kwargs)
1837        self._init_constants()
1838
1839    def _init_attributes(self, **kwargs):
1840        # print 'StrategyMixin._init_attributes'
1841        attrsman = self.get_attrsman()
1842
1843        self._init_attributes_strategy(**kwargs)
1844        self.n_iter_bikeacces_max = attrsman.add(cm.AttrConf('n_iter_bikeacces_max', kwargs.get('n_iter_bikeacces_max', 5),
1845                                                             groupnames=['options'],
1846                                                             perm='rw',
1847                                                             name='Max. bike access search iterations',
1848                                                             info='Max. number of iterations while searching an edge with bike access.',
1849                                                             ))
1850
1851        self.length_edge_min = attrsman.add(cm.AttrConf('length_edge_min', kwargs.get('length_edge_min', 20.0),
1852                                                        groupnames=['options'],
1853                                                        perm='rw',
1854                                                        name='Min. edge length search',
1855                                                        unit='m',
1856                                                        info='Min. edge length when searching an edge with bike access.',
1857                                                        ))
1858
1859    def _init_constants(self):
1860        #virtualpop = self.get_virtualpop()
1861        #stagetables = virtualpop.get_stagetables()
1862
1863        #self._walkstages = stagetables.get_stagetable('walks')
1864        #self._ridestages = stagetables.get_stagetable('rides')
1865        #self._activitystages = stagetables.get_stagetable('activities')
1866
1867        #self._plans = virtualpop.get_plans()
1868        #
1869        # print 'AutoStrategy._init_constants'
1870        # print dir(self)
1871        # self.get_attrsman().do_not_save_attrs(['_activitystages','_ridestages','_walkstages','_plans'])
1872
1873        modes = self.get_virtualpop().get_scenario().net.modes
1874        self._id_mode_ped = modes.get_id_mode('pedestrian')
1875        self._id_mode_bike = modes.get_id_mode('bicycle')
1876        self._id_mode_auto = modes.get_id_mode('passenger')
1877        self._id_mode_moto = modes.get_id_mode('motorcycle')
1878        self._edges = self.get_virtualpop().get_scenario().net.edges
1879        self.get_attrsman().do_not_save_attrs([
1880            '_id_mode_bike', '_id_mode_auto', '_id_mode_moto',
1881            '_id_mode_ped',
1882            '_edges'])
1883
1884    def preevaluate(self, ids_person):
1885        """
1886        Preevaluation strategies for person IDs in vector ids_person.
1887
1888        Returns a preevaluation vector with a preevaluation value
1889        for each person ID. The values of the preevaluation vector are as follows:
1890            -1 : Strategy cannot be applied
1891            0  : Stategy can be applied, but the preferred mode is not used
1892            1  : Stategy can be applied, and preferred mode is part of the strategy
1893            2  : Strategy uses predomunantly preferred mode
1894
1895        """
1896        n_pers = len(ids_person)
1897        print 'BikeStrategy.preevaluate', n_pers, 'persons'
1898        persons = self.get_virtualpop()
1899        preeval = np.zeros(n_pers, dtype=np.int32)
1900
1901        # put -1 for persons without car access
1902        preeval[persons.ids_ibike[ids_person] == -1] = -1
1903        print '  persons having no bike', len(np.flatnonzero(persons.ids_ibike[ids_person] == -1))
1904
1905        # put 0 for persons with bike but with a different preferred mode
1906        preeval[(persons.ids_ibike[ids_person] > -1)
1907                & (persons.ids_mode_preferred[ids_person] != self._id_mode_bike)] = 0
1908
1909        print '  persons with bike but with a different preferred mode', len(np.flatnonzero(
1910            (persons.ids_ibike[ids_person] > -1) & (persons.ids_mode_preferred[ids_person] != self._id_mode_bike)))
1911
1912        # put 2 for persons with bike access and who prefer the bikr
1913        preeval[(persons.ids_ibike[ids_person] > -1)
1914                & (persons.ids_mode_preferred[ids_person] == self._id_mode_auto)] = 2
1915        print '  persons  with car access and who prefer the car', len(np.flatnonzero(
1916            (persons.ids_ibike[ids_person] > -1) & (persons.ids_mode_preferred[ids_person] == self._id_mode_bike)))
1917
1918        return preeval
1919
1920    def get_edge_bikeaccess(self, id_edge, is_search_backward=False):
1921
1922        # print 'get_edge_bikeaccess',id_edge, is_search_backward,'id_sumo',self._edges.ids_sumo[id_edge]
1923        id_mode = self._id_mode_bike
1924        id_mode_ped = self._id_mode_ped
1925        get_accesslevel = self._edges.get_accesslevel
1926
1927        if is_search_backward:
1928            get_next = self._edges.get_incoming
1929        else:
1930            get_next = self._edges.get_outgoing
1931
1932        edgelengths = self._edges.lengths
1933        #ids_tried = set()
1934        ids_current = [id_edge]
1935        id_bikeedge = -1
1936        pos = 0.0
1937        n = 0
1938        while (id_bikeedge < 0) & (n < self.n_iter_bikeacces_max):
1939            n += 1
1940            ids_new = []
1941            for id_edge_test, is_long_enough in zip(ids_current, edgelengths[ids_current] > self.length_edge_min):
1942                # print '    check id',id_edge_test, is_long_enough,get_accesslevel(id_edge_test, id_mode)
1943                if is_long_enough & (get_accesslevel(id_edge_test, id_mode) >= 0) & (get_accesslevel(id_edge_test, id_mode_ped) >= 0):
1944                    id_bikeedge = id_edge_test
1945                    # print '    found',id_bikeedge,self._edges.ids_sumo[id_bikeedge]
1946                    break
1947                else:
1948                    ids_new += get_next(id_edge_test)
1949
1950            ids_current = ids_new
1951
1952        if id_bikeedge > -1:
1953            if is_search_backward:
1954                pos = edgelengths[id_bikeedge]-0.5*self.length_edge_min
1955            else:
1956                pos = 0.5*self.length_edge_min
1957
1958        if id_bikeedge == -1:
1959            print 'WARNING in get_edge_bikeaccess no access for', id_edge, self._edges.ids_sumo[id_edge]
1960        return id_bikeedge, pos
1961
1962    def plan_bikeride(self, id_plan, time_from, id_veh,
1963                      id_edge_from, pos_edge_from,
1964                      id_edge_to, pos_edge_to,
1965                      dist_from_to, dist_walk_max,
1966                      walkstages, ridestages):
1967
1968        # start creating stages
1969        id_stage_walk1 = -1
1970        id_stage_bike = -1
1971
1972        id_edge_from_bike, pos_from_bike = self.get_edge_bikeaccess(id_edge_from)
1973        id_edge_to_bike, pos_to_bike = self.get_edge_bikeaccess(id_edge_to, is_search_backward=True)
1974
1975        if (dist_from_to < dist_walk_max) | (id_edge_from_bike == -1) | (id_edge_to_bike == -1):
1976            # print '    go by foot because distance is too short or no bike access',dist_from_to,id_edge_from_bike,id_edge_to_bike
1977            id_stage_walk1, time = walkstages.append_stage(
1978                id_plan, time_from,
1979                id_edge_from=id_edge_from,
1980                position_edge_from=pos_edge_from,
1981                id_edge_to=id_edge_to,
1982                position_edge_to=pos_edge_to,
1983            )
1984
1985        else:
1986            # print '    try to take the bike',id_veh
1987            # print '    id_edge_from_bike',edges.ids_sumo[id_edge_from_bike],pos_from_bike
1988            # print '    id_edge_to_bike',edges.ids_sumo[id_edge_to_bike],pos_to_bike
1989
1990            if id_edge_from_bike != id_edge_from:
1991                # print '    must walk from origin to bikerack',time_from
1992
1993                id_stage_walk1, time = walkstages.append_stage(
1994                    id_plan, time_from,
1995                    id_edge_from=id_edge_from,
1996                    position_edge_from=pos_edge_from,
1997                    id_edge_to=id_edge_from_bike,
1998                    position_edge_to=pos_from_bike,
1999                )
2000
2001                if id_edge_to_bike != id_edge_to:
2002                    # print '    must cycle from bikerack to dest bike rack',time
2003                    id_stage_bike, time = ridestages.append_stage(
2004                        id_plan, time,
2005                        id_veh=id_veh,
2006                        # delay to be sure that person arrived!(workaround in combination with parking=False)
2007                        time_init=time-10,  # time_from,
2008                        id_edge_from=id_edge_from_bike,
2009                        position_edge_from=pos_from_bike,
2010                        id_edge_to=id_edge_to_bike,
2011                        position_edge_to=pos_to_bike,
2012                    )
2013                    if id_stage_bike > -1:
2014                        # print '    must walk from dest bikerack to dest',time
2015                        id_stage_walk2, time = walkstages.append_stage(
2016                            id_plan, time,
2017                            id_edge_from=id_edge_to_bike,
2018                            position_edge_from=pos_to_bike,
2019                            id_edge_to=id_edge_to,
2020                            position_edge_to=pos_edge_to,
2021                        )
2022
2023                else:
2024                    # print '    cycle from bikerack to destination',time
2025                    id_stage_bike, time = ridestages.append_stage(
2026                        id_plan, time,
2027                        id_veh=id_veh,
2028                        # delay to be sure that person arrived!(workaround in combination with parking=False)
2029                        time_init=time-10,  # time_from,
2030                        id_edge_from=id_edge_from_bike,
2031                        position_edge_from=pos_from_bike,
2032                        id_edge_to=id_edge_to,
2033                        position_edge_to=pos_edge_to,
2034                    )
2035            else:
2036                # print '    cycle directly from orign edge',time_from
2037                if id_edge_to_bike != id_edge_to:
2038                    # print '    must cycle from origin to bikerack',time_from
2039
2040                    #pos_to_bike = 0.1*edges.lengths[id_edge_to_bike]
2041                    id_stage_bike, time = ridestages.append_stage(
2042                        id_plan, time_from,
2043                        id_veh=id_veh,
2044                        # delay to be sure that person arrived!(workaround in combination with parking=False)
2045                        time_init=time_from-10,  # time_from,
2046                        id_edge_from=id_edge_from,
2047                        position_edge_from=pos_edge_from,
2048                        id_edge_to=id_edge_to_bike,
2049                        position_edge_to=pos_to_bike,
2050                    )
2051                    if id_stage_bike > -1:
2052                        id_stage_walk2, time = walkstages.append_stage(
2053                            id_plan, time,
2054                            id_edge_from=id_edge_to_bike,
2055                            position_edge_from=pos_to_bike,
2056                            id_edge_to=id_edge_to,
2057                            position_edge_to=pos_edge_to,
2058                        )
2059                else:
2060                    # print '    must cycle from origin to destination',time_from
2061                    id_stage_bike, time = ridestages.append_stage(
2062                        id_plan, time_from,
2063                        id_veh=id_veh,
2064                        # delay to be sure that person arrived!(workaround in combination with parking=False)
2065                        time_init=time_from-10,  # time_from,
2066                        id_edge_from=id_edge_from,
2067                        position_edge_from=pos_edge_from,
2068                        id_edge_to=id_edge_to,
2069                        position_edge_to=pos_edge_to,
2070                    )
2071
2072            # here we should have created a bike ride
2073            # if not, for ehatever reason,
2074            # we walk from origin to destination
2075            if id_stage_bike == -1:
2076                # print '    walk because no ride stage has been planned',time_from
2077                if id_stage_walk1 == -1:
2078                    # no walk stage has been planned
2079                    id_stage_walk1, time = walkstages.append_stage(
2080                        id_plan, time_from,
2081                        id_edge_from=id_edge_from,
2082                        position_edge_from=pos_edge_from,
2083                        id_edge_to=id_edge_to,
2084                        position_edge_to=pos_edge_to,
2085                    )
2086
2087                elif time_from == time:
2088                    # walking to bike has already been schedules,
2089                    # but cycling failed. So walk the whole way
2090                    time = walkstages.modify_stage(
2091                        id_stage_walk1, time_from,
2092                        id_edge_from=id_edge_from,
2093                        position_edge_from=pos_edge_from,
2094                        id_edge_to=id_edge_to,
2095                        position_edge_to=pos_edge_to,
2096                    )
2097        return time
2098
2099    def plan(self, ids_person, logger=None):
2100        """
2101        Generates a plan for these person according to this strategie.
2102        Overriden by specific strategy.
2103        """
2104        #make_plans_private(self, ids_person = None, mode = 'passenger')
2105        # routing necessary?
2106        virtualpop = self.get_virtualpop()
2107        plans = virtualpop.get_plans()  # self._plans
2108        walkstages = plans.get_stagetable('walks')
2109        ridestages = plans.get_stagetable('bikerides')
2110        activitystages = plans.get_stagetable('activities')
2111
2112        activities = virtualpop.get_activities()
2113        activitytypes = virtualpop.get_demand().activitytypes
2114        landuse = virtualpop.get_landuse()
2115        facilities = landuse.facilities
2116        #parking = landuse.parking
2117
2118        scenario = virtualpop.get_scenario()
2119        edges = scenario.net.edges
2120        lanes = scenario.net.lanes
2121        modes = scenario.net.modes
2122
2123        #times_est_plan = plans.times_est
2124
2125        # here we can determine edge weights for different modes
2126        plans.prepare_stagetables(['walks', 'bikerides', 'activities'])
2127
2128        # get initial travel times for persons.
2129        # initial travel times depend on the initial activity
2130
2131        # landuse.parking.clear_booking()
2132
2133        ids_person_act, ids_act_from, ids_act_to\
2134            = virtualpop.get_activities_from_pattern(0, ids_person=ids_person)
2135
2136        if len(ids_person_act) == 0:
2137            print 'WARNING in BikeStrategy.plan: no eligible persons found.'
2138            return False
2139
2140        # ok
2141
2142        # temporary maps from ids_person to other parameters
2143        nm = np.max(ids_person_act)+1
2144        map_ids_plan = np.zeros(nm, dtype=np.int32)
2145        map_ids_plan[ids_person_act] = virtualpop.add_plans(ids_person_act, id_strategy=self.get_id_strategy())
2146
2147        map_times = np.zeros(nm, dtype=np.int32)
2148        map_times[ids_person_act] = activities.get_times_end(ids_act_from, pdf='unit')
2149
2150        # set start time to plans (important!)
2151        plans.times_begin[map_ids_plan[ids_person_act]] = map_times[ids_person_act]
2152
2153        map_ids_fac_from = np.zeros(nm, dtype=np.int32)
2154        map_ids_fac_from[ids_person_act] = activities.ids_facility[ids_act_from]
2155
2156        #map_ids_parking_from = np.zeros(nm, dtype = np.int32)
2157        # ids_parking_from, inds_vehparking = parking.get_closest_parkings( virtualpop.ids_iauto[ids_person_act],
2158        # facilities.centroids[activities.ids_facility[ids_act_from]])
2159        # if len(ids_parking_from)==0:
2160        #    return False
2161
2162        # err
2163
2164        #map_ids_parking_from[ids_person_act] = ids_parking_from
2165
2166        n_plans = len(ids_person_act)
2167        print 'BikeStrategy.plan n_plans=', n_plans
2168        # print '  map_ids_parking_from[ids_person_act].shape',map_ids_parking_from[ids_person_act].shape
2169        # set initial activity
2170        # this is because the following steps start with travel
2171        # and set the next activity
2172        #names_acttype_from = activitytypes.names[activities.ids_activitytype[ids_act_from]]
2173        # for id_plan
2174
2175        ind_act = 0
2176
2177        # make initial activity stage
2178        ids_edge_from = facilities.ids_roadedge_closest[map_ids_fac_from[ids_person_act]]
2179
2180        poss_edge_from = facilities.positions_roadedge_closest[map_ids_fac_from[ids_person_act]]
2181        poss_edge_from = self.clip_positions(poss_edge_from, ids_edge_from)
2182
2183        # this is the time when first activity starts
2184        # first activity is normally not simulated
2185
2186        names_acttype_from = activitytypes.names[activities.ids_activitytype[ids_act_from]]
2187        durations_act_from = activities.get_durations(ids_act_from)
2188        times_from = map_times[ids_person_act]-durations_act_from
2189        #times_from = activities.get_times_end(ids_act_from, pdf = 'unit')
2190
2191        # do initial stage
2192        # could be common to all strategies
2193        for id_plan,\
2194            time,\
2195            id_act_from,\
2196            name_acttype_from,\
2197            duration_act_from,\
2198            id_edge_from,\
2199            pos_edge_from  \
2200            in zip(map_ids_plan[ids_person_act],
2201                   times_from,
2202                   ids_act_from,
2203                   names_acttype_from,
2204                   durations_act_from,
2205                   ids_edge_from,
2206                   poss_edge_from):
2207
2208            id_stage_act, time = activitystages.append_stage(
2209                id_plan, time,
2210                ids_activity=id_act_from,
2211                names_activitytype=name_acttype_from,
2212                durations=duration_act_from,
2213                ids_lane=edges.ids_lanes[id_edge_from][0],
2214                positions=pos_edge_from,
2215            )
2216
2217        # main loop while there are persons performing
2218        # an activity at index ind_act
2219        while len(ids_person_act) > 0:
2220            ids_plan = map_ids_plan[ids_person_act]
2221            ids_veh = virtualpop.ids_ibike[ids_person_act]
2222            dists_walk_max = virtualpop.dists_walk_max[ids_person_act]
2223            times_from = map_times[ids_person_act]
2224
2225            names_acttype_to = activitytypes.names[activities.ids_activitytype[ids_act_to]]
2226            durations_act_to = activities.get_durations(ids_act_to)
2227
2228            ids_fac_from = map_ids_fac_from[ids_person_act]
2229            ids_fac_to = activities.ids_facility[ids_act_to]
2230
2231            # origin edge and position
2232            ids_edge_from = facilities.ids_roadedge_closest[ids_fac_from]
2233            poss_edge_from = facilities.positions_roadedge_closest[ids_fac_from]
2234            poss_edge_from = self.clip_positions(poss_edge_from, ids_edge_from)
2235
2236            centroids_from = facilities.centroids[ids_fac_from]
2237
2238            # this method will find and occupy parking space
2239            #ids_parking_from = map_ids_parking_from[ids_person_act]
2240
2241            # print '  ids_veh.shape',ids_veh.shape
2242            # print '  centroids_to.shape',centroids_to.shape
2243            #ids_parking_to, inds_vehparking = parking.get_closest_parkings(ids_veh, centroids_to)
2244
2245            #ids_lane_parking_from = parking.ids_lane[ids_parking_from]
2246            #ids_edge_parking_from = lanes.ids_edge[ids_lane_parking_from]
2247            #poss_edge_parking_from = parking.positions[ids_parking_from]
2248
2249            # print '  ids_parking_to.shape',ids_parking_to.shape
2250            # print '  np.max(parking.get_ids()), np.max(ids_parking_to)',np.max(parking.get_ids()), np.max(ids_parking_to)
2251            #ids_lane_parking_to = parking.ids_lane[ids_parking_to]
2252            #ids_edge_parking_to = lanes.ids_edge[ids_lane_parking_to]
2253            #poss_edge_parking_to = parking.positions[ids_parking_to]
2254
2255            # destination edge and position
2256            ids_edge_to = facilities.ids_roadedge_closest[ids_fac_to]
2257
2258            poss_edge_to1 = facilities.positions_roadedge_closest[ids_fac_to]
2259            poss_edge_to = self.clip_positions(poss_edge_to1, ids_edge_to)
2260            centroids_to = facilities.centroids[ids_fac_to]
2261
2262            # debug poscorrection..OK
2263            # for id_edge, id_edge_sumo, length, pos_to1, pos in zip(ids_edge_to, edges.ids_sumo[ids_edge_to],edges.lengths[ids_edge_to],poss_edge_to1, poss_edge_to):
2264            #    print '  ',id_edge, 'IDe%s'%id_edge_sumo, 'L=%.2fm'%length, '%.2fm'%pos_to1, '%.2fm'%pos
2265
2266            dists_from_to = np.sqrt(np.sum((centroids_to - centroids_from)**2, 1))
2267
2268            i = 0.0
2269            n_pers = len(ids_person_act)
2270            for id_person, id_plan, time_from, id_act_from, id_act_to, name_acttype_to, duration_act_to, id_veh, id_edge_from, pos_edge_from, id_edge_to, pos_edge_to, dist_from_to, dist_walk_max\
2271                    in zip(ids_person_act, ids_plan, times_from, ids_act_from, ids_act_to, names_acttype_to, durations_act_to, ids_veh, ids_edge_from, poss_edge_from, ids_edge_to, poss_edge_to, dists_from_to, dists_walk_max):
2272                if logger:
2273                    logger.progress(i/n_pers*100)
2274                i += 1.0
2275                print 79*'*'
2276                print '  plan id_plan', id_plan, 'time_from', time_from, 'from', id_edge_from, pos_edge_from, 'to', id_edge_to, pos_edge_to
2277                print '  id_edge_from', edges.ids_sumo[id_edge_from], 'id_edge_to', edges.ids_sumo[id_edge_to]
2278
2279                time = self.plan_bikeride(id_plan, time_from, id_veh,
2280                                          id_edge_from, pos_edge_from,
2281                                          id_edge_to, pos_edge_to,
2282                                          dist_from_to, dist_walk_max,
2283                                          walkstages, ridestages)
2284
2285                ################
2286
2287                # store time estimation for this plan
2288                # note that these are the travel times, no activity time
2289                plans.times_est[id_plan] += time-time_from
2290
2291                # define current end time without last activity duration
2292                plans.times_end[id_plan] = time
2293
2294                # finally add activity and respective duration
2295
2296                id_stage_act, time = activitystages.append_stage(
2297                    id_plan, time,
2298                    ids_activity=id_act_to,
2299                    names_activitytype=name_acttype_to,
2300                    durations=duration_act_to,
2301                    ids_lane=edges.ids_lanes[id_edge_to][0],
2302                    positions=pos_edge_to,
2303                )
2304
2305                map_times[id_person] = time
2306                # return time
2307                ##
2308
2309            # select persons and activities for next setp
2310            ind_act += 1
2311            ids_person_act, ids_act_from, ids_act_to\
2312                = virtualpop.get_activities_from_pattern(ind_act, ids_person=ids_person_act)
2313            # update timing with (random) activity duration!!
2314
2315        return True
2316
2317
2318class TransitStrategy(StrategyMixin):
2319    def __init__(self, ident, parent=None,
2320                 name='Public Transport Strategy',
2321                 info='With this strategy, the person uses public transport.',
2322                 **kwargs):
2323
2324        self._init_objman(ident, parent, name=name, info=info, **kwargs)
2325        attrsman = self.set_attrsman(cm.Attrsman(self))
2326        # specific init
2327        self._init_attributes()
2328        self._init_constants()
2329
2330    def _init_attributes(self):
2331        # print 'StrategyMixin._init_attributes'
2332        pass
2333
2334    def _init_constants(self):
2335        #virtualpop = self.get_virtualpop()
2336        #stagetables = virtualpop.get_stagetables()
2337
2338        #self._walkstages = stagetables.get_stagetable('walks')
2339        #self._ridestages = stagetables.get_stagetable('rides')
2340        #self._activitystages = stagetables.get_stagetable('activities')
2341
2342        #self._plans = virtualpop.get_plans()
2343        #
2344        # print 'AutoStrategy._init_constants'
2345        # print dir(self)
2346        # self.get_attrsman().do_not_save_attrs(['_activitystages','_ridestages','_walkstages','_plans'])
2347
2348        modes = self.get_virtualpop().get_scenario().net.modes
2349        self._id_mode_bike = modes.get_id_mode('bicycle')
2350        self._id_mode_auto = modes.get_id_mode('passenger')
2351        self._id_mode_moto = modes.get_id_mode('motorcycle')
2352        self._id_mode_bus = modes.get_id_mode('bus')
2353        self.get_attrsman().do_not_save_attrs([
2354            '_id_mode_bike', '_id_mode_auto', '_id_mode_moto', '_id_mode_bus'
2355        ])
2356
2357    def preevaluate(self, ids_person):
2358        """
2359        Preevaluation strategies for person IDs in vector ids_person.
2360
2361        Returns a preevaluation vector with a preevaluation value
2362        for each person ID. The values of the preevaluation vector are as follows:
2363            -1 : Strategy cannot be applied
2364            0  : Stategy can be applied, but the preferred mode is not used
2365            1  : Stategy can be applied, and preferred mode is part of the strategy
2366            2  : Strategy uses predomunantly preferred mode
2367
2368        """
2369        n_pers = len(ids_person)
2370        persons = self.get_virtualpop()
2371        preeval = np.zeros(n_pers, dtype=np.int32)
2372
2373        # TODO: here we could exclude by age or distance facilities-stops
2374
2375        # put 0 for persons whose preference is not public transport
2376        preeval[persons.ids_mode_preferred[ids_person] != self._id_mode_bus] = 0
2377
2378        # put 2 for persons with car access and who prefer cars
2379        preeval[persons.ids_mode_preferred[ids_person] == self._id_mode_bus] = 2
2380
2381        print '  TransitStrategy.preevaluate', len(np.flatnonzero(preeval))
2382        return preeval
2383
2384    def plan_transit(self, id_plan, time_from,
2385                     id_edge_from, pos_edge_from,
2386                     id_edge_to, pos_edge_to,
2387                     id_stop_from, id_stopedge_from, pos_stop_from,
2388                     id_stop_to, id_stopedge_to, pos_stop_to,
2389                     #dist_from_to, dist_walk_max,
2390                     walkstages, transitstages,
2391                     ptlines, ptfstar, pttimes,
2392                     stops_to_enter, stops_to_exit,
2393                     ids_laneedge, ids_stoplane, ptstops):
2394
2395        ptlinks = ptlines.get_ptlinks()
2396        ptlinktypes = ptlinks.types.choices
2397        type_enter = ptlinktypes['enter']
2398        type_transit = ptlinktypes['transit']
2399        type_board = ptlinktypes['board']
2400        type_alight = ptlinktypes['alight']
2401        type_transfer = ptlinktypes['transfer']
2402        type_walk = ptlinktypes['walk']
2403        type_exit = ptlinktypes['exit']
2404
2405        if (id_edge_from == id_stopedge_from) & (abs(pos_edge_from-pos_stop_from) < 1.0):
2406            time = time_from
2407            id_stage_walk1 = None
2408        else:
2409            id_stage_walk1, time = walkstages.append_stage(id_plan, time_from,
2410                                                           id_edge_from=id_edge_from,
2411                                                           position_edge_from=pos_edge_from,
2412                                                           id_edge_to=id_stopedge_from,
2413                                                           position_edge_to=pos_stop_from,  # -7.0,
2414                                                           )
2415
2416        # print '    id_stopedge_from',id_stopedge_from
2417        # print '    pos_stop_from',pos_stop_from
2418
2419        # print
2420        # print '    id_stopedge_to',id_stopedge_to
2421        # print '    pos_stop_to',pos_stop_to
2422        # print
2423        # print '    id_stop_from',id_stop_from
2424        # print '    id_stop_to',id_stop_to
2425
2426        durations, linktypes, ids_line, ids_fromstop, ids_tostop =\
2427            ptlinks.route(id_stop_from, id_stop_to,
2428                          fstar=ptfstar, times=pttimes,
2429                          stops_to_enter=stops_to_enter,
2430                          stops_to_exit=stops_to_exit)
2431
2432        # print '  routing done. make plan..'
2433
2434        if len(linktypes) > 0:
2435            if linktypes[-1] == type_walk:  # is last stage a walk?
2436                # remove it, because will go directly to destination
2437                linktypes = linktypes[:-1]
2438                ids_line = ids_line[:-1]
2439                durations = durations[:-1]
2440                ids_fromstop = ids_fromstop[:-1]
2441                ids_tostop = ids_tostop[:-1]
2442
2443        # print '  ids_line    ',ids_line
2444        # print '  ids_fromstop',ids_fromstop
2445        # print '  ids_tostop  ',ids_tostop
2446
2447        if len(linktypes) > 0:  # is there any public transport line to take?
2448
2449            # go though PT links and generate transits and walks to trasfer
2450            ids_stopedge_from = ids_laneedge[ids_stoplane[ids_fromstop]]
2451            ids_stopedge_to = ids_laneedge[ids_stoplane[ids_tostop]]
2452            poss_stop_from = 0.5*(ptstops.positions_from[ids_fromstop]
2453                                  + ptstops.positions_to[ids_fromstop])
2454            poss_stop_to = 0.5*(ptstops.positions_from[ids_tostop]
2455                                + ptstops.positions_to[ids_tostop])
2456
2457            # this is wait time buffer to be added to the successive stage
2458            # as waiting is currently not modelled as an extra stage
2459            duration_wait = 0.0
2460
2461            # create stages for PT
2462            for linktype, id_line, duration,\
2463                id_stopedge_from, pos_fromstop,\
2464                id_stopedge_to, pos_tostop in\
2465                    zip(linktypes,
2466                        ids_line,
2467                        durations,
2468                        ids_stopedge_from, poss_stop_from,
2469                        ids_stopedge_to, poss_stop_to,
2470                        ):
2471                # print '    stage for linktype %2d fromedge %s toedge %s'%(linktype, edges.ids_sumo[id_stopedge_from],edges.ids_sumo[id_stopedge_to] )
2472
2473                print '    id_stopedge_from,id_stopedge_to', id_stopedge_from, id_stopedge_to
2474                if linktype == type_transit:  # transit!
2475                    print '    add transit'
2476                    id_stage_transit, time = transitstages.append_stage(
2477                        id_plan, time,
2478                        id_line=id_line,
2479                        duration=duration+duration_wait,
2480                        id_fromedge=id_stopedge_from,
2481                        id_toedge=id_stopedge_to,
2482                    )
2483                    duration_wait = 0.0
2484
2485                elif linktype == type_walk:  # walk to transfer
2486                    print '    add transfer'
2487                    id_stage_transfer, time = walkstages.append_stage(
2488                        id_plan, time,
2489                        id_edge_from=id_stopedge_from,
2490                        position_edge_from=pos_fromstop,
2491                        id_edge_to=id_stopedge_to,
2492                        position_edge_to=pos_tostop,
2493                        duration=duration+duration_wait,
2494                    )
2495                    duration_wait = 0.0
2496
2497                else:  # all other link time are no modelld
2498                    # do not do anything , just add wait time to next stage
2499                    print '    add duration', duration
2500                    duration_wait += duration
2501
2502            # walk from final stop to activity
2503            # print '    Stage for linktype %2d fromedge %s toedge %s'%(linktype, edges.ids_sumo[id_stopedge_to],edges.ids_sumo[id_edge_to] )
2504            # if (id_edge_to == id_stopedge_to)&(abs(pos_edge_to-pos_tostop)<1.0):
2505            #    print '  already at right edge and position'
2506            #    pass
2507            # else:
2508            id_stage_walk2, time = walkstages.append_stage(id_plan, time,
2509                                                           id_edge_from=id_stopedge_to,
2510                                                           position_edge_from=pos_tostop,
2511                                                           id_edge_to=id_edge_to,
2512                                                           position_edge_to=pos_edge_to,
2513                                                           )
2514
2515        else:
2516            # there is no public transport line linking these nodes.
2517
2518            if id_stage_walk1 is None:
2519                # Create first walk directly from home to activity
2520                id_stage_walk1, time = walkstages.append_stage(id_plan,
2521                                                               time_from,
2522                                                               id_edge_from=id_edge_from,
2523                                                               position_edge_from=pos_edge_from,
2524                                                               id_edge_to=id_edge_to,
2525                                                               position_edge_to=pos_edge_to,
2526                                                               )
2527            else:
2528                # Modify first walk directly from home to activity
2529                time = walkstages.modify_stage(id_stage_walk1, time_from,
2530                                               id_edge_from=id_edge_from,
2531                                               position_edge_from=pos_edge_from,
2532                                               id_edge_to=id_edge_to,
2533                                               position_edge_to=pos_edge_to,
2534                                               )
2535
2536        return time
2537
2538    def plan(self, ids_person, logger=None):
2539        """
2540        Generates a plan for these person according to this strategie.
2541        Overriden by specific strategy.
2542        """
2543        print 'TransitStrategy.plan', len(ids_person)
2544        #make_plans_private(self, ids_person = None, mode = 'passenger')
2545        # routing necessary?
2546        virtualpop = self.get_virtualpop()
2547        plans = virtualpop.get_plans()  # self._plans
2548        demand = virtualpop.get_demand()
2549        ptlines = demand.ptlines
2550
2551        walkstages = plans.get_stagetable('walks')
2552        transitstages = plans.get_stagetable('transits')
2553        activitystages = plans.get_stagetable('activities')
2554
2555        activities = virtualpop.get_activities()
2556        activitytypes = demand.activitytypes
2557        landuse = virtualpop.get_landuse()
2558        facilities = landuse.facilities
2559        parking = landuse.parking
2560
2561        scenario = virtualpop.get_scenario()
2562        net = scenario.net
2563        edges = net.edges
2564        lanes = net.lanes
2565        modes = net.modes
2566
2567        ptstops = net.ptstops
2568
2569        # print '   demand',demand
2570        # print '   demand.ptlines',demand.ptlines,dir(demand.ptlines)
2571        # print '   demand.ptlines.get_ptlinks()',demand.ptlines.get_ptlinks()
2572        # print '   demand.virtualpop',demand.virtualpop,dir(demand.virtualpop)
2573        # print '   demand.trips',demand.trips,dir(demand.trips)
2574        if len(ptlines) == 0:
2575            print 'WARNING in TrasitStrategy.plan: no transit services available. Create public trasit services by connecting stops.'
2576            return False
2577
2578        ptlinks = ptlines.get_ptlinks()
2579        if len(ptlinks) == 0:
2580            print 'WARNING in TrasitStrategy.plan: no public transport links. Run methods: "create routes" and "build links" from public trasport services.'
2581            return False
2582
2583        ptlinktypes = ptlinks.types.choices
2584
2585        ptfstar = ptlinks.get_fstar()
2586        pttimes = ptlinks.get_times()
2587        stops_to_enter, stops_to_exit = ptlinks.get_stops_to_enter_exit()
2588
2589        ids_stoplane = ptstops.ids_lane
2590        ids_laneedge = net.lanes.ids_edge
2591
2592        times_est_plan = plans.times_est
2593        # here we can determine edge weights for different modes
2594
2595        # this could be centralized to avoid redundance
2596        plans.prepare_stagetables(['walks', 'transits', 'activities'])
2597
2598        ids_person_act, ids_act_from, ids_act_to\
2599            = virtualpop.get_activities_from_pattern(0, ids_person=ids_person)
2600
2601        if len(ids_person_act) == 0:
2602            print 'WARNING in TrasitStrategy.plan: no eligible persons found.'
2603            return False
2604
2605        # temporary maps from ids_person to other parameters
2606        nm = np.max(ids_person_act)+1
2607        map_ids_plan = np.zeros(nm, dtype=np.int32)
2608        #ids_plan_act = virtualpop.add_plans(ids_person_act, id_strategy = self.get_id_strategy())
2609        map_ids_plan[ids_person_act] = virtualpop.add_plans(ids_person_act, id_strategy=self.get_id_strategy())
2610
2611        map_times = np.zeros(nm, dtype=np.int32)
2612        map_times[ids_person_act] = activities.get_times_end(ids_act_from, pdf='unit')
2613
2614        # set start time to plans (important!)
2615        plans.times_begin[map_ids_plan[ids_person_act]] = map_times[ids_person_act]
2616
2617        map_ids_fac_from = np.zeros(nm, dtype=np.int32)
2618        map_ids_fac_from[ids_person_act] = activities.ids_facility[ids_act_from]
2619
2620        n_plans = len(ids_person_act)
2621        print 'TrasitStrategy.plan n_plans=', n_plans
2622
2623        # make initial activity stage
2624        ids_edge_from = facilities.ids_roadedge_closest[map_ids_fac_from[ids_person_act]]
2625        poss_edge_from = facilities.positions_roadedge_closest[map_ids_fac_from[ids_person_act]]
2626        # this is the time when first activity starts
2627        # first activity is normally not simulated
2628
2629        names_acttype_from = activitytypes.names[activities.ids_activitytype[ids_act_from]]
2630        durations_act_from = activities.get_durations(ids_act_from)
2631        times_from = map_times[ids_person_act]-durations_act_from
2632        #times_from = activities.get_times_end(ids_act_from, pdf = 'unit')
2633
2634        for id_plan,\
2635            time,\
2636            id_act_from,\
2637            name_acttype_from,\
2638            duration_act_from,\
2639            id_edge_from,\
2640            pos_edge_from  \
2641            in zip(map_ids_plan[ids_person_act],
2642                   times_from,
2643                   ids_act_from,
2644                   names_acttype_from,
2645                   durations_act_from,
2646                   ids_edge_from,
2647                   poss_edge_from):
2648
2649            id_stage_act, time = activitystages.append_stage(
2650                id_plan, time,
2651                ids_activity=id_act_from,
2652                names_activitytype=name_acttype_from,
2653                durations=duration_act_from,
2654                ids_lane=edges.ids_lanes[id_edge_from][0],
2655                positions=pos_edge_from,
2656            )
2657
2658        ##
2659
2660        ind_act = 0
2661
2662        # main loop while there are persons performing
2663        # an activity at index ind_act
2664        while len(ids_person_act) > 0:
2665            ids_plan = map_ids_plan[ids_person_act]
2666
2667            times_from = map_times[ids_person_act]
2668
2669            names_acttype_to = activitytypes.names[activities.ids_activitytype[ids_act_to]]
2670            durations_act_to = activities.get_durations(ids_act_to)
2671
2672            ids_fac_from = map_ids_fac_from[ids_person_act]
2673            ids_fac_to = activities.ids_facility[ids_act_to]
2674
2675            centroids_from = facilities.centroids[ids_fac_from]
2676            centroids_to = facilities.centroids[ids_fac_to]
2677
2678            # origin edge and position
2679            ids_edge_from = facilities.ids_roadedge_closest[ids_fac_from]
2680            poss_edge_from = facilities.positions_roadedge_closest[ids_fac_from]
2681
2682            # destination edge and position
2683            ids_edge_to = facilities.ids_roadedge_closest[ids_fac_to]
2684            poss_edge_to = facilities.positions_roadedge_closest[ids_fac_to]
2685
2686            ids_stop_from = ptstops.get_closest(centroids_from)
2687            ids_stop_to = ptstops.get_closest(centroids_to)
2688
2689            ids_stopedge_from = ids_laneedge[ids_stoplane[ids_stop_from]]
2690            ids_stopedge_to = ids_laneedge[ids_stoplane[ids_stop_to]]
2691
2692            # do random pos here
2693            poss_stop_from = 0.5*(ptstops.positions_from[ids_stop_from]
2694                                  + ptstops.positions_to[ids_stop_from])
2695
2696            poss_stop_to = 0.5*(ptstops.positions_from[ids_stop_to]
2697                                + ptstops.positions_to[ids_stop_to])
2698
2699            i = 0.0
2700            for id_person, id_plan, time_from, id_act_from, id_act_to, name_acttype_to, duration_act_to, id_edge_from, pos_edge_from, id_edge_to, pos_edge_to, id_stop_from, id_stopedge_from, pos_stop_from, id_stop_to, id_stopedge_to, pos_stop_to\
2701                    in zip(ids_person_act, ids_plan, times_from, ids_act_from, ids_act_to, names_acttype_to, durations_act_to,  ids_edge_from, poss_edge_from, ids_edge_to, poss_edge_to, ids_stop_from, ids_stopedge_from, poss_stop_from, ids_stop_to, ids_stopedge_to, poss_stop_to):
2702                n_pers = len(ids_person_act)
2703                if logger:
2704                    logger.progress(i/n_pers*100)
2705                i += 1.0
2706                print 79*'_'
2707                print '  id_plan=%d, id_person=%d, ' % (id_plan, id_person)
2708
2709                time = self.plan_transit(id_plan, time_from,
2710                                         id_edge_from, pos_edge_from,
2711                                         id_edge_to, pos_edge_to,
2712                                         id_stop_from, id_stopedge_from, pos_stop_from,
2713                                         id_stop_to, id_stopedge_to, pos_stop_to,
2714                                         #dist_from_to, dist_walk_max,
2715                                         walkstages, transitstages,
2716                                         ptlines, ptfstar, pttimes,
2717                                         stops_to_enter, stops_to_exit,
2718                                         ids_laneedge, ids_stoplane, ptstops)
2719
2720                # update time for trips estimation for this plan
2721                plans.times_est[id_plan] += time-time_from
2722
2723                # define current end time without last activity duration
2724                plans.times_end[id_plan] = time
2725
2726                id_stage_act, time = activitystages.append_stage(
2727                    id_plan, time,
2728                    ids_activity=id_act_to,
2729                    names_activitytype=name_acttype_to,
2730                    durations=duration_act_to,
2731                    ids_lane=edges.ids_lanes[id_edge_to][0],
2732                    positions=pos_edge_to,
2733                )
2734
2735                # store time for next iteration in case other activities are
2736                # following
2737                map_times[id_person] = time
2738
2739            # select persons and activities for next setp
2740            ind_act += 1
2741            ids_person_act, ids_act_from, ids_act_to\
2742                = virtualpop.get_activities_from_pattern(ind_act, ids_person=ids_person_act)
2743
2744
2745class BikeTransitStrategy(BikeStrategy, TransitStrategy):
2746    def __init__(self, ident, parent=None,
2747                 name='Bike+Public Transport Strategy',
2748                 info='With this strategy, the person combines bike and public transport.',
2749                 **kwargs):
2750
2751        self._init_objman(ident, parent, name=name, info=info, **kwargs)
2752        attrsman = self.set_attrsman(cm.Attrsman(self))
2753        # specific init
2754        self._init_attributes()
2755        self._init_constants()
2756
2757    def _init_attributes(self):
2758        # print 'StrategyMixin._init_attributes'
2759        BikeStrategy._init_attributes(self)
2760        TransitStrategy._init_attributes(self)
2761
2762    def _init_constants(self):
2763
2764        BikeStrategy._init_constants(self)
2765        TransitStrategy._init_constants(self)
2766
2767    def preevaluate(self, ids_person):
2768        """
2769        Preevaluation strategies for person IDs in vector ids_person.
2770
2771        Returns a preevaluation vector with a preevaluation value
2772        for each person ID. The values of the preevaluation vector are as follows:
2773            -1 : Strategy cannot be applied
2774            0  : Stategy can be applied, but the preferred mode is not used
2775            1  : Stategy can be applied, and preferred mode is part of the strategy
2776            2  : Strategy uses predomunantly preferred mode
2777
2778        """
2779        n_pers = len(ids_person)
2780        persons = self.get_virtualpop()
2781        preeval = np.zeros(n_pers, dtype=np.int32)
2782
2783        inds_prefer = (persons.ids_mode_preferred[ids_person] == self._id_mode_bus)\
2784            | (persons.ids_mode_preferred[ids_person] == self._id_mode_bike)\
2785
2786        inds_avail = persons.ids_ibike[ids_person] > -1
2787        preeval[np.logical_not(inds_avail)] = -1
2788        # TODO: here we could exclude by age or distance facilities-stops
2789
2790        # put 0 for persons whose preference is not public transport
2791        preeval[inds_avail & np.logical_not(inds_prefer)] = 0
2792
2793        # put 2 for persons with bike access and who prefer bike or bus
2794        preeval[inds_avail & inds_prefer] = 1
2795
2796        print '  BikeTransitStrategy.preevaluate', len(np.flatnonzero(preeval))
2797        return preeval
2798
2799    def plan(self, ids_person, logger=None):
2800        """
2801        Generates a plan for these person according to this strategie.
2802        Overriden by specific strategy.
2803        """
2804        print 'TransitStrategy.plan', len(ids_person)
2805        #make_plans_private(self, ids_person = None, mode = 'passenger')
2806        # routing necessary?
2807        virtualpop = self.get_virtualpop()
2808        plans = virtualpop.get_plans()  # self._plans
2809        demand = virtualpop.get_demand()
2810        ptlines = demand.ptlines
2811
2812        walkstages = plans.get_stagetable('walks')
2813        transitstages = plans.get_stagetable('transits')
2814        ridestages = plans.get_stagetable('bikerides')
2815        activitystages = plans.get_stagetable('activities')
2816
2817        activities = virtualpop.get_activities()
2818        activitytypes = demand.activitytypes
2819        landuse = virtualpop.get_landuse()
2820        facilities = landuse.facilities
2821        #parking = landuse.parking
2822
2823        scenario = virtualpop.get_scenario()
2824        net = scenario.net
2825        edges = net.edges
2826        lanes = net.lanes
2827        modes = net.modes
2828
2829        ptstops = net.ptstops
2830
2831        # print '   demand',demand
2832        # print '   demand.ptlines',demand.ptlines,dir(demand.ptlines)
2833        # print '   demand.ptlines.get_ptlinks()',demand.ptlines.get_ptlinks()
2834        # print '   demand.virtualpop',demand.virtualpop,dir(demand.virtualpop)
2835        # print '   demand.trips',demand.trips,dir(demand.trips)
2836        if len(ptlines) == 0:
2837            print 'WARNING in TrasitStrategy.plan: no transit services available.'
2838            return False
2839
2840        ptlinks = ptlines.get_ptlinks()
2841        ptlinktypes = ptlinks.types.choices
2842
2843        ptfstar = ptlinks.get_fstar()
2844        pttimes = ptlinks.get_times()
2845        stops_to_enter, stops_to_exit = ptlinks.get_stops_to_enter_exit()
2846
2847        ids_stoplane = ptstops.ids_lane
2848        ids_laneedge = net.lanes.ids_edge
2849
2850        times_est_plan = plans.times_est
2851        # here we can determine edge weights for different modes
2852
2853        # this could be centralized to avoid redundance
2854        plans.prepare_stagetables(['walks', 'bikerides', 'transits', 'activities'])
2855
2856        ids_person_act, ids_act_from, ids_act_to\
2857            = virtualpop.get_activities_from_pattern(0, ids_person=ids_person)
2858
2859        if len(ids_person_act) == 0:
2860            print 'WARNING in TrasitStrategy.plan: no eligible persons found.'
2861            return False
2862
2863        # temporary maps from ids_person to other parameters
2864        nm = np.max(ids_person_act)+1
2865        map_ids_plan = np.zeros(nm, dtype=np.int32)
2866        #ids_plan_act = virtualpop.add_plans(ids_person_act, id_strategy = self.get_id_strategy())
2867        map_ids_plan[ids_person_act] = virtualpop.add_plans(ids_person_act, id_strategy=self.get_id_strategy())
2868
2869        map_times = np.zeros(nm, dtype=np.int32)
2870        map_times[ids_person_act] = activities.get_times_end(ids_act_from, pdf='unit')
2871
2872        # set start time to plans (important!)
2873        plans.times_begin[map_ids_plan[ids_person_act]] = map_times[ids_person_act]
2874
2875        map_ids_fac_from = np.zeros(nm, dtype=np.int32)
2876        map_ids_fac_from[ids_person_act] = activities.ids_facility[ids_act_from]
2877
2878        n_plans = len(ids_person_act)
2879        print 'TrasitStrategy.plan n_plans=', n_plans
2880
2881        # make initial activity stage
2882        ids_edge_from = facilities.ids_roadedge_closest[map_ids_fac_from[ids_person_act]]
2883        poss_edge_from = facilities.positions_roadedge_closest[map_ids_fac_from[ids_person_act]]
2884        # this is the time when first activity starts
2885        # first activity is normally not simulated
2886
2887        names_acttype_from = activitytypes.names[activities.ids_activitytype[ids_act_from]]
2888        durations_act_from = activities.get_durations(ids_act_from)
2889        times_from = map_times[ids_person_act]-durations_act_from
2890        #times_from = activities.get_times_end(ids_act_from, pdf = 'unit')
2891
2892        for id_plan,\
2893            time,\
2894            id_act_from,\
2895            name_acttype_from,\
2896            duration_act_from,\
2897            id_edge_from,\
2898            pos_edge_from  \
2899            in zip(map_ids_plan[ids_person_act],
2900                   times_from,
2901                   ids_act_from,
2902                   names_acttype_from,
2903                   durations_act_from,
2904                   ids_edge_from,
2905                   poss_edge_from):
2906
2907            id_stage_act, time = activitystages.append_stage(
2908                id_plan, time,
2909                ids_activity=id_act_from,
2910                names_activitytype=name_acttype_from,
2911                durations=duration_act_from,
2912                ids_lane=edges.ids_lanes[id_edge_from][0],
2913                positions=pos_edge_from,
2914            )
2915
2916        ##
2917
2918        ind_act = 0
2919
2920        # main loop while there are persons performing
2921        # an activity at index ind_act
2922        while len(ids_person_act) > 0:
2923            ids_plan = map_ids_plan[ids_person_act]
2924
2925            times_from = map_times[ids_person_act]
2926
2927            ids_veh = virtualpop.ids_ibike[ids_person_act]
2928            dists_walk_max = virtualpop.dists_walk_max[ids_person_act]
2929            names_acttype_to = activitytypes.names[activities.ids_activitytype[ids_act_to]]
2930            durations_act_to = activities.get_durations(ids_act_to)
2931
2932            ids_fac_from = map_ids_fac_from[ids_person_act]
2933            ids_fac_to = activities.ids_facility[ids_act_to]
2934
2935            centroids_from = facilities.centroids[ids_fac_from]
2936            centroids_to = facilities.centroids[ids_fac_to]
2937
2938            # origin edge and position
2939            ids_edge_from = facilities.ids_roadedge_closest[ids_fac_from]
2940            poss_edge_from = facilities.positions_roadedge_closest[ids_fac_from]
2941
2942            # destination edge and position
2943            ids_edge_to = facilities.ids_roadedge_closest[ids_fac_to]
2944            poss_edge_to = facilities.positions_roadedge_closest[ids_fac_to]
2945
2946            ids_stop_from = ptstops.get_closest(centroids_from)
2947            ids_stop_to = ptstops.get_closest(centroids_to)
2948
2949            ids_stopedge_from = ids_laneedge[ids_stoplane[ids_stop_from]]
2950            ids_stopedge_to = ids_laneedge[ids_stoplane[ids_stop_to]]
2951
2952            centroids_stop_from = ptstops.centroids[ids_stop_from]
2953            centroids_stop_to = ptstops.centroids[ids_stop_to]
2954            # do random pos here
2955            poss_stop_from = 0.5*(ptstops.positions_from[ids_stop_from]
2956                                  + ptstops.positions_to[ids_stop_from])
2957
2958            poss_stop_to = 0.5*(ptstops.positions_from[ids_stop_to]
2959                                + ptstops.positions_to[ids_stop_to])
2960
2961            dists_from_to = np.sqrt(np.sum((centroids_to - centroids_from)**2, 1))
2962            dists_from_stop_from = np.sqrt(np.sum((centroids_stop_from - centroids_from)**2, 1))
2963            dists_stop_to_to = np.sqrt(np.sum((centroids_to - centroids_stop_to)**2, 1))
2964
2965            i = 0.0
2966            for id_person, id_plan, time_from, id_act_from, id_act_to, name_acttype_to, duration_act_to, id_veh, id_edge_from, pos_edge_from, id_edge_to, pos_edge_to, id_stop_from, id_stopedge_from, pos_stop_from, id_stop_to, id_stopedge_to, pos_stop_to, dists_from_to, dist_from_stop_from, dist_stop_to_to, dist_walk_max\
2967                    in zip(ids_person_act, ids_plan, times_from, ids_act_from, ids_act_to, names_acttype_to, durations_act_to, ids_veh, ids_edge_from, poss_edge_from, ids_edge_to, poss_edge_to, ids_stop_from, ids_stopedge_from, poss_stop_from, ids_stop_to, ids_stopedge_to, poss_stop_to, dists_from_to, dists_from_stop_from, dists_stop_to_to, dists_walk_max):
2968                n_pers = len(ids_person_act)
2969                if logger:
2970                    logger.progress(i/n_pers*100)
2971                i += 1.0
2972                print 79*'_'
2973                print '  id_plan=%d, id_person=%d, ' % (id_plan, id_person)
2974                #dist_from_stop_from, dist_stop_to_to
2975
2976                time = self.plan_bikeride(id_plan, time_from, id_veh,
2977                                          id_edge_from, pos_edge_from,
2978                                          id_stopedge_from, pos_stop_from,
2979                                          dist_from_stop_from, dist_walk_max,
2980                                          walkstages, ridestages)
2981
2982                time = self.plan_transit(id_plan, time,
2983                                         id_stopedge_from, pos_stop_from,
2984                                         id_stopedge_to, pos_stop_to,
2985                                         id_stop_from, id_stopedge_from, pos_stop_from,
2986                                         id_stop_to, id_stopedge_to, pos_stop_to,
2987                                         #dist_from_to, dist_walk_max,
2988                                         walkstages, transitstages,
2989                                         ptlines, ptfstar, pttimes,
2990                                         stops_to_enter, stops_to_exit,
2991                                         ids_laneedge, ids_stoplane, ptstops)
2992
2993                time = self.plan_bikeride(id_plan, time, id_veh,
2994                                          id_stopedge_to, pos_stop_to,
2995                                          id_edge_to, pos_edge_to,
2996                                          dist_stop_to_to, dist_walk_max,
2997                                          walkstages, ridestages)
2998
2999                # update time for trips estimation for this plan
3000                plans.times_est[id_plan] += time-time_from
3001
3002                # define current end time without last activity duration
3003                plans.times_end[id_plan] = time
3004
3005                id_stage_act, time = activitystages.append_stage(
3006                    id_plan, time,
3007                    ids_activity=id_act_to,
3008                    names_activitytype=name_acttype_to,
3009                    durations=duration_act_to,
3010                    ids_lane=edges.ids_lanes[id_edge_to][0],
3011                    positions=pos_edge_to,
3012                )
3013
3014                # store time for next iteration in case other activities are
3015                # following
3016                map_times[id_person] = time
3017
3018            # select persons and activities for next setp
3019            ind_act += 1
3020            ids_person_act, ids_act_from, ids_act_to\
3021                = virtualpop.get_activities_from_pattern(ind_act, ids_person=ids_person_act)
3022
3023
3024class Strategies(am.ArrayObjman):
3025    def __init__(self, ident, virtualpop, **kwargs):
3026        self._init_objman(ident,
3027                          parent=virtualpop,
3028                          name='Mobility Strategies',
3029                          info="""Contains different mobility strategies.
3030                            A strategy has methods to identify whether a strategy is applicaple to a person
3031                            and to make a plan fo a person.
3032                            """,
3033                          version=0.2,
3034                          **kwargs)
3035
3036        self.add_col(am.ArrayConf('names',
3037                                  default='',
3038                                  dtype='object',
3039                                  perm='r',
3040                                  is_index=True,
3041                                  name='Short name',
3042                                  info='Strategy name. Must be unique, used as index.',
3043                                  ))
3044        self._init_attributes()
3045        self._init_constants()
3046
3047    def _init_attributes(self):
3048
3049        self.add_col(cm.ObjsConf('strategies',
3050                                 #groupnames = ['state'],
3051                                 name='Strategy',
3052                                 info='Strategy object.',
3053                                 ))
3054
3055        self.add_col(am.ArrayConf('colors', np.ones(4, np.float32),
3056                                  dtype=np.float32,
3057                                  metatype='color',
3058                                  perm='rw',
3059                                  name='Color',
3060                                  info="Route color. Color as RGBA tuple with values from 0.0 to 1.0",
3061                                  xmltag='color',
3062                                  ))
3063        if self.get_version() < 0.2:
3064            self._set_colors_default()
3065            self.set_version(0.2)
3066
3067    def format_ids(self, ids):
3068        return ', '.join(self.names[ids])
3069
3070    def get_id_from_formatted(self, idstr):
3071        return self.names.get_id_from_index(idstr)
3072
3073    def get_ids_from_formatted(self, idstrs):
3074        return self.names.get_ids_from_indices_save(idstrs.split(','))
3075
3076    def add_default(self):
3077
3078        self.add_strategy('walk', WalkStrategy)
3079        self.add_strategy('auto', AutoStrategy)
3080        self.add_strategy('bike', BikeStrategy)
3081        self.add_strategy('transit', TransitStrategy)
3082        self.add_strategy('biketransit', BikeTransitStrategy)
3083        self._set_colors_default()
3084
3085    def _set_colors_default(self):
3086        colors_default = {'walk': np.array([160, 72, 0, 220], np.float32)/255,
3087                          'auto': np.array([250, 213, 0, 220], np.float32)/255,
3088                          'bike': np.array([8, 191, 73, 210], np.float32)/255,
3089                          'transit': np.array([8, 77, 191, 220], np.float32)/255,
3090                          'biketransit': np.array([8, 201, 223, 220], np.float32)/255,
3091                          }
3092        ids = self.names.get_ids_from_indices_save(colors_default.keys())
3093        self.colors[ids] = colors_default.values()  # np.array(colors_default.values(), np.float32).reshape(-1,4)
3094
3095        #self.colors.indexset(colors_default.keys(), colors_default.values())
3096
3097    def add_strategy(self, ident, Strategyclass, color=(0.0, 0.0, 0.0, 1.0)):
3098        # print 'add_strategy', ident
3099        if not self.names.has_index(ident):
3100            strategy = Strategyclass(ident, self)
3101            self.add_row(names=ident,
3102                         strategies=strategy,
3103                         colours=color,
3104                         )
3105            return strategy
3106        else:
3107            # print 'WARNING in add_strategy: strategy %s already initialized'%ident
3108            return self.strategies[self.names.get_id_from_index(ident)]
3109
3110    def preevaluate(self, ids_person):
3111        """
3112        Preevaluation of strategies for person IDs in vector ids_person.
3113
3114        Returns a vector with strategy IDs and a preevaluation matrix.
3115        The rows of the matrix corrispond to each person ID.
3116        The columns corrsopond to reck strategy ID.
3117        The values of the preevaluation matrix are as follows:
3118            -1 : Strategy cannot be applied
3119            0  : Stategy can be applied, but the preferred mode is not used
3120            1  : Stategy can be applied, and preferred mode is part of the strategy
3121            2  : Strategy uses predomunantly preferred mode
3122
3123        """
3124        print 'preevaluate strategies'
3125        ids_strat = self.get_ids()
3126        n_pers = len(ids_person)
3127        n_strat = len(ids_strat)
3128
3129        preeval = np.zeros((n_pers, n_strat), dtype=np.int32)
3130        for i, strategy in zip(range(n_strat), self.strategies[ids_strat]):
3131            print '  preevaluate strategiy', strategy.ident
3132            preeval[i, :] = strategy.preevaluate(ids_person)
3133
3134        return ids_strat, preeval
3135
3136
3137class StageTypeMixin(am.ArrayObjman):
3138    def init_stagetable(self, ident, stages,  name='', info="Stage of Plan"):
3139
3140        self._init_objman(ident=ident, parent=stages, name=name,
3141                          info=info,
3142                          version=0.2,
3143                          )
3144
3145        self.add_col(am.IdsArrayConf('ids_plan', self.get_plans(),
3146                                     #groupnames = ['state'],
3147                                     name='ID plan',
3148                                     info='ID of plan.',
3149                                     xmltag='type',
3150                                     ))
3151
3152        self.add_col(am.ArrayConf('times_start', -1.0,
3153                                  groupnames=['parameters'],    # new
3154                                  name='Start time',
3155                                  unit='s',
3156                                  info='Planned or estimated time when this stage starts. Value -1 means unknown.',
3157                                  ))
3158
3159        self.add_col(am.ArrayConf('durations', -1.0,
3160                                  name='Duration',
3161                                  groupnames=['parameters'],  # new
3162                                  unit='s',
3163                                  info='Planned or estimated duration for this stage starts. Value -1 means unknown.',
3164                                  xmltag='type',
3165                                  ))
3166
3167    def get_plans(self):
3168        return self.parent
3169
3170    def get_ids_from_ids_plan(self, ids_plan):
3171        """
3172        Returns only stage IDs which are part of the given plans IDs.
3173        """
3174        # print 'get_ids_from_ids_plan for',type(ids_plan),ids_plan
3175
3176        ids = self.get_ids()
3177        #ids_plan_part = self.ids_plan[ids]
3178        are_selected = np.zeros(len(ids), dtype=np.bool)
3179        for ind, id_plan_part in zip(xrange(len(ids)), self.ids_plan[ids]):
3180            are_selected[ind] = id_plan_part in ids_plan
3181        return ids[are_selected]
3182        # print '  ids_plan_part',type(ids_plan_part),ids_plan_part
3183        # print '  ids_selected',type(ids_plan_part.intersection(ids_plan)),ids_plan_part.intersection(ids_plan)
3184        # return np.array(list(ids_plan_part.intersection(ids_plan)), dtype = np.int32)
3185
3186    def get_virtualpop(self):
3187        # print 'get_virtualpop  '
3188        return self.parent.parent
3189
3190    def prepare_planning(self):
3191        pass
3192
3193    def append_stage(self, id_plan, time_start,  **kwargs):
3194
3195        # try to fix timing
3196        # if time_start<0:
3197        #    time_start_prev, duration_prev = self.parent.plans.get_timing_laststage(id_plan)
3198        #    if (duration_prev>=0)&(time_start_prev>=0):
3199        #        time_start = time_start_prev+duration_prev
3200
3201        id_stage = self.add_row(ids_plan=id_plan,  times_start=time_start, **kwargs)
3202        # print 'STAGE.appended stage %s id_plan=%d, id_stage=%d, t=%d'%(self.get_name(),id_plan,id_stage,time_start)
3203        # for key in kwargs.keys():
3204        #    print '    %s=%s'%(key,kwargs[key])
3205        # print '    --id_plan, self, id_stage',id_plan, self, id_stage#,self.ids_plan.get_linktab()
3206
3207        self.parent.append_stage(id_plan, self, id_stage)
3208        # print '  plan appended',id_plan, self, id_stage
3209
3210        return id_stage, time_start+self.durations[id_stage]
3211
3212    def modify_stage(self, id_stage, time_start,  **kwargs):
3213        self.set_row(id_stage, **kwargs)
3214        return time_start+self.durations[id_stage]
3215
3216    def get_timing(self, id_stage):
3217        #ind = self.get_ind(id_stage)
3218        return self.times_start[id_stage], self.durations[id_stage]
3219
3220    def to_xml(self, id_stage, fd, indent=0):
3221        """
3222        To be overridden by specific stage class.
3223        """
3224        pass
3225
3226
3227class TransitStages(StageTypeMixin):
3228    def __init__(self, ident, stages, name='Transit rides', info='Ride on a single public transport line (no transfers).'):
3229        self.init_stagetable(ident,
3230                             stages, name=name,
3231                             info=info,
3232                             )
3233        self._init_attributes()
3234
3235    def _init_attributes(self):
3236        #ptstops =  self.parent.get_ptstops()
3237        edges = self.get_virtualpop().get_net().edges
3238        if hasattr(self, 'ids_fromstop'):
3239            self.delete('ids_fromstop')
3240            self.delete('ids_tostop')
3241
3242        self.add_col(am.IdsArrayConf('ids_line', self.get_virtualpop().get_ptlines(),
3243                                     groupnames=['parameters'],
3244                                     name='ID line',
3245                                     info='ID of public transport line.',
3246                                     ))
3247
3248        self.add_col(am.IdsArrayConf('ids_fromedge', edges,
3249                                     groupnames=['parameters'],
3250                                     name='Edge ID from',
3251                                     info='Edge ID of departure bus stop or station.',
3252                                     ))
3253
3254        self.add_col(am.IdsArrayConf('ids_toedge', edges,
3255                                     groupnames=['parameters'],
3256                                     name='Edge ID to',
3257                                     info='Edge ID of destination bus stop or station.',
3258                                     ))
3259
3260    def _init_constants(self):
3261        self.get_attrsman().do_not_save_attrs(['_costs', '_fstar', ])
3262
3263    def prepare_planning(self):
3264        ptlinks = self.ids_line.get_linktab().ptlinks.get_value()
3265        if len(ptlinks) == 0:
3266            # no links built...built them
3267            ptlinks.build()
3268
3269        self._costs = ptlinks.get_times()
3270        self._fstar = ptlinks.get_fstar()
3271
3272    def append_stage(self, id_plan, time_start=-1.0,
3273                     id_line=-1, duration=0.0,
3274                     id_fromedge=-1, id_toedge=-1, **kwargs):
3275        """
3276        Appends a transit stage to plan id_plan.
3277
3278        """
3279        # print 'TransitStages.append_stage',id_stage
3280
3281        id_stage, time_end = StageTypeMixin.append_stage(self,
3282                                                         id_plan,
3283                                                         time_start,
3284                                                         durations=duration,
3285                                                         ids_line=id_line,
3286                                                         ids_fromedge=id_fromedge,
3287                                                         ids_toedge=id_toedge,
3288                                                         )
3289
3290        # add this stage to the vehicle database
3291        # ind_ride gives the index of this ride (within the same plan??)
3292        #ind_ride = self.parent.get_iautos().append_ride(id_veh, id_stage)
3293        return id_stage, time_end
3294
3295    def to_xml(self, id_stage, fd, indent=0):
3296        # <ride from="1/3to0/3" to="0/4to1/4" lines="train0"/>
3297        net = self.get_virtualpop().get_net()
3298        #ids_stoplane = net.ptstops.ids_lane
3299        #ids_laneedge = net.lanes.ids_edge
3300        ids_sumoedge = net.edges.ids_sumo
3301
3302        #ind = self.get_ind(id_stage)
3303        fd.write(xm.start('ride', indent=indent))
3304        fd.write(xm.num('from', ids_sumoedge[self.ids_fromedge[id_stage]]))
3305        fd.write(xm.num('to', ids_sumoedge[self.ids_toedge[id_stage]]))
3306        fd.write(xm.num('lines', self.ids_line.get_linktab().linenames[self.ids_line[id_stage]]))
3307        # if self.cols.pos_edge_from[ind]>0:
3308        #    fd.write(xm.num('departPos', self.cols.pos_edge_from[ind]))
3309        # if self.cols.pos_edge_to[ind]>0:
3310        #    fd.write(xm.num('arrivalPos', self.cols.pos_edge_to[ind]))
3311
3312        fd.write(xm.stopit())  # ends stage
3313
3314
3315class AutorideStages(StageTypeMixin):
3316
3317    def __init__(self, ident, population,
3318                 name='Auto rides',
3319                 info='Rides with privately owned auto.',
3320                 version=1.0,
3321                 ):
3322
3323        self.init_stagetable(ident, population, name=name, info=info)
3324        # print 'Rides.__init__',self.get_name()
3325        self._init_attributes()
3326
3327    def _init_attributes(self):
3328        # TODO: this structure needs review: the private vehicle is part of a person, not a stage
3329        # street parking at home and work could be in stage. Private garage is part of person...
3330        # print '_init_attributes',self.parent.get_iautos(), self.ident,self.parent.get_landuse().parking
3331
3332        self.add_col(am.IdsArrayConf('ids_iauto', self.get_virtualpop().get_iautos(),
3333                                     groupnames=['state'],
3334                                     name='ID vehicle',
3335                                     info='ID of private vehicle.',
3336                                     ))
3337
3338        self.add_col(am.ArrayConf('times_init', -1.0,
3339                                  name='Init. time',
3340                                  unit='s',
3341                                  info='Initialization time, which is the time when the vehicle appears in the scenario. Value -1 means unknown.',
3342                                  ))
3343
3344        self.add_col(am.IdsArrayConf('ids_parking_from', self.get_virtualpop().get_landuse().parking,
3345                                     groupnames=['state'],
3346                                     name='ID dep. parking',
3347                                     info='Parking ID at the departure of the ride starts.',
3348                                     ))
3349
3350        self.add_col(am.IdsArrayConf('ids_parking_to', self.get_virtualpop().get_landuse().parking,
3351                                     groupnames=['state'],
3352                                     name='ID arr. parking',
3353                                     info='Parking ID  at the arrival of the ride.',
3354                                     ))
3355
3356        self.add_col(am.IdlistsArrayConf('ids_edges', self.get_virtualpop().get_net().edges,
3357                                         groupnames=['_private'],
3358                                         name='Route',
3359                                         info="The vehicle's route as a sequence of edge IDs.",
3360                                         ))
3361
3362        self.add(cm.AttrConf('dist_ride_min', 400.0,
3363                             dtype='object',
3364                             groupnames=['options'],
3365                             perm='rw',
3366                             name='Min ride dist.',
3367                             info='Minimum ride distance. If the distanve between parkings is less, then the person will walk.',
3368                             ))
3369
3370        # if hasattr(self,'parking'):
3371        #    self.delete('parking')
3372
3373    def _init_constants(self):
3374        self.get_attrsman().do_not_save_attrs(['_costs', '_fstar', ])
3375
3376    def prepare_planning(self):
3377        net = self.get_virtualpop().get_net()
3378        # ??? do this for all vehicles??
3379        self._costs = net.edges.get_times(id_mode=net.modes.get_id_mode('passenger'),
3380                                          is_check_lanes=True)
3381        self._fstar = net.edges.get_fstar(is_ignor_connections=False)
3382
3383    def append_stage(self, id_plan, time_start=-1.0, id_veh=-1,
3384                     time_init=-1,
3385                     id_parking_from=.1, id_parking_to=-1, **kwargs):
3386        """
3387        Appends a ride stage to plan id_plan in case the ride is feasible.
3388        The ride is feasible if from parking and to parking are connected.
3389
3390        If feasible, the stage ID and estimated time when stage is finished
3391        will be returned.
3392
3393        If not feasible -1 and start time will be returned.
3394        """
3395        # print 'Rides.append_stage',id_stage
3396
3397        # check feasibility
3398        route, dist, duration = self.get_route_between_parking(id_parking_from, id_parking_to)
3399
3400        if (len(route) > 0):  # |(dist > self.dist_ride_min.get_value()): # is there a connection
3401            # create stage
3402            id_stage, time_end = StageTypeMixin.append_stage(self,
3403                                                             id_plan,
3404                                                             time_start,
3405                                                             durations=duration,
3406                                                             times_init=time_init,
3407                                                             ids_iauto=id_veh,
3408                                                             ids_parking_from=id_parking_from,
3409                                                             ids_parking_to=id_parking_to,
3410                                                             ids_edges=route,
3411                                                             )
3412
3413            # add this stage to the vehicle database
3414            # ind_ride gives the index of this ride (within the same plan??)
3415            #ind_ride = self.parent.get_iautos().append_ride(id_veh, id_stage)
3416            return id_stage, time_end
3417
3418        else:
3419            # not connected or too short of a distance
3420            return -1, time_start  # no stage creation took place
3421
3422    def get_route_between_parking(self, id_parking_from, id_parking_to):
3423        """
3424        Return route and distance of ride with vehicle type  vtype
3425        between id_parking_from and id_parking_to
3426
3427        """
3428        # print 'get_route_between_parking',id_parking_from, id_parking_to
3429        scenario = self.get_virtualpop().get_scenario()
3430        edges = scenario.net.edges
3431        lanes = scenario.net.lanes
3432
3433        # print   self.get_demand().getVehicles().cols.maxSpeed
3434        #v_max = self.get_demand().getVehicles().maxSpeed.get(vtype)
3435        parking = scenario.landuse.parking
3436
3437        ids_lanes = parking.ids_lane[[id_parking_from, id_parking_to]]
3438        id_edge_from, id_edge_to = lanes.ids_edge[ids_lanes]
3439        pos_from, pos_to = parking.positions[[id_parking_from, id_parking_to]]
3440
3441        # print '  id_edge_from, id_edge_to=',id_edge_from, id_edge_to
3442        duration_approx, route = routing.get_mincostroute_edge2edge(
3443            id_edge_from,
3444            id_edge_to,
3445            weights=self._costs,  # mode-specific!!
3446            fstar=self._fstar  # mode-specific!!
3447        )
3448
3449        # here is a big problem: starting with the successive node of edge_from
3450        # may result that the first edge of the route is not  connected with edge_from
3451        # And arriving at the preceding node of edge_to may result that from
3452        # the last edge in route the edge_to is not connected.
3453
3454        #route = [edge_from]+route+[edge_to]
3455        dist = np.sum(edges.lengths[route])
3456        dist = dist - pos_from - (edges.lengths[id_edge_to] - pos_to)
3457        # if 0:
3458        #    if len(route)>0:
3459        #         print '  dist,duration',dist,duration_approx
3460        #    else:
3461        #         print '  no route found'
3462
3463        return route, dist, duration_approx
3464
3465    # def make_id_veh_ride(self, id_stage, i_ride):
3466    #    # make a unique vehicle ID for this stage
3467    #    self.inds_ride[id_stage] = i_ride
3468    #    return str(self.ids_veh[id_stage])+'.'+str(i_ride)
3469
3470    def get_writexmlinfo(self, ids_plan, is_route=True):
3471        print 'AutorideStages.get_writexmlinfo', len(ids_plan)
3472        iautos = self.get_virtualpop().get_iautos()
3473        writefunc = iautos.prepare_write_xml()
3474        ids = self.get_ids_from_ids_plan(ids_plan)
3475        writefuncs = np.zeros(len(ids), dtype=np.object)
3476        writefuncs[:] = writefunc
3477        return self.times_init[ids], writefuncs, ids
3478
3479    def to_xml(self, id_stage, fd, indent=0):
3480        #lanes = self.parent.get_scenario().net.lanes
3481        scenario = self.get_virtualpop().get_scenario()
3482
3483        edges = scenario.net.edges
3484        edgeindex = edges.ids_sumo
3485        parking = scenario.landuse.parking
3486
3487        ind = self.get_ind(id_stage)
3488        fd.write(xm.start('ride', indent=indent))
3489
3490        id_edge_from, pos_from = parking.get_edge_pos_parking(self.ids_parking_from.value[ind])
3491        id_edge_to, pos_to = parking.get_edge_pos_parking(self.ids_parking_to.value[ind])
3492
3493        # edgeindex.get_index_from_id(self.ids_edge_to.value[ind])
3494        fd.write(xm.num('from', edgeindex[id_edge_from]))
3495        fd.write(xm.num('to',  edgeindex[id_edge_to]))
3496        fd.write(xm.num('lines', self.ids_iauto.get_linktab().get_id_line_xml(
3497            self.ids_iauto[id_stage])))  # mode specific
3498
3499        # if 0:
3500        #    #pos = pos_from
3501        #    length = max(edges.lengths[id_edge_from]-4.0,0.0)
3502        #
3503        #    if (pos_from>0) & (pos_from < length ):
3504        #        fd.write(xm.num('departPos', pos))
3505        #
3506        #    elif pos_from < 0:
3507        #        fd.write(xm.num('departPos', 0.0))
3508        #
3509        #    else:
3510        #        fd.write(xm.num('departPos', length))
3511        #
3512        #    #pos = self.positions_to.value[ind]
3513        #    length = max(edges.lengths[id_edge_to]-4.0, 0.0)
3514        #    if (pos_to>0) & (pos_to < length ):
3515        #        fd.write(xm.num('arrivalPos', pos_to))
3516        #
3517        #    elif pos_to < 0:
3518        #        fd.write(xm.num('arrivalPos', 0.0))
3519        #
3520        #    else:
3521        #        fd.write(xm.num('arrivalPos', length))
3522
3523        fd.write(xm.stopit())  # ends stage
3524
3525
3526class BikerideStages(StageTypeMixin):
3527
3528    def __init__(self, ident, population,
3529                 name='Bike rides',
3530                 info='Rides with privately owned bike.',
3531                 version=1.0,
3532                 ):
3533
3534        self.init_stagetable(ident, population, name=name, info=info)
3535        # print 'Rides.__init__',self.get_name()
3536        self._init_attributes()
3537
3538    def _init_attributes(self):
3539        # TODO: this structure needs review: the private vehicle is part of a person, not a stage
3540        # street parking at home and work could be in stage. Private garage is part of person...
3541        # print '_init_attributes',self.parent.get_iautos(), self.ident,self.parent.get_landuse().parking
3542
3543        self.add_col(am.IdsArrayConf('ids_ibike', self.get_virtualpop().get_ibikes(),
3544                                     groupnames=['state'],
3545                                     name='ID bike',
3546                                     info='ID of private, individual bike.',
3547                                     ))
3548
3549        self.add_col(am.ArrayConf('times_init', -1.0,
3550                                  name='Init. time',
3551                                  unit='s',
3552                                  info='Initialization time, which is the time when the vehicle appears in the scenario. Value -1 means unknown.',
3553                                  ))
3554
3555        edges = self.get_virtualpop().get_net().edges
3556
3557        self.add_col(am.IdsArrayConf('ids_edge_from', edges,
3558                                     groupnames=['state'],
3559                                     name='ID Dep. edge',
3560                                     info='Edge ID at departure of walk.',
3561                                     ))
3562
3563        self.add_col(am.IdsArrayConf('ids_edge_to', edges,
3564                                     groupnames=['state'],
3565                                     name='ID Arr. edge',
3566                                     info='Edge ID where walk finishes.',
3567                                     ))
3568
3569        self.add_col(am.ArrayConf('positions_from', 0.0,
3570                                  dtype=np.float32,
3571                                  #choices = OPTIONMAP_POS_DEPARTURE,
3572                                  perm='r',
3573                                  name='Depart pos',
3574                                  unit='m',
3575                                  info="Position on edge at the moment of departure.",
3576                                  #xmltag = 'departPos',
3577                                  #xmlmap = get_inversemap(OPTIONMAP_POS_ARRIVAL),
3578                                  ))
3579
3580        self.add_col(am.ArrayConf('positions_to', 0.0,
3581                                  dtype=np.float32,
3582                                  #choices = OPTIONMAP_POS_ARRIVAL,
3583                                  perm='r',
3584                                  name='Arrival pos',
3585                                  unit='m',
3586                                  info="Position on edge at the moment of arrival.",
3587                                  #xmltag = 'arrivalPos',
3588                                  #xmlmap = get_inversemap(OPTIONMAP_POS_ARRIVAL),
3589                                  ))
3590
3591        self.add_col(am.IdlistsArrayConf('ids_edges', self.get_virtualpop().get_net().edges,
3592                                         groupnames=['_private'],
3593                                         name='Route',
3594                                         info="The vehicle's route as a sequence of edge IDs.",
3595                                         ))
3596
3597    def _init_constants(self):
3598        self.get_attrsman().do_not_save_attrs(['_costs', '_fstar', ])
3599
3600    def prepare_planning(self):
3601        net = self.get_virtualpop().get_net()
3602
3603        print 'prepare_planning'
3604        self._costs = net.edges.get_times(id_mode=net.modes.get_id_mode('bicycle'),
3605                                          is_check_lanes=True)
3606
3607        ids_edge = net.edges.get_ids()
3608        for id_edge, cost in zip(ids_edge, self._costs[ids_edge]):
3609            print '   id_edge', id_edge, 'sumo', net.edges.ids_sumo[id_edge], cost
3610
3611        self._fstar = net.edges.get_fstar(is_ignor_connections=False)
3612
3613    def append_stage(self, id_plan, time_start=-1.0, id_veh=-1,
3614                     time_init=-1,
3615                     id_edge_from=-1, id_edge_to=-1,
3616                     position_edge_from=0.0, position_edge_to=0.0,
3617                     **kwargs):
3618        """
3619        Appends a ride stage to plan id_plan in case the ride is feasible.
3620        The ride is feasible if from parking and to parking are connected.
3621
3622        If feasible, the stage ID and estimated time when stage is finished
3623        will be returned.
3624
3625        If not feasible -1 and start time will be returned.
3626        """
3627        # print 'BikeRides.append_stage',id_plan,time_start,time_init
3628        #edges = self.get_virtualpop().get_net().edges
3629        # check feasibility
3630        #route, dist, duration = self.get_route_between_parking(id_parking_from, id_parking_to)
3631
3632        # print '  id_edge_from, id_edge_to=',id_edge_from, id_edge_to
3633        duration_approx, route = routing.get_mincostroute_edge2edge(
3634            id_edge_from,
3635            id_edge_to,
3636            weights=self._costs,  # mode-specific!!
3637            fstar=self._fstar  # mode-specific!!
3638        )
3639
3640        #route = [edge_from]+route+[edge_to]
3641
3642        #dist = np.sum(edges.lengths[route])
3643        #dist =  dist - pos_from - ( edges.lengths[id_edge_to] - pos_to)
3644
3645        if (len(route) > 0):  # |(dist > self.dist_ride_min.get_value()): # is there a connection
3646            # create stage
3647            id_stage, time_end = StageTypeMixin.append_stage(self,
3648                                                             id_plan,
3649                                                             time_start,
3650                                                             durations=duration_approx,
3651                                                             times_init=time_init,
3652                                                             ids_ibike=id_veh,
3653                                                             ids_edge_from=id_edge_from,
3654                                                             positions_from=position_edge_from,
3655                                                             ids_edge_to=id_edge_to,
3656                                                             positions_to=position_edge_to,
3657                                                             ids_edges=route,
3658                                                             )
3659
3660            # print '  route = ',route
3661            # print '  ids_edges = ',self.ids_edges[id_stage]
3662            # add this stage to the vehicle database
3663            # ind_ride gives the index of this ride (within the same plan??)
3664            #ind_ride = self.parent.get_iautos().append_ride(id_veh, id_stage)
3665            return id_stage, time_end
3666
3667        else:
3668            # not connected or too short of a distance
3669            return -1, time_start  # no stage creation took place
3670
3671    def get_writexmlinfo(self, ids_plan, is_route=True):
3672        print 'BikerideStages.get_writexmlinfo', len(ids_plan)
3673        ibikes = self.get_virtualpop().get_ibikes()
3674        bikewritefunc = ibikes.prepare_write_xml()
3675        ids = self.get_ids_from_ids_plan(ids_plan)
3676
3677        bikewritefuncs = np.zeros(len(ids), dtype=np.object)
3678        bikewritefuncs[:] = bikewritefunc
3679        return self.times_init[ids], bikewritefuncs, ids
3680
3681    def to_xml(self, id_stage, fd, indent=0):
3682        #lanes = self.parent.get_scenario().net.lanes
3683        scenario = self.get_virtualpop().get_scenario()
3684
3685        edges = scenario.net.edges
3686        edgeindex = edges.ids_sumo
3687
3688        #parking = scenario.landuse.parking
3689
3690        #ind = self.get_ind(id_stage)
3691        fd.write(xm.start('ride', indent=indent))
3692
3693        #id_edge_from, pos_from = parking.get_edge_pos_parking(self.ids_parking_from.value[ind])
3694        #id_edge_to, pos_to = parking.get_edge_pos_parking(self.ids_parking_to.value[ind])
3695
3696        # edgeindex.get_index_from_id(self.ids_edge_to.value[ind])
3697        id_edge_from = self.ids_edge_from[id_stage]
3698        fd.write(xm.num('from', edgeindex[self.ids_edge_from[id_stage]]))
3699        fd.write(xm.num('to',  edgeindex[self.ids_edge_to[id_stage]]))
3700        fd.write(xm.num('lines', self.ids_ibike.get_linktab().get_id_line_xml(
3701            self.ids_ibike[id_stage])))  # mode specific
3702
3703        # if 0:
3704        #    #pos = pos_from
3705        #    length = max(edges.lengths[id_edge_from]-4.0,0.0)
3706        #
3707        #    if (pos_from>0) & (pos_from < length ):
3708        #        fd.write(xm.num('departPos', pos))
3709        #
3710        #    elif pos_from < 0:
3711        #        fd.write(xm.num('departPos', 0.0))
3712        #
3713        #    else:
3714        #        fd.write(xm.num('departPos', length))
3715        #
3716        #    #pos = self.positions_to.value[ind]
3717        #    length = max(edges.lengths[id_edge_to]-4.0, 0.0)
3718        #    if (pos_to>0) & (pos_to < length ):
3719        #        fd.write(xm.num('arrivalPos', pos_to))
3720        #
3721        #    elif pos_to < 0:
3722        #        fd.write(xm.num('arrivalPos', 0.0))
3723        #
3724        #    else:
3725        #        fd.write(xm.num('arrivalPos', length))
3726
3727        fd.write(xm.stopit())  # ends stage
3728
3729
3730class WalkStages(StageTypeMixin):
3731    def __init__(self, ident, stages, name='WalkStages',
3732                 info='walk from a position on a lane to another position of another lane.'):
3733
3734        self.init_stagetable(ident, stages, name=name, info=info)
3735
3736        edges = self.get_virtualpop().get_scenario().net.edges
3737        self.add_col(am.IdsArrayConf('ids_edge_from', edges,
3738                                     groupnames=['state'],
3739                                     name='ID Dep. edge',
3740                                     info='Edge ID at departure of walk.',
3741                                     ))
3742
3743        self.add_col(am.IdsArrayConf('ids_edge_to', edges,
3744                                     groupnames=['state'],
3745                                     name='ID Arr. edge',
3746                                     info='Edge ID where walk finishes.',
3747                                     ))
3748
3749        self.add_col(am.ArrayConf('positions_from', 0.0,
3750                                  dtype=np.float32,
3751                                  #choices = OPTIONMAP_POS_DEPARTURE,
3752                                  perm='r',
3753                                  name='Depart pos',
3754                                  unit='m',
3755                                  info="Position on edge at the moment of departure.",
3756                                  #xmltag = 'departPos',
3757                                  #xmlmap = get_inversemap(OPTIONMAP_POS_ARRIVAL),
3758                                  ))
3759        self.positions_from.set_xmltag(None)
3760
3761        self.add_col(am.ArrayConf('positions_to', 0.0,
3762                                  dtype=np.float32,
3763                                  #choices = OPTIONMAP_POS_ARRIVAL,
3764                                  perm='r',
3765                                  name='Arrival pos',
3766                                  unit='m',
3767                                  info="Position on edge at the moment of arrival.",
3768                                  #xmltag = 'arrivalPos',
3769                                  #xmlmap = get_inversemap(OPTIONMAP_POS_ARRIVAL),
3770                                  ))
3771
3772        self.positions_to.set_xmltag(None)
3773
3774    def append_stage(self, id_plan, time_start=-1.0,
3775                     id_edge_from=-1, id_edge_to=-1,
3776                     position_edge_from=0.1, position_edge_to=0.0,
3777                     **kwargs):
3778        # print 'WalkStages.append_stage',id_stage
3779        if kwargs.has_key('duration'):
3780            duration = kwargs['duration']
3781        else:
3782            dist, duration = self.plan_walk(id_edge_from, id_edge_to,
3783                                            position_edge_from, position_edge_to)
3784
3785        id_stage, time_end = StageTypeMixin.append_stage(self,
3786                                                         id_plan,
3787                                                         time_start,
3788                                                         durations=duration,
3789                                                         ids_edge_from=id_edge_from,
3790                                                         ids_edge_to=id_edge_to,
3791                                                         positions_from=position_edge_from,
3792                                                         positions_to=position_edge_to,
3793                                                         )
3794
3795        return id_stage, time_end
3796
3797    def modify_stage(self, id_stage, time_start,
3798                     id_edge_from=-1, id_edge_to=-1,
3799                     position_edge_from=0.1, position_edge_to=0.0):
3800
3801        dist, duration = self.plan_walk(id_edge_from, id_edge_to,
3802                                        position_edge_from, position_edge_to)
3803
3804        time_end = StageTypeMixin.modify_stage(self, id_stage, time_start,
3805                                               durations=duration,
3806                                               ids_edge_from=id_edge_from,
3807                                               ids_edge_to=id_edge_to,
3808                                               positions_from=position_edge_from,
3809                                               positions_to=position_edge_to,
3810                                               )
3811
3812        return time_end
3813
3814    def plan_walk(self, id_edge_from, id_edge_to, pos_from, pos_to, id_mode=1):
3815        """
3816        Routing for pedestrians.
3817        Currently limited to estimation of line of sight distance
3818        and walk time.
3819        """
3820        # print 'plan_walk',id_edge_from, id_edge_to,id_mode, pos_from, pos_to
3821        scenario = self.get_virtualpop().get_scenario()
3822        edges = scenario.net.edges
3823
3824        coord_from = edges.get_coord_from_pos(id_edge_from, pos_from)
3825        coord_to = edges.get_coord_from_pos(id_edge_to, pos_to)
3826
3827        # from lanes, more precis, but less efficient and less robust
3828        # lanes = scenario.net.lanes
3829        #coord_from = lanes.get_coord_from_pos(edges.ids_lane[id_edge_from][0], pos_from)
3830        #coord_to = lanes.get_coord_from_pos(edges.ids_lane[id_edge_to][0], pos_to)
3831
3832        # print '  coord_from',coord_from,type(coord_from)
3833        # print '  coord_to',coord_from,type(coord_to)
3834        # print '  delta',coord_to-coord_from
3835        # line of sight distance
3836        dist = np.sqrt(np.sum((coord_to-coord_from)**2))
3837
3838        duration_approx = dist/scenario.net.modes.speeds_max[id_mode]
3839        # print '  dist,duration',dist,duration_approx,scenario.net.modes.speeds_max[id_mode]
3840
3841        return dist, duration_approx
3842
3843    def to_xml(self, id_stage, fd, indent=0):
3844        #scenario = self.parent.get_scenario()
3845        #edges = scenario.net.edges
3846        edges = self.ids_edge_from.get_linktab()
3847        edgeindex = edges.ids_sumo
3848
3849        ind = self.get_ind(id_stage)
3850
3851        id_edge_from = self.ids_edge_from.value[ind]
3852        id_edge_to = self.ids_edge_to.value[ind]
3853        fd.write(xm.start('walk', indent=indent))
3854        fd.write(xm.num('from', edgeindex[id_edge_from]))
3855        fd.write(xm.num('to', edgeindex[id_edge_to]))
3856
3857        pos = self.positions_from.value[ind]
3858        length = max(edges.lengths[id_edge_from]-4.0, 0.0)
3859
3860        # depricated
3861        # if (pos>0) & (pos < length ):
3862        #    fd.write(xm.num('departPos', pos))
3863        #
3864        # elif pos < 0:
3865        #    fd.write(xm.num('departPos', 0.0))
3866        #
3867        # else:
3868        #    fd.write(xm.num('departPos', length))
3869
3870        pos = self.positions_to.value[ind]
3871        length = max(edges.lengths[id_edge_to]-4.0, 0.0)
3872        if (pos > 0) & (pos < length):
3873            fd.write(xm.num('arrivalPos', pos))
3874
3875        elif pos < 0:
3876            fd.write(xm.num('arrivalPos', 0.0))
3877
3878        else:
3879            fd.write(xm.num('arrivalPos', length))
3880
3881        fd.write(xm.stopit())  # ends walk
3882
3883
3884class ActivityStages(StageTypeMixin):
3885    def __init__(self, ident, stages, name='Activities'):
3886        self.init_stagetable(ident, stages, name=name, info='Do some activity at a position of a lane.')
3887
3888        self._init_attributes()
3889
3890    def _init_attributes(self):
3891
3892        # TODO: this structure needs review: the private vehicle is part of a person, not a stage
3893        # street parking at home and work could be in stage. Private garage is part of person...
3894
3895        activities = self.get_virtualpop().get_activities()
3896        self.add_col(am.IdsArrayConf('ids_activity', activities,
3897                                     groupnames=['parameters'],
3898                                     name='Activity ID',
3899                                     info='Scheduled activity ID. This is the activity which schould be carried out in this stage.',
3900                                     ))
3901
3902        # this is redundant information but here for speed when writing xml
3903        self.add_col(am.ArrayConf('names_activitytype', '',
3904                                  groupnames=['parameters'],
3905                                  dtype=np.object,
3906                                  perm='r',
3907                                  name='Type name',
3908                                  info="Name of activity type.",
3909                                  xmltag='actType',
3910                                  #xmlmap = get_inversemap( activitytypes.names.get_indexmap()),
3911                                  ))
3912
3913        # self.add_col(am.IdsArrayConf( 'ids_facility', self.get_virtualpop().get_landuse().facilities,
3914        #                                groupnames = ['parameters'],
3915        #                                name = 'ID facility',
3916        #                                info = 'Facility where activity takes place.',
3917        #                                ))
3918
3919        # lane and position can be computed from facility
3920        self.add_col(am.IdsArrayConf('ids_lane', self.get_virtualpop().get_net().lanes,
3921                                     groupnames=['parameters'],
3922                                     name='Lane ID',
3923                                     info='Lane ID where activity takes place.',
3924                                     #xmltag = 'lane',
3925                                     ))
3926        # for update..can be removed
3927        self.ids_lane.set_xmltag(None)
3928
3929        self.add_col(am.ArrayConf('positions', 0.0,
3930                                  groupnames=['parameters'],
3931                                  dtype=np.float32,
3932                                  perm='r',
3933                                  name='Lane pos',
3934                                  unit='m',
3935                                  info="Position on lane nearby where activity takes place.",
3936                                  #xmltag = 'startPos',
3937                                  #xmlmap = get_inversemap(OPTIONMAP_POS_ARRIVAL),
3938                                  ))
3939
3940        self.positions.set_xmltag(None)
3941
3942        self.add_col(am.ArrayConf('durations', 0.0,
3943                                  groupnames=['parameters'],
3944                                  dtype=np.int32,
3945                                  perm='r',
3946                                  name='Duration',
3947                                  unit='s',
3948                                  info="Duration of activity.",
3949                                  xmltag='duration',
3950                                  #xmlmap = get_inversemap(OPTIONMAP_POS_ARRIVAL),
3951                                  ))
3952
3953        self.durations.set_xmltag('duration')
3954
3955    def get_edges_positions(self, ids_stage):
3956        """
3957        Returns road edge and positions of activity.
3958        """
3959        return self.ids_lane.get_linktab().ids_edge[self.ids_lane[ids_stage]],\
3960            self.positions[ids_stage]
3961
3962    def _init_constants(self):
3963            #self._activities  = self.get_virtualpop().get_activities()
3964            #self._activitytypes = self.get_virtualpop().get_demand().activitytypes
3965            # self.do_not_save_attrs(['_activities','_activitytypes'])
3966        pass
3967
3968    def to_xml(self, id_stage, fd, indent=0):
3969
3970        # <stop lane="1/4to2/4_0" duration="20" startPos="40" actType="singing"/>
3971
3972        #ind = self.get_ind(id_stage)
3973        fd.write(xm.start('stop', indent=indent))
3974
3975        lanes = self.get_virtualpop().get_net().lanes
3976        id_lane = self.ids_lane[id_stage]
3977        # get all xml configs and damp to fd
3978        for attrconf in self.get_group('parameters'):
3979            # this will write only if a xmltag is defined
3980            attrconf.write_xml(fd, id_stage)
3981        fd.write(xm.num('lane', lanes.get_id_sumo(id_lane)))
3982        #fd.write(xm.num('duration', self.durations[id_stage]))
3983
3984        pos = self.positions[id_stage]
3985        length = max(lanes.get_lengths(id_lane)-4.0, 0.0)
3986
3987        if (pos > 0) & (pos < length):
3988            fd.write(xm.num('startPos', pos))
3989
3990        elif pos < 0:
3991            fd.write(xm.num('startPos', 0.0))
3992
3993        else:
3994            fd.write(xm.num('startPos', length))
3995
3996        #fd.write(xm.num('lane', self.cols.id_lane[ind]))
3997        #fd.write(xm.num('startPos', self.cols.pos_lane[ind]))
3998        #fd.write(xm.num('duration', self.cols.duration[ind]))
3999        # fd.write(xm.num('actType', self._activitytypes.names[self._activities.)
4000
4001        fd.write(xm.stopit())  # ends activity
4002
4003
4004class Plans(am.ArrayObjman):
4005    def __init__(self, population,  **kwargs):
4006        """Plans database."""
4007        self._init_objman(ident='plans',
4008                          parent=population,
4009                          name='Plans',
4010                          info='Mobility plan for virtual population.',
4011                          #xmltag = ('plans','plan',None),
4012                          version=0.1,
4013                          **kwargs)
4014
4015        self._init_attributes()
4016        self._init_constants()
4017
4018    def _init_attributes(self):
4019
4020        # upgrade
4021        if self.get_version() < 0.1:
4022            pass
4023
4024        self.set_version(0.1)
4025        persons = self.parent
4026
4027        #self.add(cm.ObjConf(StageTables('stagetables',self))   )
4028
4029        self.add_stagetable('walks', WalkStages)
4030        self.add_stagetable('autorides', AutorideStages)
4031        self.add_stagetable('bikerides', BikerideStages)
4032        self.add_stagetable('transits', TransitStages)
4033        self.add_stagetable('activities', ActivityStages)
4034
4035        self.add_col(am.IdsArrayConf('ids_person', persons,
4036                                     groupnames=['links'],
4037                                     name='Person ID',
4038                                     info='Person ID to who this plan belongs to.',
4039                                     ))
4040
4041        self.add_col(am.IdsArrayConf('ids_strategy', persons.get_strategies(),
4042                                     groupnames=['links'],
4043                                     name='Stategy ID',
4044                                     info='Stategy ID with which this plan has been generated.',
4045                                     ))
4046
4047        self.add_col(am.ArrayConf('times_begin', -np.inf,
4048                                  dtype=np.float32,
4049                                  name='Begin time',
4050                                  info='Time when active travelling begins. This is the time in the simulation when the person appears. The first activity is not simulated.',
4051                                  unit='s',
4052                                  ))
4053
4054        self.add_col(am.ArrayConf('times_end', -np.inf,
4055                                  dtype=np.float32,
4056                                  name='End time',
4057                                  info='Time when active travelling ends. This is the time in the simulation when the person disappears. The last activity is not simulated.',
4058                                  unit='s',
4059                                  ))
4060
4061        self.add_col(am.ArrayConf('times_est', 0.0,
4062                                  dtype=np.float32,
4063                                  name='Estim. time',
4064                                  info='Estimated time duration to execute travel plan. Activity times are excluded.',
4065                                  unit='s',
4066                                  ))
4067
4068        self.add_col(am.ArrayConf('times_exec', 0.0,
4069                                  dtype=np.float32,
4070                                  name='Exec. time',
4071                                  info='Last plan execution time from simulation run.',
4072                                  unit='s',
4073                                  ))
4074
4075        self.add_col(am.ArrayConf('utilities', 0.0,
4076                                  dtype=np.float32,
4077                                  name='utility',
4078                                  info='Utility of plan.',
4079                                  ))
4080
4081        self.add_col(am.ArrayConf('probabilities', 1.0,
4082                                  dtype=np.float32,
4083                                  name='Probability',
4084                                  info='Probability that the plan is selected out of all plans available for one person.',
4085                                  ))
4086
4087        self.add_col(am.TabIdListArrayConf('stagelists',
4088                                           name='Stages',
4089                                           info='Sequence of stages of this plan.',
4090                                           ))
4091
4092    def _init_constants(self):
4093        #self._id_mode_bike = self.parent.get_scenario().net.modes.get_id_mode('bicycle')
4094        # self.do_not_save_attrs([])
4095        pass
4096
4097    def clear_plans(self):
4098        print 'Plans.clear_plans'
4099        for stagetable in self.get_stagetables():
4100            # print '  stagetable',stagetable
4101            stagetable.clear()
4102
4103        self.clear_rows()
4104        # for attrconfig in  self.get_attrsman().get_colconfigs():
4105        #    print '  clear attrconfig',attrconfig.attrname
4106        #    attrconfig.clear()
4107        # no: self.clear()
4108
4109    def add_stagetable(self, ident, StagesClass, **kwargs):
4110        if not hasattr(self, ident):
4111            self.add(cm.ObjConf(StagesClass(ident, self, **kwargs),
4112                                groupnames=['stagetables']))
4113        return getattr(self, ident).get_value()
4114
4115    def get_stagetable(self, ident):
4116        return getattr(self, ident).get_value()
4117
4118    def get_stagetables(self):
4119        """Return a list of with all stage objects"""
4120        stageobjs = []
4121        # print 'get_stagetables',self.get_group('stagetables')
4122        for stageobj in self.get_group('stagetables'):
4123            stageobjs.append(stageobj)
4124        return stageobjs
4125
4126    def prepare_stagetables(self, idents_stagetable):
4127        # print 'prepare_stages',stagenames
4128        #ids = self.names.get_ids_from_indices_save(stagenames)
4129        # print '  ids',ids
4130        # print '  self.stagetables[ids]',self.stagetables[ids]
4131        for indent in idents_stagetable:
4132            self.get_stagetable(indent).prepare_planning()
4133
4134    def get_stages(self, id_plan):
4135        stages = self.stagelists[id_plan]
4136        if stages is None:
4137            return []
4138        else:
4139            return stages
4140
4141    def append_stage(self, id_plan, stage, id_stage):
4142        # test: stage = cm.TableEntry(stagetable, id_plan)
4143        # print 'Plans.append_stage',self,id_plan, stage, id_stage
4144
4145        if self.stagelists[id_plan] is None:
4146            self.stagelists[id_plan] = [(stage, id_stage)]
4147        else:
4148            self.stagelists[id_plan].append((stage, id_stage))
4149        # print '  after append stagelists[id_plan]',type(self.stagelists[id_plan]),self.stagelists[id_plan]
4150
4151    # def prepare_stages(self,stagenames):
4152    #    self.get_stagetables().prepare_stages(stagenames)
4153
4154    def get_timing_laststage(self, id_plan):
4155        """
4156        Return time_start and duration of last stage of plan id_plan
4157        """
4158        stages_current = self.stagelists[id_plan]
4159
4160        if stages_current is not None:
4161            stage_last, id_stage_last = stages_current[-1]
4162            return stage_last.get_timing(id_stage_last)
4163        else:
4164            return -1, -1
4165
4166
4167class Virtualpopulation(DemandobjMixin, am.ArrayObjman):
4168    def __init__(self, ident, demand, **kwargs):
4169        self._init_objman(ident=ident,
4170                          parent=demand,
4171                          name='Virtual population',
4172                          info='Contains information of each individual of the virtual population.',
4173                          version=0.2,  # only for new scenarios
4174                          **kwargs)
4175        self._init_attributes()
4176        self._init_constants()
4177
4178    def _init_attributes(self):
4179
4180        # update here
4181
4182        #
4183        self.set_version(0.2)
4184
4185        demand = self.parent
4186        scenario = demand.get_scenario()
4187
4188        # --------------------------------------------------------------------
4189        # individual vehicles tables
4190
4191        self.add(cm.ObjConf(IndividualAutos('iautos', self)))
4192        self.add(cm.ObjConf(IndividualBikes('ibikes', self)))
4193        self.add(cm.ObjConf(IndividualMotorcycles('imotos', self)))
4194
4195        # --------------------------------------------------------------------
4196        # activity  table
4197        #self.add(cm.ObjConf(ActivityTypes('activitytypes', self))   )
4198        self.add(cm.ObjConf(Activities('activities', self)))
4199
4200        # --------------------------------------------------------------------
4201        # strategies table (must be before plans)
4202
4203        self.add(cm.ObjConf(Strategies('strategies', self)))
4204
4205        # --------------------------------------------------------------------
4206        # plans table
4207        self.add(cm.ObjConf(Plans(self)))
4208
4209        self.get_strategies().add_default()
4210
4211        # ===================================================================
4212        # Add person attributes
4213
4214        # --------------------------------------------------------------------
4215        # socio economic parameters
4216        self.add_col(am.ArrayConf('identifications', '',
4217                                  dtype=np.object,
4218                                  groupnames=['socioeconomic'],
4219                                  name='Name',
4220                                  info='Identification or name of person.',
4221                                  ))
4222
4223        self.add_col(am.ArrayConf('ids_gender', default=-1,
4224                                  dtype=np.int32,
4225                                  groupnames=['socioeconomic'],
4226                                  choices=GENDERS,
4227                                  name='Gender',
4228                                  info='Gender of person.',
4229                                  ))
4230
4231        self.add_col(am.ArrayConf('years_birth', default=-1,
4232                                  dtype=np.int32,
4233                                  groupnames=['socioeconomic'],
4234                                  name='Birth year',
4235                                  info='Year when person has been born.',
4236                                  ))
4237
4238        self.add_col(am.ArrayConf('ids_occupation', default=OCCUPATIONS['unknown'],
4239                                  dtype=np.int32,
4240                                  choices=OCCUPATIONS,
4241                                  groupnames=['socioeconomic'],
4242                                  name='Occupation',
4243                                  info='Type of occupation.',
4244                                  ))
4245
4246        # --------------------------------------------------------------------
4247        # household parameters
4248        self.add_col(am.ArrayConf('numbers_houehold', default=1,
4249                                  dtype=np.int32,
4250                                  groupnames=['household'],
4251                                  name='Number in household',
4252                                  info='Number of persons in household.',
4253                                  ))
4254
4255        self.add_col(am.ArrayConf('numbers_minor', default=0,
4256                                  dtype=np.int32,
4257                                  groupnames=['household'],
4258                                  name='Number minors',
4259                                  info='Number of minor in household. In the context of traffic simulations minors are persons who need to be accompaigned by adulds when travelling.',
4260                                  ))
4261
4262        # --------------------------------------------------------------------
4263        # activity parameters
4264        # lists with activity patterns
4265
4266        self.add_col(am.IdlistsArrayConf('activitypatterns', self.activities.get_value(),
4267                                         groupnames=['activity'],
4268                                         name='Activity IDs',
4269                                         info="Sequence of activity IDs to be accomplished by the person.",
4270                                         ))
4271
4272        # --------------------------------------------------------------------
4273        # mobility parameters
4274        # --------------------------------------------------------------------
4275
4276        # give a pedestrian vtype to each person
4277        vtypes = self.get_demand().vtypes
4278        self.add_col(am.IdsArrayConf('ids_vtype', vtypes,
4279                                     id_default=vtypes.select_by_mode(mode='pedestrian')[0],
4280                                     groupnames=['mobility'],
4281                                     name='Ped. type',
4282                                     info='The pedestrian type ID specifies the walking characteristics and visual representation of the person. In SUMO terminology, this is the vehicle type.',
4283                                     #xmltag = 'type',
4284                                     ))
4285
4286        self.add_col(am.ArrayConf('traveltimebudgets', default=55*60,
4287                                  dtype=np.int32,
4288                                  groupnames=['mobility'],
4289                                  name='time budget',
4290                                  unit='s',
4291                                  info='Daily time budget used for traveling.',
4292                                  ))
4293
4294        self.add_col(am.IdsArrayConf('ids_mode_preferred', scenario.net.modes,
4295                                     groupnames=['mobility'],
4296                                     name='ID preferred mode',
4297                                     info='ID of preferred transport mode of person.',
4298                                     ))
4299
4300        self.add_col(am.IdsArrayConf('ids_iauto', self.get_iautos(),
4301                                     groupnames=['mobility'],
4302                                     name='ID auto',
4303                                     info='ID of individual auto. Negative value means no bile available.',
4304                                     ))
4305
4306        self.add_col(am.IdsArrayConf('ids_ibike', self.get_ibikes(),
4307                                     groupnames=['mobility'],
4308                                     name='ID bike',
4309                                     info='ID of individual bicycle. Negative value means no bike available.',
4310                                     ))
4311
4312        self.add_col(am.IdsArrayConf('ids_imoto', self.get_imotos(),
4313                                     groupnames=['mobility'],
4314                                     name='ID motorcycle',
4315                                     info='ID of individual motorcycle. Negative value means no motorcycle available.',
4316                                     ))
4317
4318        self.add_col(am.ArrayConf('dists_walk_max', default=300.0,
4319                                  dtype=np.float32,
4320                                  groupnames=['mobility'],
4321                                  name='Max. walk dist',
4322                                  info='Maximum acceptable walking distance between origin and destination or for transfers between modes.',
4323                                  ))
4324
4325        # --------------------------------------------------------------------
4326        # plans
4327        self.add_col(am.IdsArrayConf('ids_plan', self.get_plans(),
4328                                     groupnames=['plans'],
4329                                     name='ID Plan',
4330                                     info='Currently selected mobility plan ID of person. This is the plan which will be simulated.',
4331                                     ))
4332
4333        self.add_col(am.IdlistsArrayConf('lists_ids_plan', self.get_plans(),
4334                                         groupnames=['plans'],
4335                                         name='Plan IDs',
4336                                         info='List with alternative, feasible mobility plan IDs for each person.',
4337                                         ))
4338
4339    def _init_constants(self):
4340        modes = self.get_scenario().net.modes
4341        self.id_mode_bike = modes.get_id_mode('bicycle')
4342        self.id_mode_auto = modes.get_id_mode('passenger')
4343        self.id_mode_moto = modes.get_id_mode('motorcycle')
4344        self._edges = self.get_net().edges
4345        self.do_not_save_attrs(['id_mode_bike', 'id_mode_auto', 'id_mode_moto',
4346                                '_edges'])
4347
4348    def get_demand(self):
4349        return self.parent
4350
4351    def clear_population(self):
4352        # self.clear()
4353        self.clear_plans()
4354        self.clear_ivehicles()
4355
4356        # TODO: this should disappear
4357        self.get_landuse().parking.clear_booking()
4358
4359        # for attrconfig in  self.get_attrsman().get_colconfigs():
4360        #    attrconfig.clear()
4361        self.clear_rows()
4362
4363    def clear_plans(self):
4364        # print 'clear_plans',self.get_stagetables()
4365        self.ids_plan.reset()
4366        self.lists_ids_plan.reset()
4367        self.get_plans().clear_plans()
4368
4369        # TODO: this should disappear
4370        self.get_landuse().parking.clear_booking()
4371
4372    def clear_ivehicles(self):
4373        """
4374        Clear all individually owned vehicles.
4375        """
4376        print 'clear_ivehicles'
4377        self.get_iautos().clear_vehicles()
4378        self.get_ibikes().clear_vehicles()
4379        self.get_imotos().clear_vehicles()
4380
4381    def get_activities(self):
4382        return self.activities.get_value()
4383
4384    def get_strategies(self):
4385        return self.strategies.get_value()
4386
4387    def get_plans(self):
4388        return self.plans.get_value()
4389
4390    def get_iautos(self):
4391        return self.iautos.get_value()
4392
4393    def get_ibikes(self):
4394        return self.ibikes.get_value()
4395
4396    def get_imotos(self):
4397        return self.imotos.get_value()
4398
4399    def get_stagetables(self):
4400        return self.get_plans().get_stagetables()
4401
4402    def get_landuse(self):
4403        return self.parent.get_scenario().landuse
4404
4405    def get_scenario(self):
4406        return self.parent.get_scenario()
4407
4408    def get_net(self):
4409        return self.parent.get_scenario().net
4410
4411    def get_ptlines(self):
4412        return self.get_demand().ptlines
4413
4414    def get_ptstops(self):
4415        return self.get_net().ptstops
4416
4417    def get_id_sumo_from_id(self, id_sumo):
4418        return u'vp.%s' % id_sumo
4419
4420    def get_id_from_id_sumo(self, id_veh_sumo):
4421        if len(id_veh_sumo.split('.')) == 2:
4422            prefix, id_pers = id_veh_sumo.split('.')
4423            if prefix == 'vp':
4424                return int(id_pers)
4425            else:
4426                return -1
4427        return -1
4428
4429    def get_ids_from_ids_sumo(self, ids_sumo):
4430        ids = np.zeros(len(ids_sumo), dtype=int32)
4431        for id_sumo in ids_sumo:
4432            ids[i] = self.get_id_from_id_sumo(id_sumo)
4433        return ids
4434
4435    def get_time_depart_first(self):
4436        # print 'Virtualpop.get_time_depart_first'
4437        if len(self.get_plans()) > 0:
4438            plans = self.get_plans()
4439            ids = self.select_ids(self.ids_plan.get_value() >= 0)
4440            # print '  ids',ids
4441            return float(np.min(plans.times_begin[self.ids_plan[ids]]))
4442        else:
4443            return 0.0
4444
4445    def get_time_depart_last(self):
4446        if len(self.get_plans()) > 0:
4447            # todo: this can be improved by adding plan execution time
4448            plans = self.get_plans()
4449            ids = self.select_ids(self.ids_plan.get_value() >= 0)
4450
4451            return float(np.max(plans.times_end[self.ids_plan[ids]]))
4452        else:
4453            return 0.0
4454
4455    # def add_stagetable(self,ident,StageClass, **kwargs):
4456    #    print 'add_stagetable',ident,StageClass#,kwargs
4457    #    if not hasattr(self,ident):
4458    #        #print '  StageClass',StageClass(ident, self, **kwargs)
4459    #        #print '  ObjConf',cm.ObjConf(StageClass(ident, self, **kwargs), goupnames = ['stages'])
4460    #        self.add(cm.ObjConf(StageClass(ident, self, **kwargs), goupnames = ['stages']) )
4461    #    return getattr(self, ident).get_value()
4462
4463    # def get_stagetable(self, ident):
4464    #    return getattr(self, ident).get_value()
4465
4466    # def get_stagetables(self):
4467    #    """Return a list of with all stage objects"""
4468    #    stageobjs = []
4469    #    #print 'get_stagetables',self.get_group('stages')
4470    #    for stageobj in self.get_group('stages'):
4471    #        stageobjs.append(stageobj)
4472    #    return stageobjs
4473
4474    def make_multiple(self, n, **kwargs):
4475        return self.add_rows(n=n, **kwargs)
4476
4477    def disaggregate_odflow(self,   time_start, time_end, id_mode,
4478                            ids_fac, probs_fac_orig, probs_fac_dest,
4479                            tripnumber_tot,
4480                            id_activitytype_orig,
4481                            id_activitytype_dest,
4482                            hour_begin_earliest_orig,
4483                            hour_begin_earliest_dest,
4484                            hour_begin_latest_orig,
4485                            hour_begin_latest_dest,
4486                            duration_min_orig,
4487                            duration_min_dest,
4488                            duration_max_orig,
4489                            duration_max_dest,
4490                            scale=1.0,
4491                            hour_offset=8.0,  # 08:00
4492                            hour_tripbudget=25.0/60,  # 25min
4493                            **kwargs
4494                            ):
4495        """
4496        Disaggregation of demand dem  from taz id_zone_orig to id_zone_dest with id_mode
4497        during time interval  time_start,time_end, and creation of persons
4498        which are parameterized accordingly.
4499        The facility type at origin will be  landusetype_orig
4500        and at destination landusetype_dest.
4501
4502
4503        """
4504        tripnumber = int(scale*tripnumber_tot)
4505        print 'disaggregate_odflow', time_start, time_end, id_mode, tripnumber
4506
4507        print ' id_activitytype_orig,id_activitytype_dest', id_activitytype_orig, id_activitytype_dest
4508
4509        # print '  probs_orig',sum(probs_fac_orig),'\n',probs_fac_orig
4510        # print '  probs_dest',sum(probs_fac_dest),'\n',probs_fac_dest
4511
4512        # is there a chance to find facilities to locate persons in
4513        # origin and destination zone
4514
4515        #activitytypes= self.get_scenario().demand.activitytypes
4516        #ctivitynames = self.activitytypes.names
4517        #get_id_act = activitynames.get_id_from_index
4518
4519        if (np.sum(probs_fac_orig) > 0) & (np.sum(probs_fac_dest) > 0):
4520            # if id_mode == self._id_mode_bike:
4521            #    are_bikeowner =  np.ones(tripnumber, dtype=np.bool)
4522            # else:
4523            #    # TODO: assign a default percentage of bike owners
4524            #    are_bikeowner =  np.zeros(tripnumber, dtype=np.bool)
4525            #times_start = np.random.randint(time_start,time_end,tripnumber)
4526            ids_person = self.make_multiple(tripnumber,
4527                                            ids_mode_preferred=id_mode * np.ones(tripnumber, dtype=np.int32),
4528                                            #times_start = times_start,
4529                                            )
4530
4531            unitvec_int = np.ones(tripnumber, dtype=np.int32)
4532            unitvec_float = np.ones(tripnumber, dtype=np.int32)
4533
4534            # activity timing
4535            #hours_start = hour_offset + np.array(times_start,dtype = np.float32)/3600
4536            #tol_orig = hour_begin_latest_orig+duration_max_orig-(hour_begin_earliest_orig+duration_min_orig)
4537
4538            # print '  hours_start[:3]',hours_start[:3]
4539            # print '  tol_orig',tol_orig
4540
4541            #hours_end_est = hours_start + hour_tripbudget
4542            #tol_dest = hour_begin_latest_dest-hour_begin_earliest_dest
4543
4544            # print '  hours_end_est[:3]',hours_end_est[:3]
4545            # print '  tol_dest',tol_dest
4546
4547            #self.map_id_act_to_ids_facattrconf[id_activitytype_orig][ids_person] = ids_fac[random_choice(tripnumber, probs_fac_orig)]
4548            #self.map_id_act_to_ids_facattrconf[id_activitytype_dest][ids_person] = ids_fac[random_choice(tripnumber, probs_fac_dest)]
4549            activities = self.get_activities()
4550
4551            # fix first departure hours for first activity imposed by
4552            # OD flow data
4553            hours_end_earliest_orig = (hour_offset+float(time_start)/3600)*unitvec_float
4554            hours_end_latest_orig = (hour_offset+float(time_end)/3600)*unitvec_float
4555
4556            duration_mean_orig = 0.5 * duration_min_orig+duration_max_orig
4557            hours_begin_earliest_orig = hours_end_earliest_orig-duration_mean_orig
4558            hours_begin_latest_orig = hours_end_latest_orig-duration_mean_orig
4559
4560            # this estimate could be *optionally* replaced by preliminary routing
4561            hours_begin_earliest_dest = hours_end_earliest_orig+hour_tripbudget
4562            hours_begin_latest_dest = hours_end_latest_orig+hour_tripbudget
4563
4564            #hours_end_earliest_dest = hours_begin_earliest_dest+duration_min_dest
4565            #hours_end_latest_dest = hours_begin_latest_dest+duration_max_dest
4566
4567            ids_activity_orig = activities.add_rows(
4568                n=tripnumber,
4569                ids_activitytype=id_activitytype_orig * unitvec_int,
4570                ids_facility=ids_fac[random_choice(tripnumber, probs_fac_orig)],
4571                hours_begin_earliest=hours_begin_earliest_orig,
4572                hours_begin_latest=hours_begin_latest_orig,
4573                durations_min=duration_mean_orig-1.0/60.0 * unitvec_float,  # min mast be less than max to prevent crash
4574                durations_max=duration_mean_orig * unitvec_float,
4575            )
4576
4577            ids_activity_dest = activities.add_rows(
4578                n=tripnumber,
4579                ids_activitytype=id_activitytype_dest * unitvec_int,
4580                ids_facility=ids_fac[random_choice(tripnumber, probs_fac_dest)],
4581                hours_begin_earliest=hours_begin_earliest_dest,
4582                hours_begin_latest=hours_begin_latest_dest,
4583                durations_min=duration_min_dest*unitvec_float,
4584                durations_max=duration_max_dest*unitvec_float,
4585            )
4586
4587            for id_person, id_activity_orig, id_activity_dest in zip(ids_person, ids_activity_orig, ids_activity_dest):
4588                self.activitypatterns[id_person] = [id_activity_orig, id_activity_dest]
4589
4590            #activitypatterns = np.zeros((tripnumber,2), dtype = np.int32)
4591            #activitypatterns[:,0]= ids_activity_orig
4592            #activitypatterns[:,1]= ids_activity_dest
4593            # try convert in this way to lists
4594            # print '  activitypatterns',activitypatterns.tolist()
4595            #self.activitypatterns[ids_person] = activitypatterns.tolist()
4596            # for id_person, act_pattern in zip(ids_person,activitypatterns.tolist()):
4597            #    self.activitypatterns[id_person] =  act_pattern
4598
4599            return ids_person
4600        else:
4601            print 'WARNING in disaggregate_odflow: no probabilities', np.sum(probs_fac_orig), np.sum(probs_fac_dest)
4602
4603            return []
4604
4605    def create_pop_from_odflows(self, is_use_landusetypes=False, **kwargs):
4606        """
4607        Creates a population and defines home and activity facility
4608        according to OD matrix defined in odflows.
4609        The population is distributed within the zones according to
4610        the area of the facility.
4611        if  landusetype_orig and landusetype_dest also landuse types
4612        of facilities of origin and destination are taken into account.
4613        """
4614        print 'create_pop_from_odflows'
4615
4616        demand = self.parent
4617        odflowtab = demand.odintervals.generate_odflows()
4618        landuse = self.get_landuse()
4619        activitytypes = demand.activitytypes
4620        log = kwargs.get('logger', self.get_logger())
4621
4622        if is_use_landusetypes:
4623
4624            # TODO: not tested and works only for one landusetype per activity
4625            #activitytypes = self.activitytypes.get_value()
4626            #id_landusetype_orig = activitytypes.ids_landusetypes[kwargs['id_activitytype_orig']][0]
4627            #id_landusetype_dest = activitytypes.ids_landusetypes[kwargs['id_activitytype_dest']][0]
4628            pass
4629            # TODO: get activitypes from activity
4630            #probs_fac, ids_fac = self.get_landuse().facilities.get_departure_probabilities_landuse()
4631
4632        else:
4633            probs_fac_area, ids_fac = landuse.facilities.get_departure_probabilities()
4634
4635        # self._make_map_id_act_to_ids_facattrconf()
4636        ids_flow = odflowtab.get_ids()
4637        n_flows = len(ids_flow)
4638
4639        ids_activitytype_orig = odflowtab.ids_activitytype_orig[ids_flow]
4640        ids_activitytype_dest = odflowtab.ids_activitytype_dest[ids_flow]
4641
4642        i = 0.0
4643        for id_flow,\
4644            id_orig,\
4645            id_dest,\
4646            id_mode,\
4647            time_start,\
4648            time_end,\
4649            tripnumber,\
4650            id_activitytype_orig,\
4651            id_activitytype_dest,\
4652            hour_begin_earliest_orig,\
4653            hour_begin_earliest_dest,\
4654            hour_begin_latest_orig,\
4655            hour_begin_latest_dest,\
4656            duration_min_orig,\
4657            duration_min_dest,\
4658            duration_max_orig,\
4659            duration_max_dest\
4660            in zip(ids_flow,
4661                   odflowtab.ids_orig[ids_flow],
4662                   odflowtab.ids_dest[ids_flow],
4663                   odflowtab.ids_mode[ids_flow],
4664                   odflowtab.times_start[ids_flow],
4665                   odflowtab.times_end[ids_flow],
4666                   odflowtab.tripnumbers[ids_flow],
4667                   ids_activitytype_orig,
4668                   ids_activitytype_dest,
4669                   activitytypes.hours_begin_earliest[ids_activitytype_orig],
4670                   activitytypes.hours_begin_earliest[ids_activitytype_dest],
4671                   activitytypes.hours_begin_latest[ids_activitytype_orig],
4672                   activitytypes.hours_begin_latest[ids_activitytype_dest],
4673                   activitytypes.durations_min[ids_activitytype_orig],
4674                   activitytypes.durations_min[ids_activitytype_dest],
4675                   activitytypes.durations_max[ids_activitytype_orig],
4676                   activitytypes.durations_max[ids_activitytype_dest],
4677                   ):
4678
4679            log.progress(i/n_flows*100)
4680            i += 1
4681            if is_use_landusetypes:
4682                # TODO: not tested and works only for one landusetype per activity
4683                # but in activity typrs several landuse types are defined
4684
4685                # idea: add the probabilities for landuse types of origin and dest
4686                #probs_fac_orig = probs_fac[id_orig][id_landusetype_orig]
4687                #probs_fac_dest = probs_fac[id_dest][id_landusetype_dest]
4688                pass
4689            else:
4690                probs_fac_orig = probs_fac_area[id_orig]
4691                probs_fac_dest = probs_fac_area[id_dest]
4692
4693            self.disaggregate_odflow(time_start,
4694                                     time_end,
4695                                     id_mode,
4696                                     ids_fac,
4697                                     probs_fac_orig,
4698                                     probs_fac_dest,
4699                                     tripnumber,
4700                                     id_activitytype_orig,
4701                                     id_activitytype_dest,
4702                                     hour_begin_earliest_orig,
4703                                     hour_begin_earliest_dest,
4704                                     hour_begin_latest_orig,
4705                                     hour_begin_latest_dest,
4706                                     duration_min_orig,
4707                                     duration_min_dest,
4708                                     duration_max_orig,
4709                                     duration_max_dest,
4710                                     **kwargs
4711                                     )
4712
4713        # return odflowtab
4714
4715    def add_plans(self, ids_person, id_strategy=-1):
4716        print 'add_plans n, id_strategy', len(ids_person), id_strategy
4717        n_plans = len(ids_person)
4718        # print '  get_plans',self.get_plans()
4719        # print '  stagetables',self.get_plans().get_stagetables().get_ident_abs()
4720        # print '  stagetables',self.get_plans().get_stagetables().stagetables.get_value()
4721        ids_plan = self.get_plans().add_rows(n=n_plans,
4722                                             ids_person=ids_person,
4723                                             ids_strategy=id_strategy*np.ones(n_plans, dtype=np.int32),
4724                                             )
4725
4726        # print '  post stagetables',self.get_plans().get_stagetables().get_ident_abs()
4727        # print '  post stagetables',self.get_plans().get_stagetables().stagetables.get_value()
4728
4729        # return ids_plan
4730        self.ids_plan[ids_person] = 1*ids_plan
4731
4732        for id_person, id_plan in zip(ids_person, ids_plan):
4733            if self.lists_ids_plan[id_person] is None:
4734                self.lists_ids_plan[id_person] = [id_plan]
4735            else:
4736                self.lists_ids_plan[id_person].append(id_plan)
4737        return ids_plan
4738
4739    def plan_with_strategy(self, id_strategy, evalcrit=0, logger=None):
4740        strategy = self.get_strategies().strategies[id_strategy]
4741        ids_person = self.get_ids()
4742        evals = strategy.preevaluate(ids_person)
4743        # TODO: check whether at least two activities are in
4744        # activitypattern...could be done centrally
4745
4746        ids_person_preeval = ids_person[evals >= evalcrit]
4747        print 'plan_with_strategy', strategy.ident, 'n_pers', len(ids_person_preeval)
4748        strategy.plan(ids_person_preeval, logger=logger)
4749
4750    # def get_times(self, ind, ids_person = None, pdf = 'unit'):
4751    #    """
4752    #    Returns person IDs, activity IDs and initial times
4753    #    for persons with at least one acivity.
4754    #
4755    #    ids_person: array of preselected person IDs
4756    #
4757    #    pdf: gives the probability density function to be chosen to determin
4758    #    the departure times within the initial time intervals given by
4759    #    initial activity attributes.
4760    #    """
4761    #    ids_person, ids_activity = self.get_activity_from_pattern(0,ids_person)
4762    #    times_init = self.get_activities().get_times_init(ids_activity, pdf)
4763    #
4764    #    return ids_person, ids_activity, times_init
4765
4766    def get_activities_from_pattern(self, ind, ids_person=None):
4767        """
4768        Returns person IDs and from/to activity IDs for persons who perform an activity
4769        at the given activity index ind.
4770        Returns arrays: ids_person, ids_activity_from, ids_activity_to
4771
4772        ind: index of activity in activity pattern, starting with 0
4773        ids_person: array of preselected person IDs
4774
4775
4776        """
4777
4778        ids_person_activity = []
4779        ids_activity_from = []
4780        ids_activity_to = []
4781        if ids_person is None:
4782            ids_person = self.get_ids()
4783
4784        for id_person, activitypattern in zip(ids_person, self.activitypatterns[ids_person]):
4785            # has person activity at index ind?
4786            if len(activitypattern) > ind+1:
4787                ids_person_activity.append(id_person)
4788                ids_activity_from.append(activitypattern[ind])
4789                ids_activity_to.append(activitypattern[ind+1])
4790
4791        return ids_person_activity, ids_activity_from, ids_activity_to
4792
4793        #        activities.hours_begin_earliest[ids_person_activity],
4794        #        activities.hours_begin_latest[ids_person_activity],
4795        #        activities.durations_min[ids_person_activity],
4796        #        activities.durations_max[ids_person_activity],
4797
4798    def get_vtypes(self):
4799
4800        ids_vtypes = set()
4801        # get individual vehicle types
4802        ids_vtypes.update(self.get_iautos().ids_vtype.get_value())
4803        ids_vtypes.update(self.get_imotos().ids_vtype.get_value())
4804        ids_vtypes.update(self.get_ibikes().ids_vtype.get_value())
4805
4806        # add public transport
4807        ids_vtypes.update(self.get_ptlines().ids_vtype.get_value())
4808
4809        # add pedestrian types
4810        ids_vtypes.update(self.ids_vtype.get_value())
4811
4812        return ids_vtypes
4813
4814    def select_plans_preferred_mode(self, fraction=0.1, **kwargs):
4815        """
4816        Selects current plant to satisfy best the preferred mode.
4817        """
4818
4819        strategies = self.get_strategies()
4820        ids_strat = strategies.get_ids()
4821        n_strat = len(ids_strat)
4822        ids_pers_all = self.get_ids()
4823        ids_pers = ids_pers_all[np.random.random(len(ids_pers_all)) > (1.0-fraction)]
4824        n_pers = len(ids_pers)
4825        preevals = -1*np.ones((np.max(ids_pers)+1, np.max(ids_strat)+1), dtype=np.int32)
4826        for ind, id_strategy, strategy in zip(range(n_strat), ids_strat, strategies.strategies[ids_strat]):
4827            preevals[ids_pers, id_strategy] = strategy.preevaluate(ids_pers)
4828
4829        preferred = 2
4830        plans = self.get_plans()
4831        self.ids_plan.reset()
4832        for id_pers, ids_plan in zip(ids_pers, self.lists_ids_plan[ids_pers]):
4833            if len(ids_plan) > 0:
4834                # print '  id_pers,ids_plan',id_pers,ids_plan
4835                # print '  ids_strat, preeval',plans.ids_strategy[ids_plan],preevals[id_pers,plans.ids_strategy[ids_plan]]
4836                inds_sel = preevals[id_pers, plans.ids_strategy[ids_plan]] == preferred
4837                # print '  inds_sel',inds_sel,np.flatnonzero(inds_sel),inds_sel.dtype
4838                if len(inds_sel) > 0:
4839                    #ids_plan_sel = np.array(ids_plan)[inds_sel]
4840                    # print '    ids_plan_sel',ids_plan_sel
4841                    # at least one plan contains preferred mode
4842                    self.ids_plan[id_pers] = np.array(ids_plan)[inds_sel][0]  # whu [1]?
4843                # else:
4844                #    assumption: a plan for the preferred mode always exists
4845                #    # no preferred mode found try to satisfy best possible
4846                #    #ids_plan[preevals[id_pers,plans.ids_strategy[ids_plan]] == preferred]
4847                #    self.ids_plan[id_pers] = -1
4848        return True
4849
4850    def select_plans_min_time_est(self, fraction=1.0, timedev=-1.0, c_probit=-1.0, **kwargs):
4851        """
4852        Select plan with minimum estimated travel time as current plant.
4853        """
4854        ids_pers_all = self.get_ids()
4855        ids_pers = ids_pers_all[np.random.random(len(ids_pers_all)) > (1.0-fraction)]
4856        times_est = self.get_plans().times_est
4857        # self.ids_plan.reset()
4858        for id_pers, ids_plan_all in zip(ids_pers, self.lists_ids_plan[ids_pers]):
4859            ids_plan = np.array(ids_plan_all, dtype=np.int32)[times_est[ids_plan_all] > 0.1]
4860            if len(ids_plan) > 0:
4861                # print '  id_pers,ids_plan',id_pers,ids_plan
4862                if timedev > 0.1:
4863                    times_rand = np.random.normal(0.0, timedev, len(ids_plan))
4864                elif c_probit > 0:
4865                    times_rand = np.zeros(len(ids_plan), dtype=np.float32)
4866                    for i, t in zip(xrange(len(ids_plan)), times_est[ids_plan]):
4867                        times_rand[i] = np.random.normal(0.0, c_probit * t, 1)
4868
4869                else:
4870                    times_rand = np.zeros(len(ids_plan), dtype=np.float32)
4871                self.ids_plan[id_pers] = np.array(ids_plan)[np.argmin(times_est[ids_plan]+times_rand)]
4872        return True
4873
4874    def select_plans_random(self, fraction=0.1,  **kwargs):
4875        """
4876        A fraction of the population changes a plan.
4877        The new plans are chosen randomly.
4878        """
4879
4880        ids_pers_all = self.get_ids()
4881        print 'select_plans_random', len(ids_pers_all), fraction
4882        times_est = self.get_plans().times_est
4883        # self.ids_plan.reset()
4884        # ids_mode[random_choice(n,shares/np.sum(shares))]
4885
4886        ids_pers = ids_pers_all[np.random.random(len(ids_pers_all)) > (1.0-fraction)]
4887        print '  ids_pers', ids_pers
4888        for id_pers, ids_plan in zip(ids_pers, self.lists_ids_plan[ids_pers]):
4889            if len(ids_plan) > 0:
4890                # print '  id_pers,ids_plan',id_pers,ids_plan
4891                self.ids_plan[id_pers] = ids_plan[np.random.randint(len(ids_plan))]
4892        return True
4893
4894    def select_plans_min_time_exec(self, fraction=0.1, timedev=-1, c_probit=-1, **kwargs):
4895        """
4896        Select plan with minimum executed travel time as current plant.
4897        """
4898        ids_pers_all = self.get_ids()
4899        # print 'select_plans_random',len(ids_pers_all),fraction
4900        ids_pers = ids_pers_all[np.random.random(len(ids_pers_all)) > (1.0-fraction)]
4901        times_exec = self.get_plans().times_exec
4902        # self.ids_plan.reset()
4903        for id_pers, ids_plan_all in zip(ids_pers, self.lists_ids_plan[ids_pers]):
4904            # print '    ids_plan_all',ids_plan_all,type(ids_plan_all)
4905            ids_plan = np.array(ids_plan_all, dtype=np.int32)[times_exec[ids_plan_all] > 0.1]
4906            if len(ids_plan) > 0:
4907                # print '  id_pers,ids_plan',id_pers,ids_plan
4908                if timedev > 0.1:
4909                    times_rand = np.random.normal(0.0, timedev, len(ids_plan))
4910                elif c_probit > 0:
4911                    times_rand = np.zeros(len(ids_plan), dtype=np.float32)
4912                    for i, t in zip(xrange(len(ids_plan)), times_exec[ids_plan]):
4913                        times_rand[i] = np.random.normal(0.0, c_probit * t, 1)
4914
4915                else:
4916                    times_rand = np.zeros(len(ids_plan), dtype=np.float32)
4917
4918                self.ids_plan[id_pers] = np.array(ids_plan)[np.argmin(times_exec[ids_plan]+times_rand)]
4919        return True
4920
4921    def select_plans_min_time_exec_est(self, fraction=0.1, timedev=-1, c_probit=-1, **kwargs):
4922        """
4923        Select plan with minimum executed or estimated (if executed doesn't exist) travel time as current plant.
4924        """
4925        n_analyzed_persons = 0
4926        ids_pers_all = self.get_ids()
4927        ids_pers = ids_pers_all[np.random.random(len(ids_pers_all)) > (1.0-fraction)]
4928        times_exec = self.get_plans().times_exec
4929        times_est = self.get_plans().times_est
4930        ids_plans = self.get_plans().get_ids()
4931        for id_pers, ids_plan_all in zip(ids_pers, self.lists_ids_plan[ids_pers]):
4932            ids_plan_est = np.array(ids_plan_all, dtype=np.int32)[times_est[ids_plan_all] > 0.1]
4933            ids_plan_exec = np.array(ids_plan_all, dtype=np.int32)[times_exec[ids_plan_all] > 0.1]
4934            if len(ids_plan_est) > 0:
4935                if len(ids_plan_est) == len(ids_plan_exec):
4936                    ids_plan_est = []
4937                else:
4938                    c = np.zeros(len(ids_plan_est))
4939                    for x in range(len(ids_plan_est)):
4940                        for y in range(len(ids_plan_exec)):
4941                            if ids_plan_est[x] == ids_plan_exec[y]:
4942                                c[x] = 1
4943                    d = np.delete(ids_plan_est, np.flatnonzero(c))
4944                    ids_plan_est = d
4945
4946                n_analyzed_persons += 1
4947
4948                if timedev > 0.1:
4949                    if len(ids_plan_est) > 0:
4950                        times_rand_est = np.random.normal(0.0, timedev, len(ids_plan_est))
4951                    if len(ids_plan_exec) > 0:
4952                        times_rand_exec = np.random.normal(0.0, timedev, len(ids_plan_exec))
4953
4954                elif c_probit > 0:
4955                    if len(ids_plan_est) > 0:
4956                        times_rand_est = np.zeros(len(ids_plan_est), dtype=np.float32)
4957                        for i, t in zip(xrange(len(ids_plan_est)), times_est[ids_plan_est]):
4958                            times_rand_est[i] = np.random.normal(0.0, c_probit * t, 1)
4959                    if len(ids_plan_exec) > 0:
4960                        times_rand_exec = np.zeros(len(ids_plan_exec), dtype=np.float32)
4961                        for i, t in zip(xrange(len(ids_plan_exec)), times_exec[ids_plan_exec]):
4962                            times_rand_exec[i] = np.random.normal(0.0, c_probit * t, 1)
4963
4964                else:
4965                    if len(ids_plan_exec) > 0:
4966                        times_rand_exec = np.zeros(len(ids_plan_exec), dtype=np.float32)
4967                    if len(ids_plan_est) > 0:
4968                        times_rand_est = np.zeros(len(ids_plan_est), dtype=np.float32)
4969
4970                if len(ids_plan_exec) > 0 and len(ids_plan_est) > 0:
4971                    if min(times_exec[ids_plan_exec]+times_rand_exec) < min(times_est[ids_plan_est]+times_rand_est):
4972                        self.ids_plan[id_pers] = np.array(ids_plan_exec)[np.argmin(
4973                            times_exec[ids_plan_exec]+times_rand_exec)]
4974                    else:
4975                        self.ids_plan[id_pers] = np.array(
4976                            ids_plan_est)[np.argmin(times_est[ids_plan_est]+times_rand_est)]
4977                elif len(ids_plan_exec) == 0:
4978                    self.ids_plan[id_pers] = np.array(ids_plan_est)[np.argmin(times_est[ids_plan_est]+times_rand_est)]
4979
4980                else:
4981
4982                    self.ids_plan[id_pers] = np.array(ids_plan_exec)[np.argmin(
4983                        times_exec[ids_plan_exec]+times_rand_exec)]
4984
4985        print 'were analyzed  %d persons' % (n_analyzed_persons)
4986        return True
4987
4988    def select_plans_next(self, fraction=0.1, **kwargs):
4989        """
4990        Select next plan in the plan list as current plant.
4991        """
4992        # print 'select_plans_next'
4993        ids_pers_all = self.get_ids()
4994        ids_pers = ids_pers_all[np.random.random(len(ids_pers_all)) > (1.0-fraction)]
4995        for id_pers, id_plan_current, ids_plan in zip(ids_pers, self.ids_plan[ids_pers], self.lists_ids_plan[ids_pers]):
4996            n_plan = len(ids_plan)
4997            if n_plan > 0:
4998                # print '  id_pers,id_plan_current',id_pers,id_plan_current,ids_plan,id_plan_current != -1
4999                if id_plan_current != -1:
5000                    ind = ids_plan.index(id_plan_current)
5001                    # print '    ind',ind,ind +1 < n_plan
5002                    if ind + 1 < n_plan:
5003                        ind += 1
5004                    else:
5005                        ind = 0
5006                else:
5007                    ind = 0
5008
5009                # print '    ind,n_plan',ind,n_plan,'ids_plan[ind]', ids_plan[ind]
5010                self.ids_plan[id_pers] = ids_plan[ind]
5011        # print '  finally: ids_plan=',self.ids_plan.get_value()
5012        return True
5013
5014    def prepare_sim(self, process):
5015        return []  # [(steptime1,func1),(steptime2,func2),...]
5016
5017    def get_trips(self):
5018        # returns trip object, method common to all demand objects
5019        return self.get_iautos()
5020
5021    def get_writexmlinfo(self, is_route=False):
5022        """
5023        Returns three array where the first array is the
5024        begin time of the first vehicle and the second array is the
5025        write function to be called for the respectice vehicle and
5026        the third array contains the vehicle ids
5027
5028        Method used to sort trips when exporting to route or trip xml file
5029        """
5030        print 'Virtualpop.get_writexmlinfo'
5031        plans = self.get_plans()
5032
5033        ids_pers = self.select_ids(self.ids_plan.get_value() >= 0)
5034        n_pers = len(ids_pers)
5035        ids_plans = self.ids_plan[ids_pers]
5036
5037        # get vehicle trip info
5038        times_depart_bike, writefuncs_bike, ids_rides_bike = plans.get_stagetable(
5039            'bikerides').get_writexmlinfo(ids_plans, is_route)
5040        times_depart_auto, writefuncs_auto, ids_rides_auto = plans.get_stagetable(
5041            'autorides').get_writexmlinfo(ids_plans, is_route)
5042
5043        #self.add_stagetable('walks', WalkStages)
5044        #self.add_stagetable('autorides', AutorideStages)
5045        #self.add_stagetable('bikerides', BikerideStages)
5046        #self.add_stagetable('transits', TransitStages)
5047        #self.add_stagetable('activities', ActivityStages)
5048
5049        #rides = plans.get_stagetable('autorides')
5050
5051        # do persons
5052
5053        times_depart_pers = plans.times_begin[ids_plans]
5054        writefuncs_pers = np.zeros(n_pers, dtype=np.object)
5055        writefuncs_pers[:] = self.write_person_xml
5056
5057        # assemble vectors
5058        print '  times_depart_pers.shape', times_depart_pers.shape
5059        print '  times_depart_bike.shape', times_depart_bike.shape
5060        print '  times_depart_auto.shape', times_depart_auto.shape
5061        times_depart = np.concatenate((times_depart_pers,
5062                                       times_depart_auto,
5063                                       times_depart_bike,
5064                                       ))
5065
5066        writefuncs = np.concatenate((writefuncs_pers,
5067                                     writefuncs_auto,
5068                                     writefuncs_bike,
5069                                     ))
5070
5071        ids = np.concatenate((ids_pers,
5072                              ids_rides_auto,
5073                              ids_rides_bike,
5074                              ))
5075
5076        return times_depart, writefuncs, ids
5077
5078    def write_person_xml(self, fd, id_pers, time_begin, indent=2):
5079
5080        stages = self.get_plans().get_stages(self.ids_plan[id_pers])
5081
5082        fd.write(xm.start('person', indent=indent+2))
5083        fd.write(xm.num('id', self.get_id_sumo_from_id(id_pers)))
5084        # fd.write(xm.num('depart',self.times_start[id_pers]))
5085        fd.write(xm.num('depart', time_begin))
5086        fd.write(xm.num('type', self.parent.vtypes.ids_sumo[self.ids_vtype[id_pers]]))
5087
5088        activity_init, id_stage_init = stages[0]
5089        id_edge_init, pos_init = activity_init.get_edges_positions(id_stage_init)
5090
5091        # self.ids_edge_depart.write_xml(fd,id_trip)
5092        # self.positions_depart.write_xml(fd,id_trip)
5093        fd.write(xm.num('from', self._edges.ids_sumo[id_edge_init]))
5094        fd.write(xm.num('departPos', pos_init))
5095
5096        fd.write(xm.stop())
5097
5098        # write stages of this person.
5099        # Attention!! first and last stage, which are activities,
5100        # will NOT be exportes , therefore [1:-1]
5101        for stage, id_stage in stages[1:-1]:
5102            stage.to_xml(id_stage, fd, indent+4)
5103
5104        fd.write(xm.end('person', indent=indent+2))
5105
5106    def config_results(self, results):
5107
5108        results.add_resultobj(res.Personresults('virtualpersonresults', results,
5109                                                self,
5110                                                self.get_net().edges,
5111                                                name='Virtual person results',
5112                                                info='Table with simulation results for person of the virtual population. The results refer to all trips made by the person during the entire simulation period.',
5113                                                ), groupnames=['Trip results'])
5114
5115        results.add_resultobj(res.Vehicleresults('iautotripresults', results,
5116                                                 self.get_iautos(),
5117                                                 self.get_net().edges,
5118                                                 name='Auto trip results',
5119                                                 info='Table with trip results mad with individual autos. The results refer to all trips made by a specific vehicle during the entire simulation period.',
5120                                                 ), groupnames=['Trip results'])
5121
5122        results.add_resultobj(res.Vehicleresults('ibiketripresults', results,
5123                                                 self.get_ibikes(),
5124                                                 self.get_net().edges,
5125                                                 name='Bike trip results',
5126                                                 info='Table with trip results mad with individual bikes. The results refer to all trips made by a specific vehicle during the entire simulation period.',
5127                                                 ), groupnames=['Trip results'])
5128
5129    # def process_results(self, results, process = None):
5130    #    print 'process_results'
5131    #    ## copy total travel into plan execution time
5132    #    personresults = results.virtualpersonresults
5133    #    self.update_plans(personresults)
5134
5135    def update_results(self, personresults):
5136        """
5137        Updates plans with results from previous
5138        simulation run, and updates plan choice
5139        """
5140
5141        ids_res = personresults.get_ids()
5142        print 'update_results', len(ids_res)
5143        ids_person = personresults.ids_person[ids_res]
5144        ids_plan = self.ids_plan[ids_person]
5145        self.get_plans().times_exec[ids_plan] = personresults.times_travel_total[ids_res]
5146        # change mobility plan based on updated travel times
5147        pass
5148
5149
5150class PopGenerator(Process):
5151    def __init__(self, ident='virtualpopgenerator', virtualpop=None,  logger=None, **kwargs):
5152        print 'PopFromOdfGenerator.__init__ ', ident, virtualpop
5153
5154        # TODO: let this be independent, link to it or child??
5155        #
5156        scenario = virtualpop.get_scenario()
5157        self._init_common(ident,
5158                          parent=virtualpop,
5159                          name='Population generator',
5160                          logger=logger,
5161                          info='Create virtual population from basic statistical data.',
5162                          )
5163
5164        attrsman = self.set_attrsman(cm.Attrsman(self))
5165
5166        # make for each possible pattern a field for prob
5167        activitytypes = self.parent.get_scenario().demand.activitytypes
5168
5169        self.n_person = attrsman.add(cm.AttrConf('n_person', kwargs.get('n_person', 1000),
5170                                                 groupnames=['options'],
5171                                                 perm='rw',
5172                                                 name='Number of person',
5173                                                 info='Number of adult persons.',
5174                                                 ))
5175
5176        self.ids_acttype_default = activitytypes.get_ids_from_formatted('home,work')
5177        # self.ids_acttype = attrsman.add(cm.AttrConf( 'ids_acttype',kwargs.get('id_acttype',activitytypes.get_id_from_formatted('home')),
5178        #                    groupnames = ['options'],
5179        #                    choices = activitytypes.names.get_indexmap(),
5180        #                    perm='rw',
5181        #                    name = 'Activity type',
5182        #                    info = 'Initial activity type.',
5183        #                    ))
5184
5185        self.ttb_mean = attrsman.add(cm.AttrConf('ttb_mean', kwargs.get('ttb_mean', 55*60),
5186                                                 groupnames=['options'],
5187                                                 perm='rw',
5188                                                 name='Avg. of 24h travel time budget',
5189                                                 unit='s',
5190                                                 info="""Average travel time budget for one day.
5191                            This time excludes time for activities.
5192                             """,
5193                                                 ))
5194        self.ttb_dev = attrsman.add(cm.AttrConf('ttb_dev', kwargs.get('ttb_dev', 10*60),
5195                                                groupnames=['options'],
5196                                                perm='rw',
5197                                                name='Std. of 24h travel time budget',
5198                                                unit='s',
5199                                                info="""Standard deviation of travel time budget for one day.
5200                            """,
5201                                                ))
5202
5203        mode_to_id = self.parent.get_scenario().net.modes.get_id_mode
5204        self.share_pedestrian = attrsman.add(cm.AttrConf('share_pedestrian', kwargs.get('share_pedestrian', 0.1),
5205                                                         groupnames=['options', 'modal split'],
5206                                                         perm='rw',
5207                                                         id_mode=mode_to_id('pedestrian'),
5208                                                         name='Pedestrian share',
5209                                                         info="""Share of pedestrians.""",
5210                                                         ))
5211
5212        self.share_autouser = attrsman.add(cm.AttrConf('share_autouser', kwargs.get('share_autouser', 0.5),
5213                                                       groupnames=['options', 'modal split'],
5214                                                       perm='rw',
5215                                                       id_mode=mode_to_id('passenger'),
5216                                                       name='Auto user share',
5217                                                       info="""Share of auto users.""",
5218                                                       ))
5219
5220        self.share_motorcycleuser = attrsman.add(cm.AttrConf('share_motorcycleuser', kwargs.get('share_motorcycleuser', 0.1),
5221                                                             groupnames=['options', 'modal split'],
5222                                                             perm='rw',
5223                                                             id_mode=mode_to_id('motorcycle'),
5224                                                             name='Motorcycle user share',
5225                                                             info="""Share of Motorcycle users.""",
5226                                                             ))
5227
5228        self.share_bikeuser = attrsman.add(cm.AttrConf('share_bikeuser', kwargs.get('share_bikeuser', 0.1),
5229                                                       groupnames=['options', 'modal split'],
5230                                                       perm='rw',
5231                                                       id_mode=mode_to_id('bicycle'),
5232                                                       name='Bike user share',
5233                                                       info="""Share of bike users.""",
5234                                                       ))
5235
5236        self.share_ptuser = attrsman.add(cm.AttrConf('share_ptuser', kwargs.get('share_ptuser', 0.2),
5237                                                     groupnames=['options', 'modal split'],
5238                                                     id_mode=mode_to_id('bus'),
5239                                                     perm='rw',
5240                                                     name='PT share',
5241                                                     info="""Share of public transport user.""",
5242                                                     ))
5243
5244        #self.modeshares = attrsman.add( cm.ObjConf(ModeShares('modeshares',self,scenario.net.modes),groupnames = ['options']) )
5245
5246    def do(self):
5247        print 'PopGenerator.do'
5248        # links
5249
5250        virtualpop = self.parent
5251        virtualpop.clear_population()
5252        logger = self.get_logger()
5253        #logger.w('Update Landuse...')
5254        scenario = virtualpop.get_scenario()
5255        activitytypes = scenario.demand.activitytypes
5256        facilities = scenario.landuse.facilities
5257        edges = scenario.net.edges
5258
5259        ids_fac = facilities.get_ids()
5260        map_id_edge_to_ids_fac = {}
5261        for id_fac, id_edge in zip(ids_fac, facilities.ids_roadedge_closest[ids_fac]):
5262            if map_id_edge_to_ids_fac.has_key(id_edge):
5263                map_id_edge_to_ids_fac[id_edge].append(id_fac)
5264            else:
5265                map_id_edge_to_ids_fac[id_edge] = [id_fac, ]
5266
5267        n_pers = self.n_person
5268        unitvec_int = np.ones(n_pers, dtype=np.int32)
5269
5270        ids_person = virtualpop.make_multiple(n_pers)
5271        virtualpop.traveltimebudgets[ids_person] = self.get_ttb(ids_person)
5272
5273        virtualpop.ids_mode_preferred[ids_person] = self.get_modes_random(n_pers)
5274
5275        # here we could preselect correct landuse based on
5276        # percentage of workers, students, employees
5277        prob_fac_to = facilities.capacities[ids_fac].astype(np.float32)
5278        prob_fac_to /= np.sum(prob_fac_to)
5279        # print '  np.sum(prob_fac_to)',np.sum(prob_fac_to)
5280        ids_fac_to = ids_fac[random_choice(n_pers, prob_fac_to)]
5281
5282        # determine id_fac_from by backward routing from id_fac_to
5283        ids_edge_to = facilities.ids_roadedge_closest[ids_fac_to]
5284
5285        # pre calculate backward star and mode dependent link travel times
5286        bstar = edges.get_bstar()
5287        edgetimes = {}
5288        ids_mode = self.get_ids_mode()
5289        # idea: do also consider gradient of house prices
5290        for id_mode, speed_max in zip(ids_mode, scenario.net.modes.speeds_max[ids_mode]):
5291            edgetimes[id_mode] = edges.get_times(id_mode=id_mode,
5292                                                 speed_max=speed_max,
5293                                                 is_check_lanes=True
5294                                                 )
5295        # determine home facilities by backwards tracking from work facility
5296        ids_fac_from = np.ones(n_pers, dtype=np.int32)
5297        i = 0
5298        for id_person, id_edge_to, id_mode, ttb\
5299                in zip(ids_person,
5300                       ids_edge_to,
5301                       virtualpop.ids_mode_preferred[ids_person],
5302                       virtualpop.traveltimebudgets[ids_person],
5303                       ):
5304
5305            # print '  Backsearch',id_person,'id_edge_to',id_edge_to,edges.ids_sumo[id_edge_to],'ttb[s]',0.5*ttb
5306            ids_edge_from, costs, btree = routing.edgedijkstra_backwards(id_edge_to,
5307                                                                         0.5*ttb,  # to be specified better
5308                                                                         weights=edgetimes[id_mode],
5309                                                                         bstar=bstar,
5310                                                                         )
5311            if len(ids_edge_from) == 0:
5312                # routing failed to deliver edges of origins
5313                # put work and home on same edge
5314                ids_edge_from = [id_edge_to, ]
5315
5316            # look at all edges of origin and pick most likely facility
5317            ids_fac_lim = []
5318            for id_edge_from in ids_edge_from:
5319
5320                #id_from_check = id_edge_from
5321                # print '  check from',id_from_check,'back to',id_edge_to,'time =%.2fs'%costs[id_from_check]
5322                # while id_from_check != id_edge_to:
5323                #    id_from_check = btree[id_from_check]
5324                #    #print '  id_edge = ',id_from_check
5325                # print '  success = ',id_from_check==id_edge_to
5326                if map_id_edge_to_ids_fac.has_key(id_edge_from):
5327                    ids_fac_lim += map_id_edge_to_ids_fac[id_edge_from]
5328
5329            if len(ids_fac_lim) == 0:
5330                # no facilities at all destinations found
5331                # go edges backawards and search there
5332                # this will reduce travel time
5333                for id_edge_from in ids_edge_from:
5334                    # verify if id_edge_from has facilities.
5335                    while not map_id_edge_to_ids_fac.has_key(id_edge_from):
5336                        # print '  no facility, go backward'
5337                        id_edge_from = btree[id_edge_from]
5338
5339            ids_fac_lim = np.array(ids_fac_lim, dtype=np.int32)
5340
5341            prob_fac_from = facilities.capacities[ids_fac_lim].astype(np.float32)
5342            prob_fac_from /= np.sum(prob_fac_from)
5343            # print '  np.sum(prob_fac_to)',np.sum(prob_fac_to)
5344            ids_fac_from[i] = ids_fac[random_choice(1, prob_fac_to)]
5345            i += 1
5346
5347        # idea: adjust wake-up time with employment type
5348        activities = virtualpop.get_activities()
5349        ids_activity_from = activities.add_rows(
5350            n=n_pers,
5351            ids_activitytype=self.ids_acttype_default[0] * unitvec_int,
5352            ids_facility=ids_fac_from,
5353            # use default
5354            #hours_begin_earliest = None,
5355            #hours_begin_latest = None,
5356            #durations_min = None,
5357            #durations_max = None,
5358        )
5359
5360        ids_activity_to = activities.add_rows(
5361            n=n_pers,
5362            ids_activitytype=self.ids_acttype_default[1] * unitvec_int,
5363            ids_facility=ids_fac_to,
5364            # use default
5365            #hours_begin_earliest = None,
5366            #hours_begin_latest = None,
5367            #durations_min = None,
5368            #durations_max = None,
5369        )
5370
5371        for id_person, id_activity_from, ids_activity_to in zip(ids_person, ids_activity_from, ids_activity_to):
5372            virtualpop.activitypatterns[id_person] = [id_activity_from, ids_activity_to, ]
5373
5374        return True
5375
5376    def get_ids_mode(self):
5377        modesplitconfigs = self.get_attrsman().get_group('modal split')
5378        ids_mode = np.zeros(len(modesplitconfigs), dtype=np.int32)
5379        i = 0
5380        for modeconfig in modesplitconfigs:
5381            ids_mode[i] = modeconfig.id_mode
5382            i += 1
5383        return ids_mode
5384
5385    def get_modes_random(self, n):
5386        """
5387        Return a vector with mode IDs of length n.
5388        """
5389        # print 'get_modes_random',n
5390        modesplitconfigs = self.get_attrsman().get_group('modal split')
5391        ids_mode = np.zeros(len(modesplitconfigs), dtype=np.int32)
5392        shares = np.zeros(len(modesplitconfigs), dtype=np.float32)
5393        i = 0
5394        for modeconfig in modesplitconfigs:
5395            ids_mode[i] = modeconfig.id_mode
5396            shares[i] = modeconfig.get_value()
5397            i += 1
5398        # print '  ids_mode',ids_mode
5399        # print '  shares',shares
5400        return ids_mode[random_choice(n, shares/np.sum(shares))]
5401
5402    def get_ttb(self, ids_pers):
5403        n_pers = len(ids_pers)
5404
5405        # Truncated Normal dist with scipy
5406        # load libraries
5407        #import scipy.stats as stats
5408        # lower, upper, mu, and sigma are four parameters
5409        #lower, upper = 0.5, 1
5410        #mu, sigma = 0.6, 0.1
5411        # instantiate an object X using the above four parameters,
5412        #X = stats.truncnorm((lower - mu) / sigma, (upper - mu) / sigma, loc=mu, scale=sigma)
5413        # generate 1000 sample data
5414        #samples = X.rvs(1000)
5415
5416        return np.random.normal(self.ttb_mean, self.ttb_dev, n_pers).clip(0, 2*3600)
5417
5418
5419class PopFromOdfGenerator(Process):
5420    def __init__(self, ident, virtualpop,  logger=None, **kwargs):
5421        print 'PopFromOdfGenerator.__init__'
5422
5423        # TODO: let this be independent, link to it or child??
5424
5425        self._init_common(ident,
5426                          parent=virtualpop,
5427                          name='Pop from OD-flow generator',
5428                          logger=logger,
5429                          info='Create virtual population from origin-to-destination zone flows by disaggregation.',
5430                          )
5431
5432        attrsman = self.set_attrsman(cm.Attrsman(self))
5433
5434        # make for each possible pattern a field for prob
5435        activitytypes = self.parent.get_scenario().demand.activitytypes
5436
5437        self.hour_offset = attrsman.add(cm.AttrConf('hour_offset', kwargs.get('hour_offset', 8.0),
5438                                                    groupnames=['options'],
5439                                                    perm='rw',
5440                                                    name='Offset hours',
5441                                                    unit='h',
5442                                                    info='Hour when simulation starts. This is the hour (of the day) when simulation time shows zero seconds.',
5443                                                    ))
5444
5445        self.hour_tripbudget = attrsman.add(cm.AttrConf('hour_tripbudget', kwargs.get('hour_tripbudget', 0.5),
5446                                                        groupnames=['options'],
5447                                                        perm='rw',
5448                                                        name='Triptime budget',
5449                                                        unit='h',
5450                                                        info="""Time budget for this trip. This time is used
5451                             to initially estimate the time in hours between
5452                             the activity at origin and the activity
5453                             at destination.
5454                             """,
5455                                                        ))
5456
5457        self.scale = attrsman.add(cm.AttrConf('scale', kwargs.get('scale', 1.0),
5458                                              groupnames=['options'],
5459                                              perm='rw',
5460                                              name='Scale',
5461                                              info='Global scale factor. Scales the number of all OD trips.',
5462                                              ))
5463
5464        self.is_use_landusetypes = attrsman.add(cm.AttrConf('is_use_landusetypes', kwargs.get('is_use_landusetypes', False),
5465                                                            groupnames=['options'],
5466                                                            perm='rw',
5467                                                            name='use landuse types',
5468                                                            info="""If True, use the landuse type of
5469                            facilities when assigning the origin and destination facility.
5470                            The landuse type is selected according to the activity type.
5471                            Use this option only if landuse types have been correctly defined for
5472                            all facilities.
5473                            """,
5474                                                            ))
5475
5476        self.is_update_landuse = attrsman.add(cm.AttrConf('is_update_landuse', kwargs.get('is_update_landuse', True),
5477                                                          groupnames=['options'],
5478                                                          perm='rw',
5479                                                          name='update Landuse',
5480                                                          info="""If True, update land use database (zones, facilities, parking) before generating the population. Updating means identifying edges and facilities within zones.
5481                            """,
5482                                                          ))
5483
5484    def do(self):
5485        print 'PopFromOdfGenerator.do'
5486        # links
5487
5488        virtualpop = self.parent
5489        logger = self.get_logger()
5490        if self.is_update_landuse:
5491            logger.w('Update Landuse...')
5492            scenario = virtualpop.get_scenario()
5493            scenario.landuse.zones.refresh_zoneedges()
5494            scenario.landuse.facilities.identify_taz()
5495            scenario.landuse.facilities.identify_closest_edge()
5496            scenario.landuse.facilities.update()
5497
5498        logger.w('Create population...')
5499        virtualpop.create_pop_from_odflows(logger=logger, **self.get_kwoptions())
5500        #activitytypes = virtualpop.activitytypes
5501        return True
5502
5503
5504class Planner(Process):
5505    def __init__(self, ident='planner', virtualpop=None, strategy='all', logger=None, **kwargs):
5506        print 'Planner.__init__'
5507
5508        # TODO: let this be independent, link to it or child??
5509
5510        self._init_common(ident,
5511                          parent=virtualpop,
5512                          name='Planner',
5513                          logger=logger,
5514                          info='Generates mobility plan for population for a specific mobility strategy. Plans are only generated for persons for whome the strategy is applicable.',
5515                          )
5516
5517        attrsman = self.set_attrsman(cm.Attrsman(self))
5518
5519        # make for each possible pattern a field for prob
5520        strategies = virtualpop.get_strategies()
5521        strategychoices = {'all': -1}
5522        strategychoices.update(strategies.names.get_indexmap())
5523        self.id_strategy = attrsman.add(cm.AttrConf('id_strategy', strategychoices[strategy],
5524                                                    groupnames=['options'],
5525                                                    choices=strategychoices,
5526                                                    perm='rw',
5527                                                    name='Strategy',
5528                                                    info='Strategy to be used to create mobility plane. In case of all strategies, the planner generates all applicable plans.',
5529                                                    ))
5530
5531        evalcrits = {'apply to all persons if feasible': 0,
5532                     'apply only if preferred mode is used': 1,
5533                     'apply only if exclusively preferred mode is used': 2,
5534                     }
5535        self.evalcrit = attrsman.add(cm.AttrConf('evalcrit', kwargs.get('evalcrit', evalcrits['apply to all persons if feasible']),
5536                                                 groupnames=['options'],
5537                                                 choices=evalcrits,
5538                                                 perm='rw',
5539                                                 name='Application criteria',
5540                                                 info=""" Value that determines for which persons the plans will be generated.
5541                                        Apply to all persons if feasible:0
5542                                        Apply only if preferred mode is used:1
5543                                        Apply only if exclusively preferred mode is used:2
5544                            """,
5545                                                 ))
5546
5547    def do(self):
5548        print 'Planner.do'
5549        # links
5550
5551        virtualpop = self.parent
5552        logger = self.get_logger()
5553        #logger.w('Check applicability')
5554        #strategies = virtualpop.strategies.get_value()
5555
5556        if self.id_strategy != -1:
5557            virtualpop.plan_with_strategy(self.id_strategy, evalcrit=self.evalcrit, logger=logger)
5558
5559        else:  # plan with all strategies
5560            for id_strategy in virtualpop.get_strategies().get_ids():
5561                virtualpop.plan_with_strategy(id_strategy, evalcrit=self.evalcrit, logger=logger)
5562
5563        return True
5564
5565
5566class PlanSelector(Process):
5567    def __init__(self, ident='planselector', virtualpop=None, logger=None, **kwargs):
5568        print 'PlanSelector.__init__'
5569
5570        # TODO: let this be independent, link to it or child??
5571
5572        self._init_common(ident,
5573                          parent=virtualpop,
5574                          name='Plan Selector',
5575                          logger=logger,
5576                          info='Selects the plan for each person which will be executed during the next simulation run according to a defined selection method.',
5577                          )
5578
5579        attrsman = self.set_attrsman(cm.Attrsman(self))
5580
5581        # make for each possible pattern a field for prob
5582        strategies = virtualpop.get_strategies()
5583        # strategychoices.update(strategies.names.get_indexmap())
5584
5585        methods = {'plan with shortest estim. time': virtualpop.select_plans_min_time_est,
5586                   'plan with shortest exec. time': virtualpop.select_plans_min_time_exec,
5587                   'plan with preferred mode': virtualpop.select_plans_preferred_mode,
5588                   'next plan in list': virtualpop.select_plans_next,
5589                   'random plan': virtualpop.select_plans_random,
5590                   'plan with shortest exec. time or est. time': virtualpop.select_plans_min_time_exec_est
5591                   }
5592
5593        self.method = attrsman.add(cm.AttrConf('method', methods[kwargs.get('methodname', 'plan with shortest estim. time')],
5594                                               groupnames=['options'],
5595                                               choices=methods,
5596                                               perm='rw',
5597                                               name='Selection method',
5598                                               info='Selection method used to select current plans.',
5599                                               ))
5600
5601        self.fraction = attrsman.add(cm.AttrConf('fraction', kwargs.get('fraction', 1.0),
5602                                                 groupnames=['options'],
5603                                                 perm='rw',
5604                                                 name='Change fraction',
5605                                                 info="""Fraction of persons that are randomly chosen to change plans according to the defined method.
5606                            A value of 1.0 mens that the plans of oll persons will be changed.""",
5607                                                 ))
5608
5609        self.timedev = attrsman.add(cm.AttrConf('timedev', kwargs.get('timedev', 0.0),
5610                                                groupnames=['options'],
5611                                                perm='rw',
5612                                                name='Time deviation',
5613                                                info='Time deviation of random time component of estimated or effective time. If zero, no random time is added.',
5614                                                ))
5615
5616        self.c_probit = attrsman.add(cm.AttrConf('c_probit', kwargs.get('c_probit', 0.0),
5617                                                 groupnames=['options'],
5618                                                 perm='rw',
5619                                                 name='Probit const',
5620                                                 info="""Probit constant used to determine the deviation of the normal distributed random time component.
5621                                    The deviation is the product of this constant and the travel time. If zero, no random time is added.""",
5622                                                 ))
5623
5624    def do(self):
5625        print 'Planner.do'
5626        # links
5627
5628        #virtualpop = self.parent
5629        logger = self.get_logger()
5630        #logger.w('Check applicability')
5631        return self.method(logger=logger, **self.get_kwoptions())
5632
5633
5634class VehicleProvider(Process):
5635    def __init__(self, ident='vehicleprovider', virtualpop=None,  logger=None, **kwargs):
5636        print 'VehicleProvider.__init__'
5637
5638        # TODO: let this be independent, link to it or child??
5639
5640        self._init_common(ident,
5641                          parent=virtualpop,
5642                          name='Vehicle Provider',
5643                          logger=logger,
5644                          info='Provides individual vehicles to persons according to preferred mode and giveb statistical data.',
5645                          )
5646
5647        attrsman = self.set_attrsman(cm.Attrsman(self))
5648
5649        # make for each possible pattern a field for prob
5650
5651        self.share_autoowner = attrsman.add(cm.AttrConf('share_autoowner', kwargs.get('share_autoowner', 0.8),
5652                                                        groupnames=['options'],
5653                                                        perm='rw',
5654                                                        name='Car auto share',
5655                                                        info="""Share of auto owners. This specifies the share of auto owners and a car will be created for each car owner.
5656                                    Attention if prefeered mode has been already defined: persons who have bicicle as preferred mode get automatically a bike assigned.
5657                                    """,
5658                                                        ))
5659
5660        self.share_motorcycleowner = attrsman.add(cm.AttrConf('share_motorcycleowner', kwargs.get('share_motorcycleowner', 0.3),
5661                                                              groupnames=['options'],
5662                                                              perm='rw',
5663                                                              name='Motorcycle owner share',
5664                                                              info="""Share of Motorcycle owners. This specifies the share of Motorcycle owners and a bike will be created for each Motorcycle owner.
5665                                    Attention if prefeered mode has been already defined: persons who have Motorcycle as preferred mode get automatically a Motorcycle assigned.
5666                                    """,
5667                                                              ))
5668
5669        self.share_bikeowner = attrsman.add(cm.AttrConf('share_bikeowner', kwargs.get('share_bikeowner', 0.5),
5670                                                        groupnames=['options'],
5671                                                        perm='rw',
5672                                                        name='Bike owner share',
5673                                                        info="""Share of bike owners. This specifies the share of bike owners and a bike will be created for each bike owner.
5674                                    Attention if prefeered mode has been already defined: persons who have bicicle as preferred mode get automatically a bike assigned.
5675                                    """,
5676                                                        ))
5677
5678    def do(self):
5679        print 'VehicleProvider.do'
5680        # links
5681
5682        virtualpop = self.parent
5683        logger = self.get_logger()
5684        logger.w('Provide vehicles...')
5685
5686        ids_person = virtualpop.get_ids()
5687        n_person = len(ids_person)
5688        modes = virtualpop.get_scenario().net.modes
5689        id_mode_bike = modes.get_id_mode('bicycle')
5690        id_mode_auto = modes.get_id_mode('passenger')
5691        id_mode_moto = modes.get_id_mode('motorcycle')
5692
5693        iautos = virtualpop.get_iautos()
5694        ibikes = virtualpop.get_ibikes()
5695        imotos = virtualpop.get_imotos()
5696
5697        logger.w('generate individual vehicles for prefered modes')
5698        ids_prefer_auto = virtualpop.select_ids(
5699            (virtualpop.ids_mode_preferred.get_value() == id_mode_auto) & (virtualpop.ids_iauto.get_value() == -1))
5700        ids_iauto = iautos.assign_to_persons(ids_prefer_auto)
5701
5702        n_current = iautos.get_share(is_abs=True)
5703        #n_none = int(self.share_autoowner*n_person)-(n_person-n_current)
5704        n_need = int(self.share_autoowner*n_person)-n_current
5705        if n_need > 0:
5706            ids_pers_miss = np.flatnonzero(virtualpop.ids_iauto.get_value() == -1)
5707            # print '  n_person,n_current,n_target,n_need,len(ids_pers_miss)',n_person,n_current,int(self.share_autoowner*n_person),n_need,len(ids_pers_miss)
5708            ids_pers_assign = np.random.choice(ids_pers_miss, n_need, replace=False)
5709            ids_iauto = iautos.assign_to_persons(ids_pers_assign)
5710
5711        print '  created %d autos, target share=%.2f, share = %.2f' % (
5712            iautos.get_share(is_abs=True), iautos.get_share(), self.share_autoowner)
5713
5714        ids_prefer_bike = virtualpop.select_ids(
5715            (virtualpop.ids_mode_preferred.get_value() == id_mode_bike) & (virtualpop.ids_ibike.get_value() == -1))
5716        ids_ibikes = ibikes.assign_to_persons(ids_prefer_bike)
5717
5718        n_current = ibikes.get_share(is_abs=True)
5719        n_need = int(self.share_bikeowner*n_person)-n_current
5720        if n_need > 0:
5721            ids_pers_miss = np.flatnonzero(virtualpop.ids_ibike.get_value() == -1)
5722            # print '  n_person,n_current,n_target,n_need,len(ids_pers_miss)',n_person,n_current,int(self.share_autoowner*n_person),n_need,len(ids_pers_miss)
5723            ids_pers_assign = np.random.choice(ids_pers_miss, n_need, replace=False)
5724            ids_ibike = ibikes.assign_to_persons(ids_pers_assign)
5725
5726        print '  created %d bikes, target share=%.2f, share = %.2f' % (
5727            ibikes.get_share(is_abs=True), ibikes.get_share(), self.share_bikeowner)
5728
5729        ids_prefer_moto = virtualpop.select_ids(
5730            (virtualpop.ids_mode_preferred.get_value() == id_mode_moto) & (virtualpop.ids_imoto.get_value() == -1))
5731        ids_imoto = imotos.assign_to_persons(ids_prefer_moto)
5732
5733        n_current = imotos.get_share(is_abs=True)
5734        n_need = int(self.share_motorcycleowner*n_person)-n_current
5735        if n_need > 0:
5736            ids_pers_miss = np.flatnonzero(virtualpop.ids_imoto.get_value() == -1)
5737            ids_pers_assign = np.random.choice(ids_pers_miss, n_need, replace=False)
5738            ids_imoto = imotos.assign_to_persons(ids_pers_assign)
5739
5740        print '  created %d moto, target share=%.2f, share = %.2f' % (
5741            imotos.get_share(is_abs=True), imotos.get_share(), self.share_motorcycleowner)
5742        return True
5743
5744        # TODO: generate and assign  additional vehicles
5745        # to satisfy prescribes ownership
5746