Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/activitygen/city/AGCity.cpp
169684 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2010-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 AGCity.cpp
17
/// @author Piotr Woznica
18
/// @author Daniel Krajzewicz
19
/// @author Michael Behrisch
20
/// @author Walter Bamberger
21
/// @author Jakob Erdmann
22
/// @date July 2010
23
///
24
// City class that contains all other objects of the city: in particular
25
// streets, households, bus lines, work positions and school
26
/****************************************************************************/
27
#include <config.h>
28
29
#include <iostream>
30
#include <vector>
31
#include <string>
32
#include <map>
33
#include <iomanip>
34
#include <utils/common/RandHelper.h>
35
#include <utils/common/SUMOVehicleClass.h>
36
#include <utils/options/OptionsCont.h>
37
#include <router/RONet.h>
38
#include <router/ROEdge.h>
39
#include "AGAdult.h"
40
#include "AGStreet.h"
41
#include "AGWorkPosition.h"
42
#include "AGCity.h"
43
//#define DRIVING_LICENSE_AGE 18
44
45
46
// ===========================================================================
47
// method definitions
48
// ===========================================================================
49
void
50
AGCity::completeStreets() {
51
if (streetsCompleted) {
52
return;
53
} else {
54
streetsCompleted = true;
55
}
56
57
double pop = 0, work = 0;
58
std::vector<AGStreet*>::iterator it;
59
60
for (it = streets.begin(); it != streets.end(); ++it) {
61
pop += (*it)->getPopulation();
62
work += (*it)->getWorkplaceNumber();
63
if (((*it)->getPermissions() & SVC_PASSENGER) == SVC_PASSENGER) {
64
passengerStreets.push_back(*it);
65
}
66
}
67
statData.factorInhabitants = (double)statData.inhabitants / pop;
68
//can be improved with other input data
69
double neededWorkPositionsInCity = (1.0 - statData.unemployement)
70
* ((double)statData.getPeopleYoungerThan(statData.limitAgeRetirement)
71
- (double)statData.getPeopleYoungerThan(statData.limitAgeChildren))
72
+ (double)statData.incomingTraffic;
73
// by default laborDemand = 1.05. We generate 5% more work positions that really needed to avoid any expensive research of random work positions
74
neededWorkPositionsInCity *= statData.laborDemand;
75
statData.workPositions = (int)neededWorkPositionsInCity;
76
statData.factorWorkPositions = neededWorkPositionsInCity / (double) work;
77
78
for (it = streets.begin(); it != streets.end(); ++it) {
79
(*it)->setPopulation((*it)->getPopulation() * statData.factorInhabitants);
80
(*it)->setWorkplaceNumber((*it)->getWorkplaceNumber() * statData.factorWorkPositions);
81
}
82
83
//completing streets from edges of the network not handled/present in STAT file (no population no work position)
84
for (const auto& itE : net->getEdgeMap()) {
85
std::vector<AGStreet*>::iterator itS;
86
for (itS = streets.begin(); itS != streets.end(); ++itS) {
87
if (*itS == itE.second) {
88
break;
89
}
90
}
91
//if this edge isn't represented by a street
92
if (itS == streets.end() && !itE.second->isInternal()) {
93
streets.push_back(static_cast<AGStreet*>(itE.second));
94
if (((itE.second)->getPermissions() & SVC_PASSENGER) == SVC_PASSENGER) {
95
passengerStreets.push_back(static_cast<AGStreet*>(itE.second));
96
}
97
}
98
}
99
}
100
101
void
102
AGCity::generateWorkPositions() {
103
std::vector<AGStreet*>::iterator it;
104
int workPositionCounter = 0;
105
try {
106
for (it = streets.begin(); it != streets.end(); ++it) {
107
for (int i = 0; i < (*it)->getWorkplaceNumber(); ++i) {
108
workPositions.push_back(AGWorkPosition(&statData, **it));
109
++workPositionCounter;
110
}
111
}
112
} catch (const std::bad_alloc&) {
113
std::cout << "Number of work positions at bad_alloc exception: " << workPositionCounter << std::endl;
114
throw;
115
}
116
//std::cout << "Inner work positions done. " << workPositionCounter << " generated." << std::endl;
117
118
// Work positions outside the city
119
generateOutgoingWP();
120
std::cout << "--> work position:" << std::endl;
121
std::cout << " |-> in city: " << workPositionCounter << std::endl;
122
std::cout << " |-> out city: " << statData.workPositions - workPositionCounter << std::endl;
123
std::cout << " |-> in+out city: " << statData.workPositions << std::endl;
124
}
125
126
void
127
AGCity::generateOutgoingWP() {
128
// work positions outside the city
129
double nbrWorkers = static_cast<double>(statData.getPeopleYoungerThan(statData.limitAgeRetirement) - statData.getPeopleYoungerThan(statData.limitAgeChildren));
130
if (nbrWorkers <= 0) {
131
return;
132
}
133
nbrWorkers *= (1.0 - statData.unemployement);
134
/**
135
* N_out = N_in * (ProportionOut / (1 - ProportionOut)) = N_out = N_in * (Noutworkers / (Nworkers - Noutworkers))
136
*/
137
int nbrOutWorkPositions = (int)((double)workPositions.size() * (double)statData.outgoingTraffic / (nbrWorkers - (double)statData.outgoingTraffic));
138
139
if (cityGates.empty()) {
140
statData.workPositions = static_cast<int>(workPositions.size());
141
return;
142
}
143
144
for (int i = 0; i < nbrOutWorkPositions; ++i) {
145
int posi = statData.getRandomCityGateByOutgoing();
146
workPositions.push_back(AGWorkPosition(&statData, cityGates[posi].getStreet(), cityGates[posi].getPosition()));
147
}
148
//cout << "outgoing traffic: " << statData.outgoingTraffic << std::endl;
149
//cout << "total number of workers in the city: " << nbrWorkers << std::endl;
150
//cout << "work positions out side the city: " << nbrOutWorkPositions << std::endl;
151
//cout << "work positions in and out of the city: " << workPositions.size() << std::endl;
152
statData.workPositions = static_cast<int>(workPositions.size());
153
}
154
155
void
156
AGCity::completeBusLines() {
157
std::list<AGBusLine>::iterator it;
158
for (it = busLines.begin(); it != busLines.end(); ++it) {
159
//it->generateOpositDirection();
160
it->setBusNames();
161
}
162
}
163
164
void
165
AGCity::generatePopulation() {
166
std::vector<AGStreet*>::iterator it;
167
double people = 0;
168
nbrCars = 0;
169
int idHouseholds = 0;
170
std::vector<int> numAdults(statData.households);
171
std::vector<int> numChilds(statData.households);
172
int totalChildrenLeft = statData.inhabitants - statData.getPeopleOlderThan(statData.limitAgeChildren);
173
const double retiredProb = statData.getPeopleOlderThan(statData.limitAgeRetirement) / statData.getPeopleOlderThan(statData.limitAgeChildren);
174
for (int i = 0; i < statData.households; i++) {
175
numAdults[i] = 1;
176
numChilds[i] = 0;
177
if (RandHelper::rand() < retiredProb) {
178
numAdults[i] = -numAdults[i];
179
} else if (totalChildrenLeft > 0) {
180
numChilds[i] = statData.getPoissonsNumberOfChildren(statData.meanNbrChildren);
181
totalChildrenLeft -= numChilds[i];
182
}
183
}
184
//compensate with adults for too many / missing children
185
const int numSecondPers = statData.getPeopleOlderThan(statData.limitAgeChildren) - statData.households + totalChildrenLeft;
186
for (int i = 0; i < numSecondPers; i++) {
187
int index = i % numAdults.size();
188
if (numAdults[index] >= 0) {
189
numAdults[index] += 1;
190
} else {
191
numAdults[index] -= 1;
192
}
193
}
194
for (it = streets.begin(); it != streets.end(); ++it) {
195
people += (*it)->getPopulation();
196
while (people > 0 && idHouseholds < (int)numAdults.size()) {
197
int i = RandHelper::rand((int)numAdults.size() - idHouseholds);
198
++idHouseholds;
199
households.push_back(AGHousehold(*it, this, idHouseholds));
200
households.back().generatePeople(abs(numAdults[i]), numChilds[i], numAdults[i] < 0); //&statData
201
//households.back().generateCars(statData.carRate);
202
people -= households.back().getPeopleNbr();
203
numAdults[i] = numAdults[numAdults.size() - idHouseholds];
204
numChilds[i] = numChilds[numAdults.size() - idHouseholds];
205
}
206
}
207
208
//people from outside of the city generation:
209
generateIncomingPopulation();
210
211
//TEST
212
int nbrSingle = 0;
213
int nbrCouple = 0;
214
int nbrChild = 0;
215
int nbrHH = 0;
216
std::list<AGHousehold>::iterator itt;
217
for (itt = households.begin(); itt != households.end(); ++itt) {
218
if (itt->getAdultNbr() == 1) {
219
nbrSingle++;
220
}
221
if (itt->getAdultNbr() == 2) {
222
nbrCouple += 2;
223
}
224
nbrChild += itt->getPeopleNbr() - itt->getAdultNbr();
225
nbrHH++;
226
}
227
//cout << "number hh: " << nbrHH << std::endl;
228
//cout << "number single: " << nbrSingle << std::endl;
229
//cout << "number couple: " << nbrCouple << std::endl;
230
//cout << "number 3 or more: " << nbr3More << std::endl;
231
//cout << "number adults: " << nbrSingle + nbrCouple + nbr3More << std::endl;
232
//cout << "number children: " << nbrChild << std::endl;
233
//cout << "number people: " << nbrSingle + nbrCouple + nbr3More + nbrChild << std::endl;
234
//END TEST
235
236
std::cout << "--> population:" << std::endl;
237
std::cout << " |-> city households: " << nbrHH << std::endl;
238
std::cout << " |-> city people: " << nbrSingle + nbrCouple + nbrChild << std::endl;
239
std::cout << " |-> city single: " << nbrSingle << " / (in) couple: " << nbrCouple << std::endl;
240
std::cout << " |-> city adults: " << nbrSingle + nbrCouple << std::endl;
241
std::cout << " |-> estimation: " << statData.getPeopleOlderThan(statData.limitAgeChildren) << std::endl;
242
std::cout << " |-> retired: " << statData.getPeopleOlderThan(statData.limitAgeRetirement) << std::endl;
243
std::cout << " |-> city children: " << nbrChild << std::endl;
244
std::cout << " |-> estimation: " << statData.getPeopleYoungerThan(statData.limitAgeChildren) << std::endl;
245
246
}
247
248
void
249
AGCity::generateIncomingPopulation() {
250
for (int i = 0; i < statData.incomingTraffic; ++i) {
251
AGAdult ad(statData.getRandomPopDistributed(statData.limitAgeChildren, statData.limitAgeRetirement));
252
peopleIncoming.push_back(ad);
253
}
254
}
255
256
void
257
AGCity::schoolAllocation() {
258
std::list<AGHousehold>::iterator it;
259
bool shortage;
260
for (it = households.begin(); it != households.end(); ++it) {
261
shortage = !it->allocateChildrenSchool();
262
if (shortage) {
263
/*ofstream fichier("test.txt", ios::app); // ouverture en écriture avec effacement du fichier ouvert
264
if(fichier)
265
{
266
fichier << "===> WARNING: Not enough school places in the city for all children..." << std::endl;
267
fichier.close();
268
}
269
else
270
cerr << "Impossible d'ouvrir le fichier !" << std::endl;*/
271
272
//std::cout << "===> WARNING: Not enough school places in the city for all children..." << std::endl;
273
}
274
}
275
}
276
277
void
278
AGCity::workAllocation() {
279
const bool debug = OptionsCont::getOptions().getBool("debug");
280
statData.AdultNbr = 0;
281
//end tests
282
/**
283
* people from the city
284
*/
285
std::list<AGHousehold>::iterator it;
286
bool shortage;
287
288
if (debug) {
289
std::cout << "\n";
290
}
291
292
for (it = households.begin(); it != households.end(); ++it) {
293
if (it->retiredHouseholders()) {
294
continue;
295
}
296
shortage = !it->allocateAdultsWork();
297
if (shortage) {
298
std::cout << "===> ERROR: Not enough work positions in the city for all working people..." << std::endl;
299
}
300
statData.AdultNbr += it->getAdultNbr(); //TESTING
301
if (debug) {
302
std::cout << " processed " << statData.AdultNbr << " adults\r";
303
}
304
}
305
306
/**
307
* people from outside
308
*/
309
std::list<AGAdult>::iterator itA;
310
for (itA = peopleIncoming.begin(); itA != peopleIncoming.end(); ++itA) {
311
if (statData.workPositions > 0) {
312
itA->tryToWork(1, &workPositions);
313
} else {
314
//shouldn't happen
315
std::cout << "not enough work for incoming people..." << std::endl;
316
}
317
}
318
319
//BEGIN TESTS
320
int workingP = 0;
321
std::list<AGHousehold>::iterator itt;
322
for (itt = households.begin(); itt != households.end(); ++itt) {
323
if (itt->getAdultNbr() == 1) {
324
if (itt->getAdults().front().isWorking()) {
325
workingP++;
326
}
327
}
328
if (itt->getAdultNbr() == 2) {
329
if (itt->getAdults().front().isWorking()) {
330
workingP++;
331
}
332
if (itt->getAdults().back().isWorking()) {
333
workingP++;
334
}
335
}
336
}
337
std::cout << " |-> working people: " << peopleIncoming.size() + workingP << std::endl;
338
std::cout << " |-> working people in city: " << workingP << std::endl;
339
std::cout << " |-> working people from outside: " << peopleIncoming.size() << std::endl;
340
//END TESTS
341
}
342
343
void
344
AGCity::carAllocation() {
345
statData.hhFarFromPT = 0;
346
nbrCars = 0;
347
std::list<AGHousehold>::iterator it;
348
for (it = households.begin(); it != households.end(); ++it) {
349
if (!it->isCloseFromPubTransport(&(statData.busStations))) {
350
statData.hhFarFromPT++;
351
nbrCars++;
352
it->addACar();
353
}
354
statData.householdsNbr++;
355
}
356
// new rate: the rate on the people that have'nt any car yet:
357
// nR = (R * Drivers - AlreadyCars) / (Drivers - AlreadyCars)
358
double newRate = statData.carRate * statData.getPeopleOlderThan(statData.limitAgeChildren) - statData.hhFarFromPT;
359
if (statData.getPeopleOlderThan(statData.limitAgeChildren) == statData.hhFarFromPT) {
360
newRate = 0.;
361
} else {
362
newRate /= statData.getPeopleOlderThan(statData.limitAgeChildren) - statData.hhFarFromPT;
363
}
364
//std::cout << " - " << newRate << std::endl;
365
if (newRate < 0 || newRate >= 1) {
366
newRate = 0;
367
}
368
369
nbrCars = 0;
370
//int nbrAdults = 0;
371
for (it = households.begin(); it != households.end(); ++it) {
372
it->generateCars(newRate);
373
nbrCars += it->getCarNbr();
374
//nbrAdults += it->getAdultNbr();
375
}
376
//TEST RESULTS
377
//std::cout << "number of cars: " << nbrCars << std::endl;
378
//std::cout << "number of adults: " << statData.getPeopleOlderThan(statData.limitAgeChildren) << std::endl;
379
//std::cout << "real number of adults: " << nbrAdults << std::endl;
380
//std::cout << "number of people far from public transport: " << statData.hhFarFromPT << std::endl;
381
//std::cout << "original rate: " << setprecision(4) << statData.carRate << std::endl;
382
//std::cout << "new rate: " << setprecision(4) << newRate << std::endl;
383
//std::cout << "real rate: " << setprecision(4) << (double)nbrCars / (double)statData.getPeopleOlderThan(statData.limitAgeChildren) << std::endl;
384
//END TEST RESULTS
385
}
386
387
const AGStreet&
388
AGCity::getStreet(const std::string& edge) {
389
/**
390
* verify if it is the first time this function is called
391
* in this case, we have to complete the streets with the
392
* network edges this means that streets are completely
393
* loaded (no any more to be read from stat-file)
394
*/
395
if (!streetsCompleted) {
396
statData.consolidateStat();
397
completeStreets();
398
std::cout << "first completed in getStreet() of City: Consolidation of data not needed in ActivityGen any more" << std::endl;
399
}
400
//rest of the function
401
std::vector<AGStreet*>::iterator it = streets.begin();
402
while (it != streets.end()) {
403
if ((*it)->getID() == edge) {
404
return **it;
405
}
406
++it;
407
}
408
std::cout << "===> ERROR: WRONG STREET EDGE (" << edge << ") given and not found in street set." << std::endl;
409
throw ProcessError("Street not found with edge id " + edge);
410
}
411
412
const AGStreet&
413
AGCity::getRandomStreet() {
414
if (passengerStreets.empty()) {
415
throw ProcessError(TL("No street that allows passenger vehicles found in this city."));
416
}
417
return *RandHelper::getRandomFrom(passengerStreets);
418
}
419
420
421
/****************************************************************************/
422
423