LCOV - code coverage report
Current view: top level - src/activitygen/activities - AGWorkAndSchool.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 80.5 % 154 124
Test Date: 2024-11-22 15:46:21 Functions: 90.9 % 11 10

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-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    AGWorkAndSchool.cpp
      17              : /// @author  Piotr Woznica
      18              : /// @author  Daniel Krajzewicz
      19              : /// @author  Michael Behrisch
      20              : /// @author  Walter Bamberger
      21              : /// @date    July 2010
      22              : ///
      23              : // Generates trips to work and to school
      24              : /****************************************************************************/
      25              : #include <config.h>
      26              : 
      27              : #include <list>
      28              : #include <utils/common/SUMOVehicleClass.h>
      29              : #include <activitygen/city/AGCar.h>
      30              : #include <activitygen/city/AGChild.h>
      31              : #include <activitygen/city/AGHousehold.h>
      32              : #include <activitygen/city/AGStreet.h>
      33              : #include <activitygen/city/AGWorkPosition.h>
      34              : #include "AGWorkAndSchool.h"
      35              : 
      36              : 
      37              : // ===========================================================================
      38              : // method definitions
      39              : // ===========================================================================
      40              : bool
      41         1506 : AGWorkAndSchool::generateTrips() {
      42              :     //buildDestinations();
      43              :     // generation of the waiting list for the accompaniment
      44         1506 :     buildChildrenAccompaniment();
      45              : 
      46         1506 :     buildWorkDestinations();
      47              : 
      48         1506 :     if (myHousehold->getCarNbr() < (int)personsDrivingCars.size()) {
      49              :         return false;    //to rebuild the household
      50              :     }
      51         1506 :     if (childrenNeedingCarAccompaniment.size() != 0 && myHousehold->getCarNbr() == 0) {
      52              :         return false;    //to rebuild the household
      53              :     }
      54         1506 :     if (adultNeedingCarAccompaniment.size() != 0 && myHousehold->getCarNbr() == 0) {
      55              :         return false;
      56              :     }
      57              : 
      58         1506 :     carAllocation();
      59              : 
      60         1506 :     if (personsDrivingCars.empty() && notNeedingDrivers.empty()) {
      61          969 :         genDone = true;
      62          969 :         return true; // no trip to generate
      63              :     }
      64              : 
      65          537 :     if (! carsToTrips()) {
      66              :         return false;
      67              :     }
      68              : 
      69          537 :     genDone = true;
      70          537 :     return true;
      71              : }
      72              : 
      73              : void
      74         1506 : AGWorkAndSchool::buildChildrenAccompaniment() {
      75              :     std::list<AGChild>::const_iterator itC;
      76         2076 :     for (itC = myHousehold->getChildren().begin(); itC != myHousehold->getChildren().end(); ++itC) {
      77          570 :         if (itC->haveASchool()) {
      78          570 :             if (this->availableTranspMeans(myHousehold->getPosition(), itC->getSchoolLocation()) == 0) {
      79              :                 //in this case the school is far from home and bus stations too
      80           74 :                 this->childrenNeedingCarAccompaniment.push_back(*itC);
      81              :             }
      82              :         }
      83              :     }
      84         1506 : }
      85              : 
      86              : void
      87         1506 : AGWorkAndSchool::buildWorkDestinations() {
      88              :     std::list<AGAdult>::const_iterator itA;
      89         3942 :     for (itA = myHousehold->getAdults().begin(); itA != myHousehold->getAdults().end(); ++itA) {
      90         2436 :         if (itA->isWorking()) {
      91         1622 :             if (this->possibleTranspMean(itA->getWorkPosition().getPosition()) % 2 == 0) {
      92              :                 //not too close, to not being able to go by foot
      93         1325 :                 if (this->possibleTranspMean(itA->getWorkPosition().getPosition()) > 4) {
      94              :                     //too far from home ==> Car or Bus AND Car and bus are possible
      95          736 :                     workingPeoplePossCar.push_back(*itA);
      96          589 :                 } else if (this->possibleTranspMean(itA->getWorkPosition().getPosition()) == 4) {
      97              :                     //only the car is possible (and there is one (use of possibleTranspMean))
      98          279 :                     if (myHousehold->getCarNbr() > (int)personsDrivingCars.size()) {
      99          245 :                         personsDrivingCars.push_back(*itA);
     100              :                     } else {
     101           34 :                         adultNeedingCarAccompaniment.push_back(*itA);
     102              :                     }
     103              :                 }
     104              :             }
     105              :         }
     106              :     }
     107              : 
     108              :     // sometimes, people still have choice: when vehicles are available and their car take a bus.
     109              :     std::list<AGAdult>::iterator it;
     110         2242 :     for (it = workingPeoplePossCar.begin(); it != workingPeoplePossCar.end(); ++it) {
     111          736 :         if (possibleTranspMean(it->getWorkPosition().getPosition()) == 6 && myHousehold->getCarNbr() > (int)personsDrivingCars.size()) {
     112              :             //car or bus (always because of workDestinations' construction) AND at least one car not used
     113          634 :             if (myHousehold->getAdults().front().decide(this->carPreference)) {
     114          332 :                 personsDrivingCars.push_back(*it);
     115              :             }
     116              :         }
     117              :     }
     118         1506 : }
     119              : 
     120              : void
     121         1506 : AGWorkAndSchool::carAllocation() {
     122              :     // only two adults are possibles: no car, 1 car, 2 cars and more
     123              :     // the only choice case: 1 car / 2 adults needing this car (otherwise no choice problems)
     124         1506 :     if (! personsDrivingCars.empty() && ! adultNeedingCarAccompaniment.empty()) {
     125              :         //in that case there is only one element in each list and only one car.
     126           34 :         if (adultNeedingCarAccompaniment.front().getWorkPosition().getOpening() >= personsDrivingCars.front().getWorkPosition().getOpening()) {
     127              :             //we will invert the driver and the accompanied
     128           25 :             personsDrivingCars.push_back(adultNeedingCarAccompaniment.front());
     129           25 :             adultNeedingCarAccompaniment.pop_front();
     130              :             adultNeedingCarAccompaniment.push_back(personsDrivingCars.front());
     131              :             personsDrivingCars.pop_front();
     132              :         }
     133              :     }
     134         1506 :     if (personsDrivingCars.empty() && ! childrenNeedingCarAccompaniment.empty()) {
     135              :         //at least one adult exists because no household contains less than one adult
     136           16 :         if ((int)workingPeoplePossCar.size() != myHousehold->getAdultNbr()) { //personsDrivingCars.size() + adultNeedingCarAccompaniment.size() is equal to 0
     137              :             std::list<AGAdult>::const_iterator itUA;
     138           18 :             for (itUA = myHousehold->getAdults().begin(); itUA != myHousehold->getAdults().end(); ++itUA) {
     139           18 :                 if (! itUA->isWorking()) {
     140           16 :                     notNeedingDrivers.push_back(*itUA);
     141              :                     break;
     142              :                 }
     143              :             }
     144              :         } else {
     145            0 :             personsDrivingCars.push_back(workingPeoplePossCar.front());
     146            0 :             workingPeoplePossCar.pop_front();
     147              :         }
     148              :     }
     149         1506 : }
     150              : 
     151              : bool
     152          537 : AGWorkAndSchool::carsToTrips() {
     153              :     // check if the starting edge allows cars
     154          537 :     if (!myHousehold->getPosition().getStreet().allows(SVC_PASSENGER)) {
     155              :         return false;
     156              :     }
     157              :     std::list<AGAdult>::const_iterator itDriA;
     158          537 :     std::list<AGCar>::const_iterator itCar = myHousehold->getCars().begin();
     159         1114 :     for (itDriA = personsDrivingCars.begin(); itDriA != personsDrivingCars.end(); ++itDriA) {
     160              :         //check if the number of cars is lower than the number of drivers
     161          577 :         if (itCar == myHousehold->getCars().end()) {
     162            0 :             return false;
     163              :         }
     164              :         // check if the destination edge allows cars
     165          577 :         if (!itDriA->getWorkPosition().getPosition().getStreet().allows(SVC_PASSENGER)) {
     166              :             return false;
     167              :         }
     168         1154 :         AGTrip trip(myHousehold->getPosition(), itDriA->getWorkPosition().getPosition(), *itCar, depHour(myHousehold->getPosition(), itDriA->getWorkPosition().getPosition(), itDriA->getWorkPosition().getOpening()));
     169              :         ++itCar;
     170          577 :         tempTrip.push_back(trip);
     171          577 :     }
     172              : 
     173              :     std::list<AGAdult>::iterator itAccA;
     174          571 :     for (itAccA = adultNeedingCarAccompaniment.begin(); itAccA != adultNeedingCarAccompaniment.end(); ++itAccA) {
     175           34 :         AGTrip trip(myHousehold->getPosition(), itAccA->getWorkPosition().getPosition(), depHour(myHousehold->getPosition(), itAccA->getWorkPosition().getPosition(), itAccA->getWorkPosition().getOpening()));
     176           34 :         tempAccTrip.push_back(trip);
     177           34 :     }
     178              : 
     179              :     std::list<AGChild>::iterator itAccC;
     180          611 :     for (itAccC = childrenNeedingCarAccompaniment.begin(); itAccC != childrenNeedingCarAccompaniment.end(); ++itAccC) {
     181           74 :         AGTrip trip(myHousehold->getPosition(), itAccC->getSchoolLocation(), depHour(myHousehold->getPosition(), itAccC->getSchoolLocation(), itAccC->getSchoolOpening()));
     182           74 :         tempAccTrip.push_back(trip);
     183           74 :     }
     184              : 
     185          537 :     checkAndBuildTripConsistancy();
     186          537 :     if (isThereUnusedCar() && ! checkDriversScheduleMatching()) {
     187            0 :         makePossibleDriversDrive();
     188              :     }
     189              : 
     190          537 :     generateListTrips();
     191              :     return true;
     192              : }
     193              : 
     194              : bool
     195          537 : AGWorkAndSchool::isThereUnusedCar() {
     196          537 :     return (myHousehold->getCarNbr() > static_cast<int>(notNeedingDrivers.size() + personsDrivingCars.size()));
     197              : }
     198              : 
     199              : bool
     200          537 : AGWorkAndSchool::checkAndBuildTripConsistancy() {
     201              :     bool finish = false;
     202              :     int diff1, diff2;
     203              :     int arrTime;
     204              :     std::list<AGTrip>::iterator it1, it2;
     205              : 
     206         1103 :     while (!finish) {
     207              :         finish = true;
     208          645 :         for (it1 = tempAccTrip.begin(); it1 != tempAccTrip.end(); ++it1) {
     209          216 :             for (it2 = tempAccTrip.begin(); it2 != tempAccTrip.end(); ++it2) {
     210          137 :                 if (it1 == it2) {
     211          108 :                     continue;
     212              :                 }
     213           29 :                 diff1 = it2->getTime() - it1->getRideBackArrTime(this->timePerKm);
     214           29 :                 diff2 = it1->getTime() - it2->getRideBackArrTime(this->timePerKm);
     215              : 
     216           29 :                 if (diff1 < 0 || diff2 < 0) {
     217           29 :                     if (diff2 < diff1) {
     218           12 :                         arrTime = it2->getArrTime(this->timePerKm);
     219           12 :                         it2->addLayOver(*it1);
     220           12 :                         it2->setDepTime(it2->estimateDepTime(arrTime, this->timePerKm));
     221           12 :                         tempAccTrip.erase(it1);
     222              :                     } else {
     223           17 :                         arrTime = it1->getArrTime(this->timePerKm);
     224           17 :                         it1->addLayOver(*it2);
     225           17 :                         it1->setDepTime(it1->estimateDepTime(arrTime, this->timePerKm));
     226           17 :                         tempAccTrip.erase(it2);
     227              :                     }
     228              :                     finish = false;
     229              :                     break;
     230              :                 }
     231              :             }
     232              :             if (!finish) {
     233              :                 break; // return to while
     234              :             }
     235              :         }
     236              :     }
     237          537 :     return finish;
     238              : }
     239              : 
     240              : bool
     241           99 : AGWorkAndSchool::checkDriversScheduleMatching() {
     242              :     bool check = false;
     243              :     std::list<AGTrip>::iterator itAccT;
     244              :     std::list<AGTrip>::iterator itDriT;
     245              :     std::list<AGAdult>::iterator itA;
     246          111 :     for (itAccT = tempAccTrip.begin(); itAccT != tempAccTrip.end(); ++itAccT) {
     247           14 :         for (itDriT = tempTrip.begin(); itDriT != tempTrip.end(); ++itDriT) {
     248            2 :             if (itAccT->getArrTime(this->timePerKm) < itDriT->getArrTime(this->timePerKm)) {
     249              :                 check = true;
     250              :             }
     251              :         }
     252           22 :         for (itA = notNeedingDrivers.begin(); itA != notNeedingDrivers.end(); ++itA) {
     253           10 :             if (!itA->isWorking()) {
     254              :                 check = true;
     255            0 :             } else if (itAccT->getRideBackArrTime(this->timePerKm) < itA->getWorkPosition().getOpening()) {
     256              :                 check = true;
     257              :             }
     258              :         }
     259           12 :         if (!check) { //at least one trip is not performed by the existing drivers because it is to late for them
     260              :             return false;
     261              :         }
     262              :         check = false;
     263              :     }
     264              :     return true;
     265              : }
     266              : 
     267              : void
     268          537 : AGWorkAndSchool::generateListTrips() {
     269              :     int arrTime;
     270              :     std::list<AGTrip>::iterator itAccT;
     271              :     std::list<AGTrip>::iterator itDriT;
     272              :     std::list<AGAdult>::iterator itA;
     273              :     bool alreadyDone;
     274              : 
     275              :     /**
     276              :      * 1 / 3 : Accompaniment
     277              :      */
     278          616 :     for (itAccT = tempAccTrip.begin(); itAccT != tempAccTrip.end(); ++itAccT) {
     279              :         alreadyDone = false;
     280          155 :         for (itDriT = tempTrip.begin(); itDriT != tempTrip.end(); ++itDriT) {
     281           76 :             if (!alreadyDone) {
     282           70 :                 if (itAccT->getArrTime(this->timePerKm) < itDriT->getArrTime(this->timePerKm) && !alreadyDone) {
     283              :                     //Add the accompaniment trip to the driver's trip OR new trip
     284           28 :                     if (itAccT->getRideBackArrTime(this->timePerKm) < itDriT->getTime()) {
     285              :                         //there is enough time to accompany people and go back home before going to work
     286           56 :                         itAccT->setVehicleName(itDriT->getVehicleName());
     287           28 :                         itAccT->addLayOver(itAccT->getArr());//final destination is the last accompaniment stop: not the destination of the course
     288           28 :                         itAccT->setArr(myHousehold->getPosition());//final destination of the whole trip: home
     289           28 :                         myPartialActivityTrips.push_back(*itAccT);
     290              :                         alreadyDone = true;
     291              :                     } else {
     292              :                         //the driver drives people to their working place or school and goes directly to work after that
     293            0 :                         arrTime = itDriT->getArrTime(this->timePerKm);
     294            0 :                         itDriT->addLayOver(*itAccT);
     295            0 :                         itDriT->setDepTime(itDriT->estimateDepTime(arrTime, this->timePerKm));
     296              :                         //tempAccTrip.erase(itAccT);
     297              :                         //--itAccT; //because of erasure
     298              :                         alreadyDone = true;
     299              :                     }
     300              :                 }
     301              :             }
     302              :         }
     303              : 
     304           95 :         for (itA = notNeedingDrivers.begin(); itA != notNeedingDrivers.end(); ++itA) {
     305           16 :             if (!itA->isWorking() && !alreadyDone) {
     306           16 :                 std::string nameC = getUnusedCar();
     307           16 :                 if (nameC.size() != 0) {
     308            0 :                     itAccT->setVehicleName(getUnusedCar());
     309            0 :                     itAccT->addLayOver(itAccT->getArr());
     310            0 :                     itAccT->setArr(myHousehold->getPosition());
     311            0 :                     myPartialActivityTrips.push_back(*itAccT);
     312              :                     alreadyDone = true;
     313              :                 }
     314            0 :             } else if (itAccT->getRideBackArrTime(this->timePerKm) < itA->getWorkPosition().getOpening() && !alreadyDone) {
     315            0 :                 std::string nameC = getUnusedCar();
     316            0 :                 if (nameC.size() != 0) {
     317            0 :                     itAccT->setVehicleName(getUnusedCar());
     318            0 :                     itAccT->addLayOver(itAccT->getArr());
     319            0 :                     itAccT->setArr(myHousehold->getPosition());
     320            0 :                     myPartialActivityTrips.push_back(*itAccT);
     321              :                     alreadyDone = true;
     322              :                 }
     323              :             }
     324              :         }
     325              :     }
     326              : 
     327              :     /**
     328              :      * 2/3 : drivers way
     329              :      */
     330         1114 :     for (itDriT = tempTrip.begin(); itDriT != tempTrip.end(); ++itDriT) {
     331          577 :         myPartialActivityTrips.push_back(*itDriT);
     332              :     }
     333              : 
     334              :     /**
     335              :      * 3/3: way return
     336              :      */
     337         1114 :     for (itA = personsDrivingCars.begin(); itA != personsDrivingCars.end(); ++itA) {
     338          577 :         for (itDriT = tempTrip.begin(); itDriT != tempTrip.end(); ++itDriT) {
     339          577 :             if (itA->getWorkPosition().getPosition() == itDriT->getArr()) {
     340         1154 :                 AGTrip trip(itA->getWorkPosition().getPosition(), myHousehold->getPosition(), itDriT->getVehicleName(), itA->getWorkPosition().getClosing());
     341          577 :                 myPartialActivityTrips.push_back(trip);
     342          577 :                 tempTrip.erase(itDriT);
     343              :                 break;
     344          577 :             }
     345              :         }
     346              :     }
     347          537 : }
     348              : 
     349              : std::string
     350           16 : AGWorkAndSchool::getUnusedCar() {
     351           16 :     std::string nameCar = "";
     352           16 :     std::string nameCarUsed = "";
     353              :     //only two cars can be used in the household, so: the first one or the last one is not used.
     354           16 :     if (!tempTrip.empty()) {
     355            0 :         nameCarUsed = tempTrip.front().getVehicleName();
     356           16 :     } else if (!myPartialActivityTrips.empty()) {
     357            0 :         nameCarUsed = myPartialActivityTrips.front().getVehicleName();
     358              :     }
     359              : 
     360           16 :     if (nameCarUsed.size() != 0) {
     361            0 :         if (myHousehold->getCars().front().getName() == nameCarUsed) {
     362            0 :             nameCar = myHousehold->getCars().back().getName();
     363              :         } else {
     364            0 :             nameCar = myHousehold->getCars().front().getName();
     365              :         }
     366              :     }
     367           16 :     return nameCar;
     368              : }
     369              : 
     370              : void
     371            0 : AGWorkAndSchool::makePossibleDriversDrive() {
     372              :     //give to a non working adult the ability to drive children or someone else.
     373            0 :     if ((int)(workingPeoplePossCar.size() + personsDrivingCars.size() + adultNeedingCarAccompaniment.size()) != myHousehold->getAdultNbr()) {
     374              :         std::list<AGAdult>::const_iterator itUA;
     375            0 :         for (itUA = myHousehold->getAdults().begin(); itUA != myHousehold->getAdults().end(); ++itUA) {
     376            0 :             if (! itUA->isWorking()) {
     377            0 :                 notNeedingDrivers.push_back(*itUA);
     378              :                 break;
     379              :             }
     380              :         }
     381              :     }
     382            0 : }
     383              : 
     384              : 
     385              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1