| #include "engine/engine.h" |
| #include "utility/utility.h" |
|
|
| #include <algorithm> |
| #include <cmath> |
| #include <limits> |
| #include <iostream> |
| #include <memory> |
|
|
| #include <ctime> |
| namespace CityFlow { |
|
|
| Engine::Engine(const std::string &configFile, int threadNum) : threadNum(threadNum), startBarrier(threadNum + 1), |
| endBarrier(threadNum + 1) { |
| for (int i = 0; i < threadNum; i++) { |
| threadVehiclePool.emplace_back(); |
| threadRoadPool.emplace_back(); |
| threadIntersectionPool.emplace_back(); |
| threadDrivablePool.emplace_back(); |
| } |
| bool success = loadConfig(configFile); |
| if (!success) { |
| std::cerr << "load config failed!" << std::endl; |
| } |
|
|
| for (int i = 0; i < threadNum; i++) { |
| threadPool.emplace_back(&Engine::threadController, this, |
| std::ref(threadVehiclePool[i]), |
| std::ref(threadRoadPool[i]), |
| std::ref(threadIntersectionPool[i]), |
| std::ref(threadDrivablePool[i])); |
| } |
|
|
| } |
|
|
|
|
| bool Engine::loadConfig(const std::string &configFile) { |
| rapidjson::Document document; |
| if (!readJsonFromFile(configFile, document)) { |
| std::cerr << "cannot open config file!" << std::endl; |
| return false; |
| } |
|
|
| if (!document.IsObject()) { |
| std::cerr << "wrong format of config file" << std::endl; |
| return false; |
| } |
|
|
| try { |
| interval = getJsonMember<double>("interval", document); |
| warnings = false; |
| rlTrafficLight = getJsonMember<bool>("rlTrafficLight", document); |
| laneChange = getJsonMember<bool>("laneChange", document, false); |
| seed = getJsonMember<int>("seed", document); |
| rnd.seed(seed); |
| dir = getJsonMember<const char*>("dir", document); |
| std::string roadnetFile = getJsonMember<const char*>("roadnetFile", document); |
| std::string flowFile = getJsonMember<const char*>("flowFile", document); |
|
|
| if (!loadRoadNet(dir + roadnetFile)) { |
| std::cerr << "loading roadnet file error!" << std::endl; |
| return false; |
| } |
|
|
| if (!loadFlow(dir + flowFile)) { |
| std::cerr << "loading flow file error!" << std::endl; |
| return false; |
| } |
|
|
| if (warnings) checkWarning(); |
| saveReplayInConfig = saveReplay = getJsonMember<bool>("saveReplay", document); |
|
|
| if (saveReplay) { |
| std::string roadnetLogFile = getJsonMember<const char*>("roadnetLogFile", document); |
| std::string replayLogFile = getJsonMember<const char*>("replayLogFile", document); |
| setLogFile(dir + roadnetLogFile, dir + replayLogFile); |
| } |
| } catch (const JsonFormatError &e) { |
| std::cerr << e.what() << std::endl; |
| return false; |
| } |
| stepLog = ""; |
| return true; |
| } |
|
|
| bool Engine::loadRoadNet(const std::string &jsonFile) { |
| bool ans = roadnet.loadFromJson(jsonFile); |
| int cnt = 0; |
| for (Road &road : roadnet.getRoads()) { |
| threadRoadPool[cnt].push_back(&road); |
| cnt = (cnt + 1) % threadNum; |
| } |
| for (Intersection &intersection : roadnet.getIntersections()) { |
| threadIntersectionPool[cnt].push_back(&intersection); |
| cnt = (cnt + 1) % threadNum; |
| } |
| for (Drivable *drivable : roadnet.getDrivables()) { |
| threadDrivablePool[cnt].push_back(drivable); |
| cnt = (cnt + 1) % threadNum; |
| } |
| jsonRoot.SetObject(); |
| jsonRoot.AddMember("static", roadnet.convertToJson(jsonRoot.GetAllocator()), jsonRoot.GetAllocator()); |
| return ans; |
| } |
|
|
| bool Engine::loadFlow(const std::string &jsonFilename) { |
| rapidjson::Document root; |
| if (!readJsonFromFile(jsonFilename, root)) { |
| std::cerr << "cannot open flow file!" << std::endl; |
| return false; |
| } |
| std::list<std::string> path; |
| try { |
| if (!root.IsArray()) |
| throw JsonTypeError("flow file", "array"); |
| for (rapidjson::SizeType i = 0; i < root.Size(); i++) { |
| path.emplace_back("flow[" + std::to_string(i) + "]"); |
| rapidjson::Value &flow = root[i]; |
| std::vector<Road *> roads; |
| const auto &routes = getJsonMemberArray("route", flow); |
| roads.reserve(routes.Size()); |
| for (auto &route: routes.GetArray()) { |
| path.emplace_back("route[" + std::to_string(roads.size()) + "]"); |
| if (!route.IsString()) |
| throw JsonTypeError("route", "string"); |
| std::string roadName = route.GetString(); |
| auto road = roadnet.getRoadById(roadName); |
| if (!road) |
| throw JsonFormatError("No such road: " + roadName); |
| roads.push_back(road); |
| path.pop_back(); |
| } |
| auto route = std::make_shared<const Route>(roads); |
|
|
| VehicleInfo vehicleInfo; |
| const auto &vehicle = getJsonMemberObject("vehicle", flow); |
| vehicleInfo.len = getJsonMember<double>("length", vehicle); |
| vehicleInfo.width = getJsonMember<double>("width", vehicle); |
| vehicleInfo.maxPosAcc = getJsonMember<double>("maxPosAcc", vehicle); |
| vehicleInfo.maxNegAcc = getJsonMember<double>("maxNegAcc", vehicle); |
| vehicleInfo.usualPosAcc = getJsonMember<double>("usualPosAcc", vehicle); |
| vehicleInfo.usualNegAcc = getJsonMember<double>("usualNegAcc", vehicle); |
| vehicleInfo.minGap = getJsonMember<double>("minGap", vehicle); |
| vehicleInfo.maxSpeed = getJsonMember<double>("maxSpeed", vehicle); |
| vehicleInfo.headwayTime = getJsonMember<double>("headwayTime", vehicle); |
| vehicleInfo.route = route; |
| int startTime = getJsonMember<int>("startTime", flow, 0); |
| int endTime = getJsonMember<int>("endTime", flow, -1); |
| Flow newFlow(vehicleInfo, getJsonMember<double>("interval", flow), this, startTime, endTime, |
| "flow_" + std::to_string(i)); |
| flows.push_back(newFlow); |
| path.pop_back(); |
| } |
| assert(path.empty()); |
| } catch (const JsonFormatError &e) { |
| std::cerr << "Error occurred when reading flow file" << std::endl; |
| for (const auto &node : path) { |
| std::cerr << "/" << node; |
| } |
| std::cerr << " " << e.what() << std::endl; |
| return false; |
| } |
| return true; |
| } |
|
|
| bool Engine::checkWarning() { |
| bool result = true; |
|
|
| if (interval < 0.2 || interval > 1.5) { |
| std::cerr << "Deprecated time interval, recommended interval between 0.2 and 1.5" << std::endl; |
| result = false; |
| } |
|
|
| for (Lane *lane : roadnet.getLanes()) { |
| if (lane->getLength() < 50) { |
| std::cerr << "Deprecated road length, recommended road length at least 50 meters" << std::endl; |
| result = false; |
| } |
| if (lane->getMaxSpeed() > 30) { |
| std::cerr << "Deprecated road max speed, recommended max speed at most 30 meters/s" << std::endl; |
| result = false; |
| } |
| } |
|
|
| return result; |
| } |
|
|
| void Engine::vehicleControl(Vehicle &vehicle, std::vector<std::pair<Vehicle *, double>> &buffer) { |
| double nextSpeed; |
| if (vehicle.hasSetSpeed()) |
| nextSpeed = vehicle.getBufferSpeed(); |
| else |
| nextSpeed = vehicle.getNextSpeed(interval).speed; |
|
|
| if (laneChange) { |
| Vehicle * partner = vehicle.getPartner(); |
| if (partner != nullptr && !partner->hasSetSpeed()){ |
| double partnerSpeed = partner->getNextSpeed(interval).speed; |
| nextSpeed = min2double(nextSpeed, partnerSpeed); |
| partner->setSpeed(nextSpeed); |
|
|
| if (partner->hasSetEnd()) |
| vehicle.setEnd(true); |
| } |
| } |
|
|
| if (vehicle.getPartner()) { |
| assert(vehicle.getDistance() == vehicle.getPartner()->getDistance()); |
|
|
| } |
|
|
| double deltaDis, speed = vehicle.getSpeed(); |
|
|
| if (nextSpeed < 0) { |
| deltaDis = 0.5 * speed * speed / vehicle.getMaxNegAcc(); |
| nextSpeed = 0; |
| } else { |
| deltaDis = (speed + nextSpeed) * interval / 2; |
| } |
| vehicle.setSpeed(nextSpeed); |
| vehicle.setDeltaDistance(deltaDis); |
|
|
| if (laneChange) { |
| if (!vehicle.isReal() && vehicle.getChangedDrivable() != nullptr) { |
| vehicle.abortLaneChange(); |
| } |
|
|
| if (vehicle.isChanging()) { |
| assert(vehicle.isReal()); |
|
|
| int dir = vehicle.getLaneChangeDirection(); |
| double newOffset = fabs(vehicle.getOffset() + max2double(0.2 * nextSpeed, 1) * interval * dir); |
| newOffset = min2double(newOffset, vehicle.getMaxOffset()); |
| vehicle.setOffset(newOffset * dir); |
|
|
| if (newOffset >= vehicle.getMaxOffset()) { |
| std::lock_guard<std::mutex> guard(lock); |
| vehicleMap.erase(vehicle.getPartner()->getId()); |
| vehicleMap[vehicle.getId()] = vehicle.getPartner(); |
| vehicle.finishChanging(); |
| } |
|
|
| } |
| } |
|
|
|
|
| if (!vehicle.hasSetEnd() && vehicle.hasSetDrivable()) { |
| buffer.emplace_back(&vehicle, vehicle.getBufferDis()); |
| } |
|
|
| } |
|
|
| void Engine::threadController(std::set<Vehicle *> &vehicles, |
| std::vector<Road *> &roads, |
| std::vector<Intersection *> &intersections, |
| std::vector<Drivable *> &drivables) { |
| while (!finished) { |
| threadPlanRoute(roads); |
| if (laneChange) { |
| threadInitSegments(roads); |
| threadPlanLaneChange(vehicles); |
| threadUpdateLeaderAndGap(drivables); |
| } |
| threadNotifyCross(intersections); |
| threadGetAction(vehicles); |
| threadUpdateLocation(drivables); |
| threadUpdateAction(vehicles); |
| threadUpdateLeaderAndGap(drivables); |
| } |
| } |
|
|
| void Engine::threadPlanRoute(const std::vector<Road *> &roads) { |
| startBarrier.wait(); |
| for (auto &road : roads) { |
| for (auto &vehicle : road->getPlanRouteBuffer()) { |
| vehicle->updateRoute(); |
| } |
| } |
| endBarrier.wait(); |
| } |
|
|
| void Engine::threadUpdateLocation(const std::vector<Drivable *> &drivables) { |
| startBarrier.wait(); |
| for (Drivable *drivable : drivables) { |
| auto &vehicles = drivable->getVehicles(); |
| auto vehicleItr = vehicles.begin(); |
| while (vehicleItr != vehicles.end()) { |
| Vehicle *vehicle = *vehicleItr; |
|
|
| if ((vehicle->getChangedDrivable()) != nullptr || vehicle->hasSetEnd()) { |
| vehicleItr = vehicles.erase(vehicleItr); |
| }else{ |
| vehicleItr++; |
| } |
|
|
| if (vehicle->hasSetEnd()) { |
| std::lock_guard<std::mutex> guard(lock); |
| vehicleRemoveBuffer.insert(vehicle); |
| if (!vehicle->getLaneChange()->hasFinished()) { |
| vehicleMap.erase(vehicle->getId()); |
| finishedVehicleCnt += 1; |
| cumulativeTravelTime += getCurrentTime() - vehicle->getEnterTime(); |
| } |
| auto iter = vehiclePool.find(vehicle->getPriority()); |
| threadVehiclePool[iter->second.second].erase(vehicle); |
| |
| delete vehicle; |
| vehiclePool.erase(iter); |
| activeVehicleCount--; |
| } |
|
|
| } |
| } |
| endBarrier.wait(); |
| } |
|
|
| void Engine::threadNotifyCross(const std::vector<Intersection *> &intersections) { |
| |
| startBarrier.wait(); |
| for (Intersection *intersection : intersections) |
| for (Cross &cross : intersection->getCrosses()) |
| cross.clearNotify(); |
|
|
| for (Intersection *intersection : intersections) |
| for (LaneLink *laneLink : intersection->getLaneLinks()) { |
| |
| const auto &crosses = laneLink->getCrosses(); |
| auto rIter = crosses.rbegin(); |
|
|
| |
| Vehicle *vehicle = laneLink->getEndLane()->getLastVehicle(); |
| if (vehicle && static_cast<LaneLink *>(vehicle->getPrevDrivable()) == laneLink) { |
| double vehDistance = vehicle->getDistance() - vehicle->getLen(); |
| while (rIter != crosses.rend()) { |
| double crossDistance = laneLink->getLength() - (*rIter)->getDistanceByLane(laneLink); |
| if (crossDistance + vehDistance < (*rIter)->getLeaveDistance()) { |
| (*rIter)->notify(laneLink, vehicle, -(vehicle->getDistance() + crossDistance)); |
| ++rIter; |
| } else break; |
| } |
| } |
|
|
| |
| for (Vehicle *linkVehicle : laneLink->getVehicles()) { |
| double vehDistance = linkVehicle->getDistance(); |
|
|
| while (rIter != crosses.rend()) { |
| double crossDistance = (*rIter)->getDistanceByLane(laneLink); |
| if (vehDistance > crossDistance) { |
| if (vehDistance - crossDistance - linkVehicle->getLen() <= |
| (*rIter)->getLeaveDistance()) { |
| (*rIter)->notify(laneLink, linkVehicle, crossDistance - vehDistance); |
| } else break; |
| } else { |
| (*rIter)->notify(laneLink, linkVehicle, crossDistance - vehDistance); |
| } |
| ++rIter; |
| } |
| } |
|
|
| |
| vehicle = laneLink->getStartLane()->getFirstVehicle(); |
| if (vehicle && static_cast<LaneLink *>(vehicle->getNextDrivable()) == laneLink && laneLink->isAvailable()) { |
| double vehDistance = laneLink->getStartLane()->getLength() - vehicle->getDistance(); |
| while (rIter != crosses.rend()) { |
| (*rIter)->notify(laneLink, vehicle, vehDistance + (*rIter)->getDistanceByLane(laneLink)); |
| ++rIter; |
| } |
| } |
| } |
| endBarrier.wait(); |
| } |
|
|
| void Engine::threadPlanLaneChange(const std::set<CityFlow::Vehicle *> &vehicles) { |
| startBarrier.wait(); |
| std::vector<CityFlow::Vehicle *> buffer; |
|
|
| for (auto vehicle : vehicles) |
| if (vehicle->isRunning() && vehicle->isReal()) { |
| vehicle->makeLaneChangeSignal(interval); |
| if (vehicle->planLaneChange()){ |
| buffer.emplace_back(vehicle); |
| } |
| } |
| { |
| std::lock_guard<std::mutex> guard(lock); |
| laneChangeNotifyBuffer.insert(laneChangeNotifyBuffer.end(), buffer.begin(), buffer.end()); |
| } |
| endBarrier.wait(); |
| } |
|
|
| void Engine::threadInitSegments(const std::vector<Road *> &roads) { |
| startBarrier.wait(); |
| for (Road *road : roads) |
| for (Lane &lane : road->getLanes()) { |
| lane.initSegments(); |
| } |
| endBarrier.wait(); |
| } |
|
|
|
|
| void Engine::threadGetAction(std::set<Vehicle *> &vehicles) { |
| startBarrier.wait(); |
| std::vector<std::pair<Vehicle *, double>> buffer; |
| for (auto vehicle: vehicles) |
| if (vehicle->isRunning()) |
| vehicleControl(*vehicle, buffer); |
| { |
| std::lock_guard<std::mutex> guard(lock); |
| pushBuffer.insert(pushBuffer.end(), buffer.begin(), buffer.end()); |
| } |
| endBarrier.wait(); |
| } |
|
|
| void Engine::threadUpdateAction(std::set<Vehicle *> &vehicles) { |
| startBarrier.wait(); |
| for (auto vehicle: vehicles) |
| if (vehicle->isRunning()) { |
| if (vehicleRemoveBuffer.count(vehicle->getBufferBlocker())){ |
| vehicle->setBlocker(nullptr); |
| } |
|
|
| vehicle->update(); |
| vehicle->clearSignal(); |
| } |
| endBarrier.wait(); |
| } |
|
|
| void Engine::threadUpdateLeaderAndGap(const std::vector<Drivable *> &drivables) { |
| startBarrier.wait(); |
| for (Drivable *drivable : drivables) { |
| Vehicle *leader = nullptr; |
| for (Vehicle *vehicle : drivable->getVehicles()) { |
| vehicle->updateLeaderAndGap(leader); |
| leader = vehicle; |
| } |
| if (drivable->isLane()){ |
| static_cast<Lane *>(drivable)->updateHistory(); |
| } |
| } |
| endBarrier.wait(); |
| } |
|
|
| void Engine::planLaneChange() { |
| startBarrier.wait(); |
| endBarrier.wait(); |
| scheduleLaneChange(); |
| } |
|
|
| void Engine::planRoute() { |
| startBarrier.wait(); |
| endBarrier.wait(); |
| for (auto &road : roadnet.getRoads()) { |
| for (auto &vehicle : road.getPlanRouteBuffer()) |
| if (vehicle->isRouteValid()) { |
| vehicle->setFirstDrivable(); |
| vehicle->getCurLane()->pushWaitingVehicle(vehicle); |
| }else { |
| Flow *flow = vehicle->getFlow(); |
| if (flow) flow->setValid(false); |
|
|
| |
| auto iter = vehiclePool.find(vehicle->getPriority()); |
| threadVehiclePool[iter->second.second].erase(vehicle); |
| delete vehicle; |
| vehiclePool.erase(iter); |
| } |
| road.clearPlanRouteBuffer(); |
| } |
| } |
|
|
| void Engine::getAction() { |
| startBarrier.wait(); |
| endBarrier.wait(); |
| } |
|
|
| void Engine::updateLocation() { |
| startBarrier.wait(); |
| endBarrier.wait(); |
| std::sort(pushBuffer.begin(), pushBuffer.end(), vehicleCmp); |
| for (auto &vehiclePair : pushBuffer) { |
| Vehicle *vehicle = vehiclePair.first; |
| Drivable *drivable = vehicle->getChangedDrivable(); |
| if (drivable != nullptr) { |
| drivable->pushVehicle(vehicle); |
| if (drivable->isLaneLink()) { |
| vehicle->setEnterLaneLinkTime(step); |
| } else { |
| vehicle->setEnterLaneLinkTime(std::numeric_limits<int>::max()); |
| } |
| } |
| } |
| pushBuffer.clear(); |
| } |
|
|
| void Engine::updateAction() { |
| startBarrier.wait(); |
| endBarrier.wait(); |
| vehicleRemoveBuffer.clear(); |
| } |
|
|
| void Engine::handleWaiting() { |
| for (Lane *lane : roadnet.getLanes()) { |
| auto &buffer = lane->getWaitingBuffer(); |
| if (buffer.empty()) continue; |
| auto &vehicle = buffer.front(); |
| if (lane->available(vehicle)) { |
| vehicle->setRunning(true); |
| activeVehicleCount += 1; |
| Vehicle * tail = lane->getLastVehicle(); |
| lane->pushVehicle(vehicle); |
| vehicle->updateLeaderAndGap(tail); |
| buffer.pop_front(); |
| } |
| } |
| } |
|
|
| void Engine::updateLog() { |
| std::string result; |
| for (const Vehicle* vehicle: getRunningVehicles()) { |
| Point pos = vehicle->getPoint(); |
| Point dir = vehicle->getCurDrivable()->getDirectionByDistance(vehicle->getDistance()); |
|
|
| int lc = vehicle->lastLaneChangeDirection(); |
| result.append( |
| double2string(pos.x) + " " + double2string(pos.y) + " " + double2string(atan2(dir.y, dir.x)) + " " |
| + vehicle->getId() + " " + std::to_string(lc) + " " + double2string(vehicle->getLen()) + " " |
| + double2string(vehicle->getWidth()) + ","); |
| } |
| result.append(";"); |
|
|
| for (const Road &road : roadnet.getRoads()) { |
| if (road.getEndIntersection().isVirtualIntersection()) |
| continue; |
| result.append(road.getId()); |
| for (const Lane &lane : road.getLanes()) { |
| if (lane.getEndIntersection()->isImplicitIntersection()){ |
| result.append(" i"); |
| continue; |
| } |
|
|
| bool can_go = true; |
| for (LaneLink *laneLink : lane.getLaneLinks()) { |
| if (!laneLink->isAvailable()) { |
| can_go = false; |
| break; |
| } |
| } |
| result.append(can_go ? " g" : " r"); |
| } |
| result.append(","); |
| } |
| logOut << result << std::endl; |
| } |
|
|
| void Engine::updateLeaderAndGap() { |
| startBarrier.wait(); |
| endBarrier.wait(); |
| } |
|
|
| void Engine::notifyCross() { |
| startBarrier.wait(); |
| endBarrier.wait(); |
| } |
|
|
| void Engine::nextStep() { |
| for (auto &flow : flows) |
| flow.nextStep(interval); |
| planRoute(); |
| handleWaiting(); |
| if (laneChange) { |
| initSegments(); |
| planLaneChange(); |
| updateLeaderAndGap(); |
| } |
| notifyCross(); |
|
|
| getAction(); |
| updateLocation(); |
| updateAction(); |
| updateLeaderAndGap(); |
|
|
| if (!rlTrafficLight) { |
| std::vector<Intersection> &intersections = roadnet.getIntersections(); |
| for (auto &intersection : intersections) |
| intersection.getTrafficLight().passTime(interval); |
| } |
|
|
| if (saveReplay) { |
| updateLog(); |
| } |
|
|
| step += 1; |
| } |
|
|
| void Engine::initSegments() { |
| startBarrier.wait(); |
| endBarrier.wait(); |
| } |
|
|
| bool Engine::checkPriority(int priority) { |
| return vehiclePool.find(priority) != vehiclePool.end(); |
| } |
|
|
| void Engine::pushVehicle(Vehicle *const vehicle, bool pushToDrivable) { |
| size_t threadIndex = rnd() % threadNum; |
| vehiclePool.emplace(vehicle->getPriority(), std::make_pair(vehicle, threadIndex)); |
| vehicleMap.emplace(vehicle->getId(), vehicle); |
| threadVehiclePool[threadIndex].insert(vehicle); |
|
|
| if (pushToDrivable) |
| ((Lane *) vehicle->getCurDrivable())->pushWaitingVehicle(vehicle); |
| } |
|
|
| size_t Engine::getVehicleCount() const { |
| return activeVehicleCount; |
| } |
|
|
| std::vector<std::string> Engine::getVehicles(bool includeWaiting) const { |
| std::vector<std::string> ret; |
| ret.reserve(activeVehicleCount); |
| for (const Vehicle* vehicle : getRunningVehicles(includeWaiting)) { |
| ret.emplace_back(vehicle->getId()); |
| } |
| return ret; |
| } |
|
|
| std::map<std::string, int> Engine::getLaneVehicleCount() const { |
| std::map<std::string, int> ret; |
| for (const Lane *lane : roadnet.getLanes()) { |
| ret.emplace(lane->getId(), lane->getVehicleCount()); |
| } |
| return ret; |
| } |
|
|
| std::map<std::string, int> Engine::getLaneWaitingVehicleCount() const { |
| std::map<std::string, int> ret; |
| for (const Lane *lane : roadnet.getLanes()) { |
| int cnt = 0; |
| for (Vehicle *vehicle : lane->getVehicles()) { |
| if (vehicle->getSpeed() < 0.1) { |
| cnt += 1; |
| } |
| } |
| ret.emplace(lane->getId(), cnt); |
| } |
| return ret; |
| } |
|
|
| std::map<std::string, std::vector<std::string>> Engine::getLaneVehicles() { |
| std::map<std::string, std::vector<std::string>> ret; |
| for (const Lane *lane : roadnet.getLanes()) { |
| std::vector<std::string> vehicles; |
| for (Vehicle *vehicle : lane->getVehicles()) { |
| vehicles.push_back(vehicle->getId()); |
| } |
| ret.emplace(lane->getId(), vehicles); |
| } |
| return ret; |
| } |
|
|
| std::map<std::string, double> Engine::getVehicleSpeed() const { |
| std::map<std::string, double> ret; |
| for (const Vehicle* vehicle : getRunningVehicles()) { |
| ret.emplace(vehicle->getId(), vehicle->getSpeed()); |
| } |
| return ret; |
| } |
|
|
| std::map<std::string, double> Engine::getVehicleDistance() const { |
| std::map<std::string, double> ret; |
| for (const Vehicle* vehicle : getRunningVehicles()) { |
| ret.emplace(vehicle->getId(), vehicle->getDistance()); |
| } |
| return ret; |
| } |
|
|
| double Engine::getCurrentTime() const { |
| return step * interval; |
| } |
|
|
| double Engine::getAverageTravelTime() const { |
| double tt = cumulativeTravelTime; |
| int n = finishedVehicleCnt; |
| for (auto &vehicle_pair : vehiclePool) { |
| auto &vehicle = vehicle_pair.second.first; |
| tt += getCurrentTime() - vehicle->getEnterTime(); |
| n++; |
| } |
| return n == 0 ? 0 : tt / n; |
| } |
|
|
| void Engine::pushVehicle(const std::map<std::string, double> &info, const std::vector<std::string> &roads) { |
| VehicleInfo vehicleInfo; |
| std::map<std::string, double>::const_iterator it; |
| if ((it = info.find("speed")) != info.end()) vehicleInfo.speed = it->second; |
| if ((it = info.find("length")) != info.end()) vehicleInfo.len = it->second; |
| if ((it = info.find("width")) != info.end()) vehicleInfo.width = it->second; |
| if ((it = info.find("maxPosAcc")) != info.end()) vehicleInfo.maxPosAcc = it->second; |
| if ((it = info.find("maxNegAcc")) != info.end()) vehicleInfo.maxNegAcc = it->second; |
| if ((it = info.find("usualPosAcc")) != info.end()) vehicleInfo.usualPosAcc = it->second; |
| if ((it = info.find("usualNegAcc")) != info.end()) vehicleInfo.usualNegAcc = it->second; |
| if ((it = info.find("minGap")) != info.end()) vehicleInfo.minGap = it->second; |
| if ((it = info.find("maxSpeed")) != info.end()) vehicleInfo.maxSpeed = it->second; |
| if ((it = info.find("headwayTime")) != info.end()) vehicleInfo.headwayTime = it->second; |
|
|
| std::vector<Road *> routes; |
| routes.reserve(roads.size()); |
| for (auto &road: roads) routes.emplace_back(roadnet.getRoadById(road)); |
| auto route = std::make_shared<const Route>(routes); |
| vehicleInfo.route = route; |
| |
| Vehicle *vehicle = new Vehicle(vehicleInfo, |
| "manually_pushed_" + std::to_string(manuallyPushCnt++), this); |
| pushVehicle(vehicle, false); |
| vehicle->getFirstRoad()->addPlanRouteVehicle(vehicle); |
| } |
|
|
| void Engine::setTrafficLightPhase(const std::string &id, int phaseIndex) { |
| if (!rlTrafficLight) { |
| std::cerr << "please set rlTrafficLight to true to enable traffic light control" << std::endl; |
| return; |
| } |
| roadnet.getIntersectionById(id)->getTrafficLight().setPhase(phaseIndex); |
| } |
|
|
| void Engine::setReplayLogFile(const std::string &logFile) { |
| if (!saveReplayInConfig) { |
| std::cerr << "saveReplay is not set to true in config file!" << std::endl; |
| return; |
| } |
| if (logOut.is_open()) logOut.close(); |
| logOut.open(dir + logFile); |
| } |
|
|
| void Engine::setSaveReplay(bool open) { |
| if (!saveReplayInConfig) { |
| std::cerr << "saveReplay is not set to true in config file!" << std::endl; |
| return; |
| } |
| saveReplay = open; |
| } |
| |
| void Engine::reset(bool resetRnd) { |
| for (auto &vehiclePair : vehiclePool) delete vehiclePair.second.first; |
| for (auto &pool : threadVehiclePool) pool.clear(); |
| vehiclePool.clear(); |
| vehicleMap.clear(); |
| roadnet.reset(); |
|
|
| finishedVehicleCnt = 0; |
| cumulativeTravelTime = 0; |
|
|
| for (auto &flow : flows) flow.reset(); |
| step = 0; |
| activeVehicleCount = 0; |
| if (resetRnd) { |
| rnd.seed(seed); |
| } |
| } |
|
|
| Engine::~Engine() { |
| logOut.close(); |
| finished = true; |
| for (int i = 0; i < (laneChange ? 9 : 6); ++i) { |
| startBarrier.wait(); |
| endBarrier.wait(); |
| } |
| for (auto &thread : threadPool) thread.join(); |
| for (auto &vehiclePair : vehiclePool) delete vehiclePair.second.first; |
| } |
| |
| void Engine::setLogFile(const std::string &jsonFile, const std::string &logFile) { |
| if (!writeJsonToFile(jsonFile, jsonRoot)) { |
| std::cerr << "write roadnet log file error" << std::endl; |
| } |
| logOut.open(logFile); |
| } |
|
|
| std::vector<const Vehicle *> Engine::getRunningVehicles(bool includeWaiting) const { |
| std::vector<const Vehicle *> ret; |
| ret.reserve(activeVehicleCount); |
| for (const auto &vehiclePair: vehiclePool) { |
| const Vehicle *vehicle = vehiclePair.second.first; |
| if (vehicle->isReal() && (includeWaiting || vehicle->isRunning())) { |
| ret.emplace_back(vehicle); |
| } |
| } |
| return ret; |
| } |
|
|
| void Engine::scheduleLaneChange() { |
| std::sort(laneChangeNotifyBuffer.begin(), laneChangeNotifyBuffer.end(), |
| [](Vehicle *a, Vehicle *b){return a->laneChangeUrgency() > b->laneChangeUrgency();}); |
| for (auto v : laneChangeNotifyBuffer){ |
| v->updateLaneChangeNeighbor(); |
| v->sendSignal(); |
| |
| |
| if (v->planLaneChange() && v->canChange() && !v->isChanging()) { |
| std::shared_ptr<LaneChange> lc = v->getLaneChange(); |
| if (lc->isGapValid() && v->getCurDrivable()->isLane()) { |
| |
| |
| insertShadow(v); |
| } |
| } |
| } |
| laneChangeNotifyBuffer.clear(); |
| } |
|
|
| void Engine::insertShadow(Vehicle *vehicle) { |
| size_t threadIndex = vehiclePool.at(vehicle->getPriority()).second; |
| Vehicle *shadow = new Vehicle(*vehicle, vehicle->getId() + "_shadow", this); |
| vehicleMap.emplace(shadow->getId(), shadow); |
| vehiclePool.emplace(shadow->getPriority(), std::make_pair(shadow, threadIndex)); |
| threadVehiclePool[threadIndex].insert(shadow); |
| vehicle->insertShadow(shadow); |
| activeVehicleCount++; |
| } |
|
|
| void Engine::loadFromFile(const char *fileName) { |
| Archive archive(*this, fileName); |
| archive.resume(*this); |
| } |
|
|
| void Engine::setVehicleSpeed(const std::string &id, double speed) { |
| auto iter = vehicleMap.find(id); |
| if (iter == vehicleMap.end()) { |
| throw std::runtime_error("Vehicle '" + id + "' not found"); |
| }else { |
| iter->second->setCustomSpeed(speed); |
| } |
| } |
|
|
| std::string Engine::getLeader(const std::string &vehicleId) const { |
| auto iter = vehicleMap.find(vehicleId); |
| if (iter == vehicleMap.end()) { |
| throw std::runtime_error("Vehicle '" + vehicleId + "' not found"); |
| }else { |
| Vehicle *vehicle = iter->second; |
| if (laneChange) { |
| if (!vehicle->isReal()) |
| vehicle = vehicle->getPartner(); |
| } |
| Vehicle *leader = vehicle->getLeader(); |
| if (leader) return leader->getId(); |
| else return ""; |
| } |
| } |
|
|
| bool Engine::setRoute(const std::string &vehicle_id, const std::vector<std::string> &anchor_id) { |
| auto vehicle_itr = vehicleMap.find(vehicle_id); |
| if (vehicle_itr == vehicleMap.end()) return false; |
| Vehicle *vehicle = vehicle_itr->second; |
|
|
| std::vector<Road *> anchors; |
| for (const auto &id : anchor_id) { |
| auto anchor = roadnet.getRoadById(id); |
| if (!anchor) |
| return false; |
| anchors.emplace_back(anchor); |
| } |
|
|
| return vehicle->setRoute(anchors); |
| } |
|
|
| std::map<std::string, std::string> Engine::getVehicleInfo(const std::string &id) const { |
| auto iter = vehicleMap.find(id); |
| if (iter == vehicleMap.end()) { |
| throw std::runtime_error("Vehicle '" + id + "' not found"); |
| }else { |
| Vehicle *vehicle = iter->second; |
| return vehicle->getInfo(); |
| } |
| } |
|
|
| } |
|
|