Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/activitygen/activities/AGWorkAndSchool.cpp
169678 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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
/****************************************************************************/
16
/// @file AGWorkAndSchool.cpp
17
/// @author Piotr Woznica
18
/// @author Daniel Krajzewicz
19
/// @author Michael Behrisch
20
/// @author Walter Bamberger
21
/// @date July 2010
22
///
23
// Generates trips to work and to school
24
/****************************************************************************/
25
#include <config.h>
26
27
#include <list>
28
#include <utils/common/SUMOVehicleClass.h>
29
#include <activitygen/city/AGCar.h>
30
#include <activitygen/city/AGChild.h>
31
#include <activitygen/city/AGHousehold.h>
32
#include <activitygen/city/AGStreet.h>
33
#include <activitygen/city/AGWorkPosition.h>
34
#include "AGWorkAndSchool.h"
35
36
37
// ===========================================================================
38
// method definitions
39
// ===========================================================================
40
bool
41
AGWorkAndSchool::generateTrips() {
42
//buildDestinations();
43
// generation of the waiting list for the accompaniment
44
buildChildrenAccompaniment();
45
46
buildWorkDestinations();
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
74
AGWorkAndSchool::buildChildrenAccompaniment() {
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
87
AGWorkAndSchool::buildWorkDestinations() {
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
121
AGWorkAndSchool::carAllocation() {
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
128
personsDrivingCars.push_back(adultNeedingCarAccompaniment.front());
129
adultNeedingCarAccompaniment.pop_front();
130
adultNeedingCarAccompaniment.push_back(personsDrivingCars.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
152
AGWorkAndSchool::carsToTrips() {
153
// check if the starting edge allows cars
154
if (!myHousehold->getPosition().getStreet().allows(SVC_PASSENGER)) {
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
185
checkAndBuildTripConsistancy();
186
if (isThereUnusedCar() && ! checkDriversScheduleMatching()) {
187
makePossibleDriversDrive();
188
}
189
190
generateListTrips();
191
return true;
192
}
193
194
bool
195
AGWorkAndSchool::isThereUnusedCar() {
196
return (myHousehold->getCarNbr() > static_cast<int>(notNeedingDrivers.size() + personsDrivingCars.size()));
197
}
198
199
bool
200
AGWorkAndSchool::checkAndBuildTripConsistancy() {
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
241
AGWorkAndSchool::checkDriversScheduleMatching() {
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
268
AGWorkAndSchool::generateListTrips() {
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
275
/**
276
* 1 / 3 : Accompaniment
277
*/
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
327
/**
328
* 2/3 : drivers way
329
*/
330
for (itDriT = tempTrip.begin(); itDriT != tempTrip.end(); ++itDriT) {
331
myPartialActivityTrips.push_back(*itDriT);
332
}
333
334
/**
335
* 3/3: way return
336
*/
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
350
AGWorkAndSchool::getUnusedCar() {
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
371
AGWorkAndSchool::makePossibleDriversDrive() {
372
//give to a non working adult the ability to drive children or someone else.
373
if ((int)(workingPeoplePossCar.size() + personsDrivingCars.size() + adultNeedingCarAccompaniment.size()) != myHousehold->getAdultNbr()) {
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
/****************************************************************************/
386
387