Line data Source code
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 : /****************************************************************************/
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 16 : AGCity::completeStreets() {
51 16 : if (streetsCompleted) {
52 : return;
53 : } else {
54 9 : streetsCompleted = true;
55 : }
56 :
57 : double pop = 0, work = 0;
58 : std::vector<AGStreet*>::iterator it;
59 :
60 123 : for (it = streets.begin(); it != streets.end(); ++it) {
61 114 : pop += (*it)->getPopulation();
62 114 : work += (*it)->getWorkplaceNumber();
63 114 : if (((*it)->getPermissions() & SVC_PASSENGER) == SVC_PASSENGER) {
64 88 : passengerStreets.push_back(*it);
65 : }
66 : }
67 9 : statData.factorInhabitants = (double)statData.inhabitants / pop;
68 : //can be improved with other input data
69 9 : double neededWorkPositionsInCity = (1.0 - statData.unemployement)
70 9 : * ((double)statData.getPeopleYoungerThan(statData.limitAgeRetirement)
71 9 : - (double)statData.getPeopleYoungerThan(statData.limitAgeChildren))
72 9 : + (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 9 : neededWorkPositionsInCity *= statData.laborDemand;
75 9 : statData.workPositions = (int)neededWorkPositionsInCity;
76 9 : statData.factorWorkPositions = neededWorkPositionsInCity / (double) work;
77 :
78 123 : for (it = streets.begin(); it != streets.end(); ++it) {
79 114 : (*it)->setPopulation((*it)->getPopulation() * statData.factorInhabitants);
80 114 : (*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 2403 : for (const auto& itE : net->getEdgeMap()) {
85 : std::vector<AGStreet*>::iterator itS;
86 38724 : for (itS = streets.begin(); itS != streets.end(); ++itS) {
87 36444 : if (*itS == itE.second) {
88 : break;
89 : }
90 : }
91 : //if this edge isn't represented by a street
92 2394 : if (itS == streets.end() && !itE.second->isInternal()) {
93 354 : streets.push_back(static_cast<AGStreet*>(itE.second));
94 354 : if (((itE.second)->getPermissions() & SVC_PASSENGER) == SVC_PASSENGER) {
95 328 : passengerStreets.push_back(static_cast<AGStreet*>(itE.second));
96 : }
97 : }
98 : }
99 : }
100 :
101 : void
102 9 : AGCity::generateWorkPositions() {
103 : std::vector<AGStreet*>::iterator it;
104 : int workPositionCounter = 0;
105 : try {
106 477 : for (it = streets.begin(); it != streets.end(); ++it) {
107 3638 : for (int i = 0; i < (*it)->getWorkplaceNumber(); ++i) {
108 6340 : workPositions.push_back(AGWorkPosition(&statData, **it));
109 3170 : ++workPositionCounter;
110 : }
111 : }
112 0 : } catch (const std::bad_alloc& e) {
113 0 : std::cout << "Number of work positions at bad_alloc exception: " << workPositionCounter << std::endl;
114 0 : throw;
115 0 : }
116 : //std::cout << "Inner work positions done. " << workPositionCounter << " generated." << std::endl;
117 :
118 : // Work positions outside the city
119 9 : generateOutgoingWP();
120 : std::cout << "--> work position:" << std::endl;
121 9 : std::cout << " |-> in city: " << workPositionCounter << std::endl;
122 9 : std::cout << " |-> out city: " << statData.workPositions - workPositionCounter << std::endl;
123 9 : std::cout << " |-> in+out city: " << statData.workPositions << std::endl;
124 9 : }
125 :
126 : void
127 9 : AGCity::generateOutgoingWP() {
128 : // work positions outside the city
129 9 : double nbrWorkers = static_cast<double>(statData.getPeopleYoungerThan(statData.limitAgeRetirement) - statData.getPeopleYoungerThan(statData.limitAgeChildren));
130 9 : if (nbrWorkers <= 0) {
131 : return;
132 : }
133 9 : nbrWorkers *= (1.0 - statData.unemployement);
134 : /**
135 : * N_out = N_in * (ProportionOut / (1 - ProportionOut)) = N_out = N_in * (Noutworkers / (Nworkers - Noutworkers))
136 : */
137 9 : int nbrOutWorkPositions = (int)((double)workPositions.size() * (double)statData.outgoingTraffic / (nbrWorkers - (double)statData.outgoingTraffic));
138 :
139 9 : if (cityGates.empty()) {
140 6 : statData.workPositions = static_cast<int>(workPositions.size());
141 6 : return;
142 : }
143 :
144 243 : for (int i = 0; i < nbrOutWorkPositions; ++i) {
145 240 : int posi = statData.getRandomCityGateByOutgoing();
146 480 : 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 3 : statData.workPositions = static_cast<int>(workPositions.size());
153 : }
154 :
155 : void
156 9 : AGCity::completeBusLines() {
157 : std::list<AGBusLine>::iterator it;
158 20 : for (it = busLines.begin(); it != busLines.end(); ++it) {
159 : //it->generateOpositDirection();
160 11 : it->setBusNames();
161 : }
162 9 : }
163 :
164 : void
165 9 : AGCity::generatePopulation() {
166 : std::vector<AGStreet*>::iterator it;
167 : double people = 0;
168 9 : nbrCars = 0;
169 : int idHouseholds = 0;
170 9 : std::vector<int> numAdults(statData.households);
171 9 : std::vector<int> numChilds(statData.households);
172 9 : int totalChildrenLeft = statData.inhabitants - statData.getPeopleOlderThan(statData.limitAgeChildren);
173 9 : const double retiredProb = statData.getPeopleOlderThan(statData.limitAgeRetirement) / statData.getPeopleOlderThan(statData.limitAgeChildren);
174 2014 : for (int i = 0; i < statData.households; i++) {
175 2005 : numAdults[i] = 1;
176 2005 : numChilds[i] = 0;
177 2005 : if (RandHelper::rand() < retiredProb) {
178 0 : numAdults[i] = -numAdults[i];
179 2005 : } else if (totalChildrenLeft > 0) {
180 1367 : numChilds[i] = statData.getPoissonsNumberOfChildren(statData.meanNbrChildren);
181 1367 : totalChildrenLeft -= numChilds[i];
182 : }
183 : }
184 : //compensate with adults for too many / missing children
185 9 : const int numSecondPers = statData.getPeopleOlderThan(statData.limitAgeChildren) - statData.households + totalChildrenLeft;
186 1249 : for (int i = 0; i < numSecondPers; i++) {
187 1240 : int index = i % numAdults.size();
188 1240 : if (numAdults[index] >= 0) {
189 1240 : numAdults[index] += 1;
190 : } else {
191 0 : numAdults[index] -= 1;
192 : }
193 : }
194 477 : for (it = streets.begin(); it != streets.end(); ++it) {
195 468 : people += (*it)->getPopulation();
196 2473 : while (people > 0 && idHouseholds < (int)numAdults.size()) {
197 2005 : int i = RandHelper::rand((int)numAdults.size() - idHouseholds);
198 2005 : ++idHouseholds;
199 4010 : households.push_back(AGHousehold(*it, this, idHouseholds));
200 2005 : households.back().generatePeople(abs(numAdults[i]), numChilds[i], numAdults[i] < 0); //&statData
201 : //households.back().generateCars(statData.carRate);
202 2005 : people -= households.back().getPeopleNbr();
203 2005 : numAdults[i] = numAdults[numAdults.size() - idHouseholds];
204 2005 : numChilds[i] = numChilds[numAdults.size() - idHouseholds];
205 : }
206 : }
207 :
208 : //people from outside of the city generation:
209 9 : 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 2014 : for (itt = households.begin(); itt != households.end(); ++itt) {
218 2005 : if (itt->getAdultNbr() == 1) {
219 765 : nbrSingle++;
220 : }
221 2005 : if (itt->getAdultNbr() == 2) {
222 1240 : nbrCouple += 2;
223 : }
224 2005 : nbrChild += itt->getPeopleNbr() - itt->getAdultNbr();
225 2005 : 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 9 : std::cout << " |-> city households: " << nbrHH << std::endl;
238 9 : std::cout << " |-> city people: " << nbrSingle + nbrCouple + nbrChild << std::endl;
239 18 : std::cout << " |-> city single: " << nbrSingle << " / (in) couple: " << nbrCouple << std::endl;
240 9 : std::cout << " |-> city adults: " << nbrSingle + nbrCouple << std::endl;
241 9 : std::cout << " |-> estimation: " << statData.getPeopleOlderThan(statData.limitAgeChildren) << std::endl;
242 9 : std::cout << " |-> retired: " << statData.getPeopleOlderThan(statData.limitAgeRetirement) << std::endl;
243 9 : std::cout << " |-> city children: " << nbrChild << std::endl;
244 9 : std::cout << " |-> estimation: " << statData.getPeopleYoungerThan(statData.limitAgeChildren) << std::endl;
245 :
246 9 : }
247 :
248 : void
249 9 : AGCity::generateIncomingPopulation() {
250 809 : for (int i = 0; i < statData.incomingTraffic; ++i) {
251 800 : AGAdult ad(statData.getRandomPopDistributed(statData.limitAgeChildren, statData.limitAgeRetirement));
252 800 : peopleIncoming.push_back(ad);
253 : }
254 9 : }
255 :
256 : void
257 9 : AGCity::schoolAllocation() {
258 : std::list<AGHousehold>::iterator it;
259 : bool shortage;
260 2014 : for (it = households.begin(); it != households.end(); ++it) {
261 2005 : 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 9 : }
276 :
277 : void
278 9 : AGCity::workAllocation() {
279 9 : const bool debug = OptionsCont::getOptions().getBool("debug");
280 9 : statData.AdultNbr = 0;
281 : //end tests
282 : /**
283 : * people from the city
284 : */
285 : std::list<AGHousehold>::iterator it;
286 : bool shortage;
287 :
288 9 : if (debug) {
289 0 : std::cout << "\n";
290 : }
291 :
292 2014 : for (it = households.begin(); it != households.end(); ++it) {
293 2005 : if (it->retiredHouseholders()) {
294 580 : continue;
295 : }
296 1425 : shortage = !it->allocateAdultsWork();
297 1425 : if (shortage) {
298 : std::cout << "===> ERROR: Not enough work positions in the city for all working people..." << std::endl;
299 : }
300 1425 : statData.AdultNbr += it->getAdultNbr(); //TESTING
301 1425 : if (debug) {
302 0 : std::cout << " processed " << statData.AdultNbr << " adults\r";
303 : }
304 : }
305 :
306 : /**
307 : * people from outside
308 : */
309 : std::list<AGAdult>::iterator itA;
310 809 : for (itA = peopleIncoming.begin(); itA != peopleIncoming.end(); ++itA) {
311 800 : if (statData.workPositions > 0) {
312 800 : 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 2014 : for (itt = households.begin(); itt != households.end(); ++itt) {
323 2005 : if (itt->getAdultNbr() == 1) {
324 765 : if (itt->getAdults().front().isWorking()) {
325 528 : workingP++;
326 : }
327 : }
328 2005 : if (itt->getAdultNbr() == 2) {
329 1240 : if (itt->getAdults().front().isWorking()) {
330 807 : workingP++;
331 : }
332 1240 : if (itt->getAdults().back().isWorking()) {
333 817 : workingP++;
334 : }
335 : }
336 : }
337 9 : std::cout << " |-> working people: " << peopleIncoming.size() + workingP << std::endl;
338 9 : std::cout << " |-> working people in city: " << workingP << std::endl;
339 : std::cout << " |-> working people from outside: " << peopleIncoming.size() << std::endl;
340 : //END TESTS
341 9 : }
342 :
343 : void
344 9 : AGCity::carAllocation() {
345 9 : statData.hhFarFromPT = 0;
346 9 : nbrCars = 0;
347 : std::list<AGHousehold>::iterator it;
348 2014 : for (it = households.begin(); it != households.end(); ++it) {
349 2005 : if (!it->isCloseFromPubTransport(&(statData.busStations))) {
350 249 : statData.hhFarFromPT++;
351 249 : nbrCars++;
352 249 : it->addACar();
353 : }
354 2005 : 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 9 : double newRate = statData.carRate * statData.getPeopleOlderThan(statData.limitAgeChildren) - statData.hhFarFromPT;
359 9 : if (statData.getPeopleOlderThan(statData.limitAgeChildren) == statData.hhFarFromPT) {
360 : newRate = 0.;
361 : } else {
362 7 : newRate /= statData.getPeopleOlderThan(statData.limitAgeChildren) - statData.hhFarFromPT;
363 : }
364 : //std::cout << " - " << newRate << std::endl;
365 9 : if (newRate < 0 || newRate >= 1) {
366 : newRate = 0;
367 : }
368 :
369 9 : nbrCars = 0;
370 : //int nbrAdults = 0;
371 2014 : for (it = households.begin(); it != households.end(); ++it) {
372 2005 : it->generateCars(newRate);
373 2005 : 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 9 : }
386 :
387 : const AGStreet&
388 144 : 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 144 : if (!streetsCompleted) {
396 7 : statData.consolidateStat();
397 7 : 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 3198 : while (it != streets.end()) {
403 3198 : if ((*it)->getID() == edge) {
404 144 : return **it;
405 : }
406 : ++it;
407 : }
408 : std::cout << "===> ERROR: WRONG STREET EDGE (" << edge << ") given and not found in street set." << std::endl;
409 0 : throw ProcessError("Street not found with edge id " + edge);
410 : }
411 :
412 : const AGStreet&
413 3377 : AGCity::getRandomStreet() {
414 3377 : if (passengerStreets.empty()) {
415 2 : throw ProcessError(TL("No street that allows passenger vehicles found in this city."));
416 : }
417 3376 : return *RandHelper::getRandomFrom(passengerStreets);
418 : }
419 :
420 :
421 : /****************************************************************************/
|