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