LCOV - code coverage report
Current view: top level - src/activitygen/city - AGCity.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 94.7 % 170 161
Test Date: 2024-11-22 15:46:21 Functions: 100.0 % 11 11

            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              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1