Path: blob/main/src/activitygen/AGActivityGenHandler.cpp
169665 views
/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// activitygen module4// Copyright 2010 TUM (Technische Universitaet Muenchen, http://www.tum.de/)5// This program and the accompanying materials are made available under the6// terms of the Eclipse Public License 2.0 which is available at7// https://www.eclipse.org/legal/epl-2.0/8// This Source Code may also be made available under the following Secondary9// Licenses when the conditions for such availability set forth in the Eclipse10// Public License 2.0 are satisfied: GNU General Public License, version 211// or later which is available at12// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html13// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later14/****************************************************************************/15/// @file AGActivityGenHandler.cpp16/// @author Piotr Woznica17/// @author Daniel Krajzewicz18/// @author Jakob Erdmann19/// @author Michael Behrisch20/// @author Walter Bamberger21/// @date July 201022///23// The handler for parsing the statistics file.24/****************************************************************************/25#include <config.h>2627#include "AGActivityGenHandler.h"28#include <iostream>29#include <utility>30#include <map>31#include <string>32#include <utils/options/OptionsCont.h>33#include <utils/common/MsgHandler.h>34#include <utils/common/StringTokenizer.h>35#include <utils/common/UtilExceptions.h>36#include <utils/xml/SUMOSAXHandler.h>37#include <utils/xml/SUMOXMLDefinitions.h>38#include <router/RONet.h>39#include "city/AGCity.h"40#include "city/AGSchool.h"41#include "city/AGPosition.h"42#include "city/AGBusLine.h"434445// ===========================================================================46// method definitions47// ===========================================================================48AGActivityGenHandler::AGActivityGenHandler(AGCity& city, RONet* net)49: SUMOSAXHandler("sumo-stat"),50myCity(city), net(net) {}515253AGActivityGenHandler::~AGActivityGenHandler() {}545556void57AGActivityGenHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {58try {59switch (element) {60case AGEN_TAG_GENERAL:61parseGeneralCityInfo(attrs);62break;63case AGEN_TAG_STREET:64parseStreets(attrs);65break;66case AGEN_TAG_WORKHOURS:67parseWorkHours();68break;69case AGEN_TAG_OPENING:70parseOpeningHour(attrs);71break;72case AGEN_TAG_CLOSING:73parseClosingHour(attrs);74break;75case AGEN_TAG_SCHOOLS:76parseSchools();77break;78case AGEN_TAG_SCHOOL:79parseSchool(attrs);80break;81case AGEN_TAG_BUSSTATION:82parseBusStation(attrs);83break;84case AGEN_TAG_BUSLINE:85parseBusLine(attrs);86break;87case AGEN_TAG_STATIONS:88parseStations();89break;90case AGEN_TAG_REV_STATIONS:91parseRevStations();92break;93case AGEN_TAG_STATION:94parseStation(attrs);95break;96case AGEN_TAG_FREQUENCY:97parseFrequency(attrs);98break;99case AGEN_TAG_POPULATION:100parsePopulation();101break;102/*case AGEN_TAG_CHILD_ACOMP:103parseChildrenAccompaniment();104break;*/105case AGEN_TAG_BRACKET:106parseBracket(attrs);107break;108case AGEN_TAG_PARAM:109parseParameters(attrs);110break;111case AGEN_TAG_ENTRANCE:112parseCityGates(attrs);113break;114default:115break;116}117} catch (const std::exception& e) {118throw ProcessError(e.what());119}120}121122123void124AGActivityGenHandler::parseGeneralCityInfo(const SUMOSAXAttributes& attrs) {125try {126bool ok;127myCity.statData.inhabitants = attrs.getInt(AGEN_ATTR_INHABITANTS);128myCity.statData.households = attrs.getInt(AGEN_ATTR_HOUSEHOLDS);129myCity.statData.limitAgeChildren = attrs.getOpt<int>(AGEN_ATTR_CHILDREN, nullptr, ok, 18);130myCity.statData.limitAgeRetirement = attrs.getOpt<int>(AGEN_ATTR_RETIREMENT, nullptr, ok, 63);131myCity.statData.carRate = attrs.getOpt<double>(AGEN_ATTR_CARS, nullptr, ok, 0.58);132myCity.statData.unemployement = attrs.getOpt<double>(AGEN_ATTR_UNEMPLOYEMENT, nullptr, ok, 0.06);133myCity.statData.laborDemand = attrs.getOpt<double>(AGEN_ATTR_LABORDEMAND, nullptr, ok, 1.05);134myCity.statData.maxFootDistance = attrs.getOpt<double>(AGEN_ATTR_MAX_FOOT_DIST, nullptr, ok, 300.0);135myCity.statData.incomingTraffic = attrs.getOpt<int>(AGEN_ATTR_IN_TRAFFIC, nullptr, ok, 0);136myCity.statData.outgoingTraffic = attrs.getOpt<int>(AGEN_ATTR_OUT_TRAFFIC, nullptr, ok, 0);137} catch (const std::exception& e) {138WRITE_ERROR("Error while parsing the element " +139SUMOXMLDefinitions::Tags.getString(AGEN_TAG_GENERAL) + ": " +140e.what());141throw ProcessError();142}143}144145void146AGActivityGenHandler::parseParameters(const SUMOSAXAttributes& attrs) {147try {148bool ok;149myCity.statData.carPreference = attrs.getOpt<double>(AGEN_ATTR_CARPREF, nullptr, ok, 0.0);150myCity.statData.speedTimePerKm = attrs.getOpt<double>(AGEN_ATTR_CITYSPEED, nullptr, ok, 360.0);151myCity.statData.freeTimeActivityRate = attrs.getOpt<double>(AGEN_ATTR_FREETIMERATE, nullptr, ok, 0.15);152myCity.statData.uniformRandomTrafficRate = attrs.getOpt<double>(AGEN_ATTR_UNI_RAND_TRAFFIC, nullptr, ok, 0.0);153myCity.statData.departureVariation = attrs.getOpt<double>(AGEN_ATTR_DEP_VARIATION, nullptr, ok, 0.0);154} catch (const std::exception& e) {155WRITE_ERROR("Error while parsing the element " +156SUMOXMLDefinitions::Tags.getString(AGEN_TAG_PARAM) + ": " +157e.what());158throw ProcessError();159}160}161162void163AGActivityGenHandler::parseStreets(const SUMOSAXAttributes& attrs) {164try {165double pop = 0;166double work = 0;167168std::string eid = attrs.getString(SUMO_ATTR_EDGE);169if (attrs.hasAttribute(AGEN_ATTR_POPULATION)) {170pop = attrs.getFloat(AGEN_ATTR_POPULATION);171if (std::isnan(pop)) {172pop = 0;173WRITE_WARNINGF(TL("Invalid % value of edge % is treated as zero."), SUMOXMLDefinitions::Attrs.getString(AGEN_ATTR_POPULATION), eid);174}175}176if (attrs.hasAttribute(AGEN_ATTR_OUT_WORKPOSITION)) {177work = attrs.getFloat(AGEN_ATTR_OUT_WORKPOSITION);178if (std::isnan(work)) {179work = 0;180WRITE_WARNINGF(TL("Invalid % value of edge % is treated as zero."), SUMOXMLDefinitions::Attrs.getString(AGEN_ATTR_OUT_WORKPOSITION), eid);181}182}183AGStreet* street = dynamic_cast<AGStreet*>(net->getEdge(eid));184if (street == nullptr) {185WRITE_ERRORF(TL("Edge '%' is not known."), eid);186return;187}188street->setPopulation(pop * street->getLength());189street->setWorkplaceNumber(work * street->getLength());190myCity.streets.push_back(street);191} catch (const std::exception& e) {192WRITE_ERROR("Error while parsing the element " +193SUMOXMLDefinitions::Tags.getString(AGEN_TAG_STREET) + ": " +194e.what());195throw ProcessError();196}197}198199void200AGActivityGenHandler::parseCityGates(const SUMOSAXAttributes& attrs) {201try {202std::string edge = attrs.getString(SUMO_ATTR_EDGE);203double positionOnEdge = attrs.getFloat(SUMO_ATTR_POSITION);204AGPosition posi(myCity.getStreet(edge), positionOnEdge);205myCity.statData.incoming[(int)myCity.cityGates.size()] = attrs.getFloat(AGEN_ATTR_INCOMING);206myCity.statData.outgoing[(int)myCity.cityGates.size()] = attrs.getFloat(AGEN_ATTR_OUTGOING);207myCity.cityGates.push_back(posi);208209} catch (const std::exception& e) {210WRITE_ERROR("Error while parsing the element " +211SUMOXMLDefinitions::Tags.getString(AGEN_TAG_CITYGATES) + ": " +212e.what());213throw ProcessError();214}215}216217void218AGActivityGenHandler::parseWorkHours() {219myCurrentObject = "workHours";220}221222void223AGActivityGenHandler::parseOpeningHour(const SUMOSAXAttributes& attrs) {224if (myCurrentObject == "workHours") {225try {226myCity.statData.beginWorkHours[attrs.getInt(AGEN_ATTR_HOUR)] = attrs.getFloat(AGEN_ATTR_PROP);227228} catch (const std::exception& e) {229WRITE_ERROR("Error while parsing the element " +230SUMOXMLDefinitions::Tags.getString(AGEN_TAG_OPENING) + ": "231+ e.what());232throw ProcessError();233}234}235}236237void238AGActivityGenHandler::parseClosingHour(const SUMOSAXAttributes& attrs) {239if (myCurrentObject == "workHours") {240try {241myCity.statData.endWorkHours[attrs.getInt(AGEN_ATTR_HOUR)] = attrs.getFloat(AGEN_ATTR_PROP);242243} catch (const std::exception& e) {244WRITE_ERROR("Error while parsing the element " +245SUMOXMLDefinitions::Tags.getString(AGEN_TAG_CLOSING) + ": "246+ e.what());247throw ProcessError();248}249}250}251252void253AGActivityGenHandler::parseSchools() {254myCurrentObject = "schools";255}256257void258AGActivityGenHandler::parseSchool(const SUMOSAXAttributes& attrs) {259try {260bool ok = true;261std::string edge = attrs.getString(SUMO_ATTR_EDGE, &ok);262if (!ok) {263throw ProcessError("Cannot parse edge attribute");264}265double positionOnEdge = attrs.hasAttribute(SUMO_ATTR_POSITION) ? attrs.getFloat(SUMO_ATTR_POSITION) : 0.;266AGPosition posi(myCity.getStreet(edge), positionOnEdge);267int beginAge = attrs.getInt(AGEN_ATTR_BEGINAGE);268int endAge = attrs.getInt(AGEN_ATTR_ENDAGE);269int capacity = attrs.getInt(AGEN_ATTR_CAPACITY);270int openingHour = attrs.getInt(AGEN_ATTR_OPENING);271int closingHour = attrs.getInt(AGEN_ATTR_CLOSING);272AGSchool sch(capacity, posi, beginAge, endAge, openingHour, closingHour);273myCity.schools.push_back(sch);274275} catch (const std::exception& e) {276WRITE_ERROR("Error while parsing the element " +277SUMOXMLDefinitions::Tags.getString(AGEN_TAG_SCHOOL) + ": " +278e.what());279throw ProcessError();280}281}282283void284AGActivityGenHandler::parseBusStation(const SUMOSAXAttributes& attrs) {285try {286bool ok = true;287std::string edge = attrs.getString(SUMO_ATTR_EDGE, &ok);288if (!ok) {289throw ProcessError("Cannot parse edge attribute");290};291double positionOnEdge = attrs.hasAttribute(SUMO_ATTR_POSITION) ? attrs.getFloat(SUMO_ATTR_POSITION) : 0.;292int id = attrs.getInt(SUMO_ATTR_ID);293AGPosition posi(myCity.getStreet(edge), positionOnEdge);294myCity.statData.busStations.insert(std::pair<int, AGPosition>(id, posi));295296} catch (const std::exception& e) {297WRITE_ERROR("Error while parsing the element " +298SUMOXMLDefinitions::Tags.getString(AGEN_TAG_BUSSTATION) + ": " +299e.what());300throw ProcessError();301}302}303304void305AGActivityGenHandler::parseBusLine(const SUMOSAXAttributes& attrs) {306try {307myCurrentObject = "busLine";308AGBusLine busL(attrs.getString(SUMO_ATTR_ID));309busL.setMaxTripTime(attrs.getInt(AGEN_ATTR_MAX_TRIP_DURATION));310myCity.busLines.push_front(busL);311currentBusLine = &*myCity.busLines.begin();312313} catch (const std::exception& e) {314WRITE_ERROR("Error while parsing the element " +315SUMOXMLDefinitions::Tags.getString(AGEN_TAG_BUSLINE) + ": " +316e.what());317throw ProcessError();318}319}320321void322AGActivityGenHandler::parseStations() {323isRevStation = false;324}325326void327AGActivityGenHandler::parseRevStations() {328isRevStation = true;329}330331void332AGActivityGenHandler::parseStation(const SUMOSAXAttributes& attrs) {333if (myCurrentObject != "busLine") {334return;335}336337try {338bool ok = true;339int refID = attrs.get<int>(SUMO_ATTR_REFID, myCurrentObject.c_str(), ok);340if (!ok) {341throw ProcessError();342}343if (myCity.statData.busStations.count(refID) == 0) {344throw ProcessError(TLF("Unknown bus station '%'.", refID));345}346if (!isRevStation) {347currentBusLine->locateStation(myCity.statData.busStations.find(refID)->second);348} else {349currentBusLine->locateRevStation(myCity.statData.busStations.find(refID)->second);350}351352} catch (const std::exception& e) {353WRITE_ERROR("Error while parsing the element " +354SUMOXMLDefinitions::Tags.getString(AGEN_TAG_STATION) + ": " +355e.what());356throw ProcessError();357}358}359360void361AGActivityGenHandler::parseFrequency(const SUMOSAXAttributes& attrs) {362if (myCurrentObject != "busLine") {363return;364}365366try {367int beginB = attrs.getInt(SUMO_ATTR_BEGIN);368int endB = attrs.getInt(SUMO_ATTR_END);369int rateB = attrs.getInt(AGEN_ATTR_RATE);370currentBusLine->generateBuses(beginB, endB, rateB);371372} catch (const std::exception& e) {373WRITE_ERROR("Error while parsing the element " +374SUMOXMLDefinitions::Tags.getString(AGEN_TAG_FREQUENCY) + ": " +375e.what());376throw ProcessError();377}378}379380void381AGActivityGenHandler::parsePopulation() {382myCurrentObject = "population";383}384385void386AGActivityGenHandler::parseBracket(const SUMOSAXAttributes& attrs) {387try {388389int beginAge = attrs.getInt(AGEN_ATTR_BEGINAGE); //included in the bracket390int endAge = attrs.getInt(AGEN_ATTR_ENDAGE); //NOT included in the bracket391bool overlapping = false;392// evaluate age393if (beginAge < endAge) {394for (auto it = myCity.statData.ageSpan.begin(); it != myCity.statData.ageSpan.end(); ++it) {395if (!(beginAge >= it->second || endAge <= it->first)) {396overlapping = true;397}398}399if (!overlapping) {400myCity.statData.ageSpan[beginAge] = endAge;401402if (myCurrentObject == "population") {403myCity.statData.population[endAge] = attrs.getInt(AGEN_ATTR_PEOPLENBR);404}405} else {406WRITE_ERROR("Error while parsing the element " +407SUMOXMLDefinitions::Tags.getString(AGEN_TAG_BRACKET) + ": begin and end age of the population is overlapping");408throw ProcessError();409}410} else {411WRITE_ERROR("Error while parsing the element " +412SUMOXMLDefinitions::Tags.getString(AGEN_TAG_BRACKET) + ": begin and end age of the population are not properly set");413throw ProcessError();414}415416} catch (const std::exception& e) {417WRITE_ERROR("Error while parsing the element " +418SUMOXMLDefinitions::Tags.getString(AGEN_TAG_BRACKET) + ": " +419e.what());420throw ProcessError();421}422}423424425/****************************************************************************/426427428