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.dev/sumo
3 // Copyright (C) 2010-2024 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 // ===========================================================================
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  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  }
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
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& e) {
113  std::cout << "Number of work positions at bad_alloc exception: " << workPositionCounter << std::endl;
114  throw e;
115  }
116  //std::cout << "Inner work positions done. " << workPositionCounter << " generated." << std::endl;
117 
118  // Work positions outside the city
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
128  // work positions outside the city
130  if (nbrWorkers <= 0) {
131  return;
132  }
133  nbrWorkers *= (1.0 - statData.unemployement);
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) {
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
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
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);
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) {
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:
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
250  for (int i = 0; i < statData.incomingTraffic; ++i) {
252  peopleIncoming.push_back(ad);
253  }
254 }
255 
256 void
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
279  const bool debug = OptionsCont::getOptions().getBool("debug");
280  statData.AdultNbr = 0;
281  //end tests
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 
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
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))) {
351  nbrCars++;
352  it->addACar();
353  }
355  }
356  // new rate: the rate on the people that have'nt any car yet:
357  // nR = (R * Drivers - AlreadyCars) / (Drivers - AlreadyCars)
360  newRate = 0.;
361  } else {
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) {
395  if (!streetsCompleted) {
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&
414  if (passengerStreets.empty()) {
415  throw ProcessError(TL("No street that allows passenger vehicles found in this city."));
416  }
418 }
419 
420 
421 /****************************************************************************/
#define TL(string)
Definition: MsgHandler.h:315
@ 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:278
std::vector< AGStreet * > passengerStreets
Definition: AGCity.h:80
std::list< AGHousehold > households
Definition: AGCity.h:84
void completeBusLines()
Definition: AGCity.cpp:156
std::vector< AGPosition > cityGates
Definition: AGCity.h:85
void carAllocation()
Definition: AGCity.cpp:344
RONet * net
Definition: AGCity.h:100
void generateWorkPositions()
Definition: AGCity.cpp:102
void generateOutgoingWP()
Definition: AGCity.cpp:127
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:249
const AGStreet & getStreet(const std::string &edge)
Definition: AGCity.cpp:388
const AGStreet & getRandomStreet()
Definition: AGCity.cpp:413
void schoolAllocation()
Definition: AGCity.cpp:257
void generatePopulation()
Definition: AGCity.cpp:165
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:60
const NamedObjectCont< ROEdge * > & getEdgeMap() const
Definition: RONet.h:422
static const T & getRandomFrom(const std::vector< T > &v, SumoRNG *rng=nullptr)
Returns a random element from the given vector.
Definition: RandHelper.h:206
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.cpp:94