Eclipse SUMO - Simulation of Urban MObility
AGWorkAndSchool.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 // activitygen module
5 // Copyright 2010 TUM (Technische Universitaet Muenchen, http://www.tum.de/)
6 // This program and the accompanying materials are made available under the
7 // terms of the Eclipse Public License 2.0 which is available at
8 // https://www.eclipse.org/legal/epl-2.0/
9 // This Source Code may also be made available under the following Secondary
10 // Licenses when the conditions for such availability set forth in the Eclipse
11 // Public License 2.0 are satisfied: GNU General Public License, version 2
12 // or later which is available at
13 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
14 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
15 /****************************************************************************/
23 // Generates trips to work and to school
24 /****************************************************************************/
25 #include <config.h>
26 
27 #include <list>
29 #include <activitygen/city/AGCar.h>
34 #include "AGWorkAndSchool.h"
35 
36 
37 // ===========================================================================
38 // method definitions
39 // ===========================================================================
40 bool
42  //buildDestinations();
43  // generation of the waiting list for the accompaniment
45 
47 
48  if (myHousehold->getCarNbr() < (int)personsDrivingCars.size()) {
49  return false; //to rebuild the household
50  }
51  if (childrenNeedingCarAccompaniment.size() != 0 && myHousehold->getCarNbr() == 0) {
52  return false; //to rebuild the household
53  }
54  if (adultNeedingCarAccompaniment.size() != 0 && myHousehold->getCarNbr() == 0) {
55  return false;
56  }
57 
58  carAllocation();
59 
60  if (personsDrivingCars.empty() && notNeedingDrivers.empty()) {
61  genDone = true;
62  return true; // no trip to generate
63  }
64 
65  if (! carsToTrips()) {
66  return false;
67  }
68 
69  genDone = true;
70  return true;
71 }
72 
73 void
75  std::list<AGChild>::const_iterator itC;
76  for (itC = myHousehold->getChildren().begin(); itC != myHousehold->getChildren().end(); ++itC) {
77  if (itC->haveASchool()) {
78  if (this->availableTranspMeans(myHousehold->getPosition(), itC->getSchoolLocation()) == 0) {
79  //in this case the school is far from home and bus stations too
80  this->childrenNeedingCarAccompaniment.push_back(*itC);
81  }
82  }
83  }
84 }
85 
86 void
88  std::list<AGAdult>::const_iterator itA;
89  for (itA = myHousehold->getAdults().begin(); itA != myHousehold->getAdults().end(); ++itA) {
90  if (itA->isWorking()) {
91  if (this->possibleTranspMean(itA->getWorkPosition().getPosition()) % 2 == 0) {
92  //not too close, to not being able to go by foot
93  if (this->possibleTranspMean(itA->getWorkPosition().getPosition()) > 4) {
94  //too far from home ==> Car or Bus AND Car and bus are possible
95  workingPeoplePossCar.push_back(*itA);
96  } else if (this->possibleTranspMean(itA->getWorkPosition().getPosition()) == 4) {
97  //only the car is possible (and there is one (use of possibleTranspMean))
98  if (myHousehold->getCarNbr() > (int)personsDrivingCars.size()) {
99  personsDrivingCars.push_back(*itA);
100  } else {
101  adultNeedingCarAccompaniment.push_back(*itA);
102  }
103  }
104  }
105  }
106  }
107 
108  // sometimes, people still have choice: when vehicles are available and their car take a bus.
109  std::list<AGAdult>::iterator it;
110  for (it = workingPeoplePossCar.begin(); it != workingPeoplePossCar.end(); ++it) {
111  if (possibleTranspMean(it->getWorkPosition().getPosition()) == 6 && myHousehold->getCarNbr() > (int)personsDrivingCars.size()) {
112  //car or bus (always because of workDestinations' construction) AND at least one car not used
113  if (myHousehold->getAdults().front().decide(this->carPreference)) {
114  personsDrivingCars.push_back(*it);
115  }
116  }
117  }
118 }
119 
120 void
122  // only two adults are possibles: no car, 1 car, 2 cars and more
123  // the only choice case: 1 car / 2 adults needing this car (otherwise no choice problems)
124  if (! personsDrivingCars.empty() && ! adultNeedingCarAccompaniment.empty()) {
125  //in that case there is only one element in each list and only one car.
126  if (adultNeedingCarAccompaniment.front().getWorkPosition().getOpening() >= personsDrivingCars.front().getWorkPosition().getOpening()) {
127  //we will invert the driver and the accompanied
129  adultNeedingCarAccompaniment.pop_front();
131  personsDrivingCars.pop_front();
132  }
133  }
134  if (personsDrivingCars.empty() && ! childrenNeedingCarAccompaniment.empty()) {
135  //at least one adult exists because no household contains less than one adult
136  if ((int)workingPeoplePossCar.size() != myHousehold->getAdultNbr()) { //personsDrivingCars.size() + adultNeedingCarAccompaniment.size() is equal to 0
137  std::list<AGAdult>::const_iterator itUA;
138  for (itUA = myHousehold->getAdults().begin(); itUA != myHousehold->getAdults().end(); ++itUA) {
139  if (! itUA->isWorking()) {
140  notNeedingDrivers.push_back(*itUA);
141  break;
142  }
143  }
144  } else {
145  personsDrivingCars.push_back(workingPeoplePossCar.front());
146  workingPeoplePossCar.pop_front();
147  }
148  }
149 }
150 
151 bool
153  // check if the starting edge allows cars
155  return false;
156  }
157  std::list<AGAdult>::const_iterator itDriA;
158  std::list<AGCar>::const_iterator itCar = myHousehold->getCars().begin();
159  for (itDriA = personsDrivingCars.begin(); itDriA != personsDrivingCars.end(); ++itDriA) {
160  //check if the number of cars is lower than the number of drivers
161  if (itCar == myHousehold->getCars().end()) {
162  return false;
163  }
164  // check if the destination edge allows cars
165  if (!itDriA->getWorkPosition().getPosition().getStreet().allows(SVC_PASSENGER)) {
166  return false;
167  }
168  AGTrip trip(myHousehold->getPosition(), itDriA->getWorkPosition().getPosition(), *itCar, depHour(myHousehold->getPosition(), itDriA->getWorkPosition().getPosition(), itDriA->getWorkPosition().getOpening()));
169  ++itCar;
170  tempTrip.push_back(trip);
171  }
172 
173  std::list<AGAdult>::iterator itAccA;
174  for (itAccA = adultNeedingCarAccompaniment.begin(); itAccA != adultNeedingCarAccompaniment.end(); ++itAccA) {
175  AGTrip trip(myHousehold->getPosition(), itAccA->getWorkPosition().getPosition(), depHour(myHousehold->getPosition(), itAccA->getWorkPosition().getPosition(), itAccA->getWorkPosition().getOpening()));
176  tempAccTrip.push_back(trip);
177  }
178 
179  std::list<AGChild>::iterator itAccC;
180  for (itAccC = childrenNeedingCarAccompaniment.begin(); itAccC != childrenNeedingCarAccompaniment.end(); ++itAccC) {
181  AGTrip trip(myHousehold->getPosition(), itAccC->getSchoolLocation(), depHour(myHousehold->getPosition(), itAccC->getSchoolLocation(), itAccC->getSchoolOpening()));
182  tempAccTrip.push_back(trip);
183  }
184 
188  }
189 
191  return true;
192 }
193 
194 bool
196  return (myHousehold->getCarNbr() > static_cast<int>(notNeedingDrivers.size() + personsDrivingCars.size()));
197 }
198 
199 bool
201  bool finish = false;
202  int diff1, diff2;
203  int arrTime;
204  std::list<AGTrip>::iterator it1, it2;
205 
206  while (!finish) {
207  finish = true;
208  for (it1 = tempAccTrip.begin(); it1 != tempAccTrip.end(); ++it1) {
209  for (it2 = tempAccTrip.begin(); it2 != tempAccTrip.end(); ++it2) {
210  if (it1 == it2) {
211  continue;
212  }
213  diff1 = it2->getTime() - it1->getRideBackArrTime(this->timePerKm);
214  diff2 = it1->getTime() - it2->getRideBackArrTime(this->timePerKm);
215 
216  if (diff1 < 0 || diff2 < 0) {
217  if (diff2 < diff1) {
218  arrTime = it2->getArrTime(this->timePerKm);
219  it2->addLayOver(*it1);
220  it2->setDepTime(it2->estimateDepTime(arrTime, this->timePerKm));
221  tempAccTrip.erase(it1);
222  } else {
223  arrTime = it1->getArrTime(this->timePerKm);
224  it1->addLayOver(*it2);
225  it1->setDepTime(it1->estimateDepTime(arrTime, this->timePerKm));
226  tempAccTrip.erase(it2);
227  }
228  finish = false;
229  break;
230  }
231  }
232  if (!finish) {
233  break; // return to while
234  }
235  }
236  }
237  return finish;
238 }
239 
240 bool
242  bool check = false;
243  std::list<AGTrip>::iterator itAccT;
244  std::list<AGTrip>::iterator itDriT;
245  std::list<AGAdult>::iterator itA;
246  for (itAccT = tempAccTrip.begin(); itAccT != tempAccTrip.end(); ++itAccT) {
247  for (itDriT = tempTrip.begin(); itDriT != tempTrip.end(); ++itDriT) {
248  if (itAccT->getArrTime(this->timePerKm) < itDriT->getArrTime(this->timePerKm)) {
249  check = true;
250  }
251  }
252  for (itA = notNeedingDrivers.begin(); itA != notNeedingDrivers.end(); ++itA) {
253  if (!itA->isWorking()) {
254  check = true;
255  } else if (itAccT->getRideBackArrTime(this->timePerKm) < itA->getWorkPosition().getOpening()) {
256  check = true;
257  }
258  }
259  if (!check) { //at least one trip is not performed by the existing drivers because it is to late for them
260  return false;
261  }
262  check = false;
263  }
264  return true;
265 }
266 
267 void
269  int arrTime;
270  std::list<AGTrip>::iterator itAccT;
271  std::list<AGTrip>::iterator itDriT;
272  std::list<AGAdult>::iterator itA;
273  bool alreadyDone;
274 
278  for (itAccT = tempAccTrip.begin(); itAccT != tempAccTrip.end(); ++itAccT) {
279  alreadyDone = false;
280  for (itDriT = tempTrip.begin(); itDriT != tempTrip.end(); ++itDriT) {
281  if (!alreadyDone) {
282  if (itAccT->getArrTime(this->timePerKm) < itDriT->getArrTime(this->timePerKm) && !alreadyDone) {
283  //Add the accompaniment trip to the driver's trip OR new trip
284  if (itAccT->getRideBackArrTime(this->timePerKm) < itDriT->getTime()) {
285  //there is enough time to accompany people and go back home before going to work
286  itAccT->setVehicleName(itDriT->getVehicleName());
287  itAccT->addLayOver(itAccT->getArr());//final destination is the last accompaniment stop: not the destination of the course
288  itAccT->setArr(myHousehold->getPosition());//final destination of the whole trip: home
289  myPartialActivityTrips.push_back(*itAccT);
290  alreadyDone = true;
291  } else {
292  //the driver drives people to their working place or school and goes directly to work after that
293  arrTime = itDriT->getArrTime(this->timePerKm);
294  itDriT->addLayOver(*itAccT);
295  itDriT->setDepTime(itDriT->estimateDepTime(arrTime, this->timePerKm));
296  //tempAccTrip.erase(itAccT);
297  //--itAccT; //because of erasure
298  alreadyDone = true;
299  }
300  }
301  }
302  }
303 
304  for (itA = notNeedingDrivers.begin(); itA != notNeedingDrivers.end(); ++itA) {
305  if (!itA->isWorking() && !alreadyDone) {
306  std::string nameC = getUnusedCar();
307  if (nameC.size() != 0) {
308  itAccT->setVehicleName(getUnusedCar());
309  itAccT->addLayOver(itAccT->getArr());
310  itAccT->setArr(myHousehold->getPosition());
311  myPartialActivityTrips.push_back(*itAccT);
312  alreadyDone = true;
313  }
314  } else if (itAccT->getRideBackArrTime(this->timePerKm) < itA->getWorkPosition().getOpening() && !alreadyDone) {
315  std::string nameC = getUnusedCar();
316  if (nameC.size() != 0) {
317  itAccT->setVehicleName(getUnusedCar());
318  itAccT->addLayOver(itAccT->getArr());
319  itAccT->setArr(myHousehold->getPosition());
320  myPartialActivityTrips.push_back(*itAccT);
321  alreadyDone = true;
322  }
323  }
324  }
325  }
326 
330  for (itDriT = tempTrip.begin(); itDriT != tempTrip.end(); ++itDriT) {
331  myPartialActivityTrips.push_back(*itDriT);
332  }
333 
337  for (itA = personsDrivingCars.begin(); itA != personsDrivingCars.end(); ++itA) {
338  for (itDriT = tempTrip.begin(); itDriT != tempTrip.end(); ++itDriT) {
339  if (itA->getWorkPosition().getPosition() == itDriT->getArr()) {
340  AGTrip trip(itA->getWorkPosition().getPosition(), myHousehold->getPosition(), itDriT->getVehicleName(), itA->getWorkPosition().getClosing());
341  myPartialActivityTrips.push_back(trip);
342  tempTrip.erase(itDriT);
343  break;
344  }
345  }
346  }
347 }
348 
349 std::string
351  std::string nameCar = "";
352  std::string nameCarUsed = "";
353  //only two cars can be used in the household, so: the first one or the last one is not used.
354  if (!tempTrip.empty()) {
355  nameCarUsed = tempTrip.front().getVehicleName();
356  } else if (!myPartialActivityTrips.empty()) {
357  nameCarUsed = myPartialActivityTrips.front().getVehicleName();
358  }
359 
360  if (nameCarUsed.size() != 0) {
361  if (myHousehold->getCars().front().getName() == nameCarUsed) {
362  nameCar = myHousehold->getCars().back().getName();
363  } else {
364  nameCar = myHousehold->getCars().front().getName();
365  }
366  }
367  return nameCar;
368 }
369 
370 void
372  //give to a non working adult the ability to drive children or someone else.
374  std::list<AGAdult>::const_iterator itUA;
375  for (itUA = myHousehold->getAdults().begin(); itUA != myHousehold->getAdults().end(); ++itUA) {
376  if (! itUA->isWorking()) {
377  notNeedingDrivers.push_back(*itUA);
378  break;
379  }
380  }
381  }
382 }
383 
384 
385 /****************************************************************************/
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
bool genDone
Definition: AGActivity.h:115
AGHousehold * myHousehold
Definition: AGActivity.h:108
std::list< AGTrip > myPartialActivityTrips
Definition: AGActivity.h:113
int availableTranspMeans(AGPosition from, AGPosition to)
Definition: AGActivity.cpp:85
int possibleTranspMean(AGPosition destination)
Definition: AGActivity.cpp:48
int depHour(AGPosition from, AGPosition to, int arrival)
Definition: AGActivity.cpp:110
double timePerKm
Definition: AGActivity.h:116
AGPosition getPosition()
const std::list< AGCar > & getCars() const
int getCarNbr()
Definition: AGHousehold.cpp:83
int getAdultNbr()
Definition: AGHousehold.cpp:93
const std::list< AGChild > & getChildren() const
const std::list< AGAdult > & getAdults() const
Definition: AGHousehold.cpp:98
double getPosition() const
Provides the relative position of this AGPosition on the street.
Definition: AGPosition.cpp:105
const AGStreet & getStreet() const
Provides the street this AGPosition is located on.
Definition: AGPosition.cpp:99
bool allows(const SUMOVehicleClass vclass) const
Returns whether the given vehicle class is allowed on this street.
Definition: AGStreet.cpp:71
Definition: AGTrip.h:38
std::list< AGAdult > personsDrivingCars
bool checkAndBuildTripConsistancy()
void buildWorkDestinations()
std::list< AGTrip > tempTrip
std::list< AGAdult > adultNeedingCarAccompaniment
std::list< AGAdult > notNeedingDrivers
std::list< AGTrip > tempAccTrip
std::list< AGAdult > workingPeoplePossCar
std::list< AGChild > childrenNeedingCarAccompaniment
void makePossibleDriversDrive()
bool checkDriversScheduleMatching()
void buildChildrenAccompaniment()
std::string getUnusedCar()