Eclipse SUMO - Simulation of Urban MObility
AGCity.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2010-2023 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/****************************************************************************/
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>
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// ===========================================================================
49void
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 }
68 //can be improved with other input data
69 double neededWorkPositionsInCity = (1.0 - statData.unemployement)
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 //it->print();
82 }
83
84 //completing streets from edges of the network not handled/present in STAT file (no population no work position)
85 for (const auto& itE : net->getEdgeMap()) {
86 std::vector<AGStreet*>::iterator itS;
87 for (itS = streets.begin(); itS != streets.end(); ++itS) {
88 if (*itS == itE.second) {
89 break;
90 }
91 }
92 //if this edge isn't represented by a street
93 if (itS == streets.end() && !itE.second->isInternal()) {
94 streets.push_back(static_cast<AGStreet*>(itE.second));
95 if (((itE.second)->getPermissions() & SVC_PASSENGER) == SVC_PASSENGER) {
96 passengerStreets.push_back(static_cast<AGStreet*>(itE.second));
97 }
98 }
99 }
100}
101
102void
104 std::vector<AGStreet*>::iterator it;
105 int workPositionCounter = 0;
106
107 try {
108 for (it = streets.begin(); it != streets.end(); ++it) {
109 //std::cout << "number of work positions in street: " << it->getWorkplaceNumber() << std::endl;
110 for (int i = 0; i < (*it)->getWorkplaceNumber(); ++i) {
111 workPositions.push_back(AGWorkPosition(&statData, **it));
112 ++workPositionCounter;
113 }
114 }
115 } catch (const std::bad_alloc& e) {
116 std::cout << "Number of work positions at bad_alloc exception: " << workPositionCounter << std::endl;
117 throw e;
118 }
119 //std::cout << "Inner work positions done. " << workPositionCounter << " generated." << std::endl;
120
121 // Work positions outside the city
123 std::cout << "--> work position: " << std::endl;
124 std::cout << " |-> in city: " << workPositionCounter << std::endl;
125 std::cout << " |-> out city: " << statData.workPositions - workPositionCounter << std::endl;
126 std::cout << " |-> in+out city: " << statData.workPositions << std::endl;
127}
128
129void
131 // work positions outside the city
133 if (nbrWorkers <= 0) {
134 return;
135 }
136 nbrWorkers *= (1.0 - statData.unemployement);
140 int nbrOutWorkPositions = (int)((double)workPositions.size() * (double)statData.outgoingTraffic / (nbrWorkers - (double)statData.outgoingTraffic));
141
142 if (cityGates.empty()) {
143 return;
144 }
145
146 for (int i = 0; i < nbrOutWorkPositions; ++i) {
148 workPositions.push_back(AGWorkPosition(&statData, cityGates[posi].getStreet(), cityGates[posi].getPosition()));
149 }
150 //cout << "outgoing traffic: " << statData.outgoingTraffic << std::endl;
151 //cout << "total number of workers in the city: " << nbrWorkers << std::endl;
152 //cout << "work positions out side the city: " << nbrOutWorkPositions << std::endl;
153 //cout << "work positions in and out of the city: " << workPositions.size() << std::endl;
154 statData.workPositions = static_cast<int>(workPositions.size());
155}
156
157void
159 std::list<AGBusLine>::iterator it;
160 for (it = busLines.begin(); it != busLines.end(); ++it) {
161 //it->generateOpositDirection();
162 it->setBusNames();
163 }
164}
165
166void
168 std::vector<AGStreet*>::iterator it;
169 double people = 0;
170 nbrCars = 0;
171 int idHouseholds = 0;
172 std::vector<int> numAdults(statData.households);
173 std::vector<int> numChilds(statData.households);
176 for (int i = 0; i < statData.households; i++) {
177 numAdults[i] = 1;
178 numChilds[i] = 0;
179 if (RandHelper::rand() < retiredProb) {
180 numAdults[i] = -numAdults[i];
181 } else if (totalChildrenLeft > 0) {
183 totalChildrenLeft -= numChilds[i];
184 }
185 }
186 //compensate with adults for too many / missing children
187 const int numSecondPers = statData.getPeopleOlderThan(statData.limitAgeChildren) - statData.households + totalChildrenLeft;
188 for (int i = 0; i < numSecondPers; i++) {
189 int index = i % numAdults.size();
190 if (numAdults[index] >= 0) {
191 numAdults[index] += 1;
192 } else {
193 numAdults[index] -= 1;
194 }
195 }
196 for (it = streets.begin(); it != streets.end(); ++it) {
197 people += (*it)->getPopulation();
198 while (people > 0 && idHouseholds < (int)numAdults.size()) {
199 int i = RandHelper::rand((int)numAdults.size() - idHouseholds);
200 ++idHouseholds;
201 households.push_back(AGHousehold(*it, this, idHouseholds));
202 households.back().generatePeople(abs(numAdults[i]), numChilds[i], numAdults[i] < 0); //&statData
203 //households.back().generateCars(statData.carRate);
204 people -= households.back().getPeopleNbr();
205 numAdults[i] = numAdults[numAdults.size() - idHouseholds];
206 numChilds[i] = numChilds[numAdults.size() - idHouseholds];
207 }
208 }
209
210 //people from outside of the city generation:
212
213 //TEST
214 int nbrSingle = 0;
215 int nbrCouple = 0;
216 int nbrChild = 0;
217 int nbrHH = 0;
218 int workingP = 0;
219 std::list<AGHousehold>::iterator itt;
220 for (itt = households.begin(); itt != households.end(); ++itt) {
221 if (itt->getAdultNbr() == 1) {
222 nbrSingle++;
223 if (itt->getAdults().front().isWorking()) {
224 workingP++;
225 }
226 }
227 if (itt->getAdultNbr() == 2) {
228 nbrCouple += 2;
229 if (itt->getAdults().front().isWorking()) {
230 workingP++;
231 }
232 if (itt->getAdults().back().isWorking()) {
233 workingP++;
234 }
235 }
236 nbrChild += itt->getPeopleNbr() - itt->getAdultNbr();
237 nbrHH++;
238 }
239 //cout << "number hh: " << nbrHH << std::endl;
240 //cout << "number single: " << nbrSingle << std::endl;
241 //cout << "number couple: " << nbrCouple << std::endl;
242 //cout << "number 3 or more: " << nbr3More << std::endl;
243 //cout << "number adults: " << nbrSingle + nbrCouple + nbr3More << std::endl;
244 //cout << "number children: " << nbrChild << std::endl;
245 //cout << "number people: " << nbrSingle + nbrCouple + nbr3More + nbrChild << std::endl;
246 //END TEST
247
248 std::cout << "--> population: " << std::endl;
249 std::cout << " |-> city households: " << nbrHH << std::endl;
250 std::cout << " |-> city people: " << nbrSingle + nbrCouple + nbrChild << std::endl;
251 std::cout << " |-> city single: " << nbrSingle << " / (in) couple: " << nbrCouple << std::endl;
252 std::cout << " |-> city adults: " << nbrSingle + nbrCouple << std::endl;
253 std::cout << " |-> estimation: " << statData.getPeopleOlderThan(statData.limitAgeChildren) << std::endl;
254 std::cout << " |-> retired: " << statData.getPeopleOlderThan(statData.limitAgeRetirement) << std::endl;
255 std::cout << " |-> city children: " << nbrChild << std::endl;
256 std::cout << " |-> estimation: " << statData.getPeopleYoungerThan(statData.limitAgeChildren) << std::endl;
257
258}
259
260void
262 for (int i = 0; i < statData.incomingTraffic; ++i) {
264 peopleIncoming.push_back(ad);
265 }
266}
267
268void
270 std::list<AGHousehold>::iterator it;
271 bool shortage;
272 for (it = households.begin(); it != households.end(); ++it) {
273 shortage = !it->allocateChildrenSchool();
274 if (shortage) {
275 /*ofstream fichier("test.txt", ios::app); // ouverture en écriture avec effacement du fichier ouvert
276 if(fichier)
277 {
278 fichier << "===> WARNING: Not enough school places in the city for all children..." << std::endl;
279 fichier.close();
280 }
281 else
282 cerr << "Impossible d'ouvrir le fichier !" << std::endl;*/
283
284 //std::cout << "===> WARNING: Not enough school places in the city for all children..." << std::endl;
285 }
286 }
287}
288
289void
291 const bool debug = OptionsCont::getOptions().getBool("debug");
292 statData.AdultNbr = 0;
293 //end tests
297 std::list<AGHousehold>::iterator it;
298 bool shortage;
299
300 if (debug) {
301 std::cout << "\n";
302 }
303
304 for (it = households.begin(); it != households.end(); ++it) {
305 if (it->retiredHouseholders()) {
306 continue;
307 }
308 shortage = !it->allocateAdultsWork();
309 if (shortage) {
310 std::cout << "===> ERROR: Not enough work positions in the city for all working people..." << std::endl;
311 }
312 statData.AdultNbr += it->getAdultNbr(); //TESTING
313 if (debug) {
314 std::cout << " processed " << statData.AdultNbr << " adults\r";
315 }
316 }
317
321 std::list<AGAdult>::iterator itA;
322 for (itA = peopleIncoming.begin(); itA != peopleIncoming.end(); ++itA) {
323 if (statData.workPositions > 0) {
324 itA->tryToWork(1, &workPositions);
325 } else {
326 //shouldn't happen
327 std::cout << "not enough work for incoming people..." << std::endl;
328 }
329 }
330
331 //BEGIN TESTS
332 int workingP = 0;
333 std::list<AGHousehold>::iterator itt;
334 for (itt = households.begin(); itt != households.end(); ++itt) {
335 if (itt->getAdultNbr() == 1) {
336 if (itt->getAdults().front().isWorking()) {
337 workingP++;
338 }
339 }
340 if (itt->getAdultNbr() == 2) {
341 if (itt->getAdults().front().isWorking()) {
342 workingP++;
343 }
344 if (itt->getAdults().back().isWorking()) {
345 workingP++;
346 }
347 }
348 }
349 std::cout << " |-> working people: " << peopleIncoming.size() + workingP << std::endl;
350 std::cout << " |-> working people in city: " << workingP << std::endl;
351 std::cout << " |-> working people from outside: " << peopleIncoming.size() << std::endl;
352 //END TESTS
353}
354
355void
358 nbrCars = 0;
359 std::list<AGHousehold>::iterator it;
360 for (it = households.begin(); it != households.end(); ++it) {
361 if (!it->isCloseFromPubTransport(&(statData.busStations))) {
363 nbrCars++;
364 it->addACar();
365 }
367 }
368 // new rate: the rate on the people that have'nt any car yet:
369 // nR = (R * Drivers - AlreadyCars) / (Drivers - AlreadyCars)
372 newRate = 0.;
373 } else {
375 }
376 //std::cout << " - " << newRate << std::endl;
377 if (newRate < 0 || newRate >= 1) {
378 newRate = 0;
379 }
380
381 nbrCars = 0;
382 //int nbrAdults = 0;
383 for (it = households.begin(); it != households.end(); ++it) {
384 it->generateCars(newRate);
385 nbrCars += it->getCarNbr();
386 //nbrAdults += it->getAdultNbr();
387 }
388 //TEST RESULTS
389 //std::cout << "number of cars: " << nbrCars << std::endl;
390 //std::cout << "number of adults: " << statData.getPeopleOlderThan(statData.limitAgeChildren) << std::endl;
391 //std::cout << "real number of adults: " << nbrAdults << std::endl;
392 //std::cout << "number of people far from public transport: " << statData.hhFarFromPT << std::endl;
393 //std::cout << "original rate: " << setprecision(4) << statData.carRate << std::endl;
394 //std::cout << "new rate: " << setprecision(4) << newRate << std::endl;
395 //std::cout << "real rate: " << setprecision(4) << (double)nbrCars / (double)statData.getPeopleOlderThan(statData.limitAgeChildren) << std::endl;
396 //END TEST RESULTS
397}
398
399const AGStreet&
400AGCity::getStreet(const std::string& edge) {
407 if (!streetsCompleted) {
410 std::cout << "first completed in getStreet() of City: Consolidation of data not needed in ActivityGen any more" << std::endl;
411 }
412 //rest of the function
413 std::vector<AGStreet*>::iterator it = streets.begin();
414 while (it != streets.end()) {
415 if ((*it)->getID() == edge) {
416 return **it;
417 }
418 ++it;
419 }
420 std::cout << "===> ERROR: WRONG STREET EDGE (" << edge << ") given and not found in street set." << std::endl;
421 throw ProcessError("Street not found with edge id " + edge);
422}
423
424const AGStreet&
426 if (passengerStreets.empty()) {
427 throw ProcessError(TL("No street that allows passenger vehicles found in this city."));
428 }
430}
431
432
433/****************************************************************************/
#define TL(string)
Definition: MsgHandler.h:284
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
An adult person who can have a job.
Definition: AGAdult.h:48
std::vector< AGStreet * > streets
Definition: AGCity.h:79
bool streetsCompleted
Definition: AGCity.h:105
void workAllocation()
Definition: AGCity.cpp:290
std::vector< AGStreet * > passengerStreets
Definition: AGCity.h:80
std::list< AGHousehold > households
Definition: AGCity.h:84
void completeBusLines()
Definition: AGCity.cpp:158
std::vector< AGPosition > cityGates
Definition: AGCity.h:85
void carAllocation()
Definition: AGCity.cpp:356
RONet * net
Definition: AGCity.h:100
void generateWorkPositions()
Definition: AGCity.cpp:103
void generateOutgoingWP()
Definition: AGCity.cpp:130
AGDataAndStatistics & statData
Definition: AGCity.h:78
std::vector< AGWorkPosition > workPositions
Definition: AGCity.h:81
void completeStreets()
Definition: AGCity.cpp:50
int nbrCars
Definition: AGCity.h:107
std::list< AGBusLine > busLines
Definition: AGCity.h:83
void generateIncomingPopulation()
Definition: AGCity.cpp:261
const AGStreet & getStreet(const std::string &edge)
Definition: AGCity.cpp:400
const AGStreet & getRandomStreet()
Definition: AGCity.cpp:425
void schoolAllocation()
Definition: AGCity.cpp:269
void generatePopulation()
Definition: AGCity.cpp:167
std::list< AGAdult > peopleIncoming
Definition: AGCity.h:86
int getPoissonsNumberOfChildren(double mean)
int getRandomPopDistributed(int n, int m)
std::map< int, AGPosition > busStations
A model of the street in the city.
Definition: AGStreet.h:50
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:59
const NamedObjectCont< ROEdge * > & getEdgeMap() const
Definition: RONet.h:409
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.cpp:94
static const T & getRandomFrom(const std::vector< T > &v, SumoRNG *rng=nullptr)
Returns a random element from the given vector.
Definition: RandHelper.h:198