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

          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 1.14