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