Skip to content
Snippets Groups Projects
Select Git revision
  • 57-sphinx-documentation
  • devel default
  • 107-compilation-error-when-building-maestro-core-on-m1-apple-processors
  • 108-implement-cpu-id-query-for-apple-m1-hardware
  • 58-scripting-interface-to-maestro-core
  • 101-need-ci-test-using-installed-maestro
  • 105-memory-leak-in-pm-message-envelope-handling
  • 104-permit-disabling-memory-pool
  • 103-liberl-installation-issue-on-devel
  • 94-maestro-rdma-transport-ignores-max_msg_size-2
  • main protected
  • 102-possible-race-in-check_pm_redundant_interlock-test
  • 97-check-if-shm-provider-can-be-enabled-after-libfabric-1-14-is-in-our-tree-2
  • 100-include-maestro-attributes-h-cannot-include-mamba-header-from-deps-path
  • 97-check-if-shm-provider-can-be-enabled-after-libfabric-1-14-is-in-our-tree
  • 17-job-failed-282354-needs-update-of-mio-interface-and-build-rules
  • 96-test-libfabric-update-to-1-13-or-1-14
  • feature/stop-telemetry-after-all-left
  • 94-maestro-rdma-transport-ignores-max_msg_size
  • 93-improve-performance-of-mstro_attribute_val_cmp_str
  • v0.3_rc1
  • maestro_d65
  • d65_experiments_20211113
  • v0.2
  • v0.2_rc1
  • d3.3
  • d3.3-review
  • d5.5
  • d5.5-review
  • v0.1
  • d3.2
  • d3.2-draft
  • v0.0
33 results

ChangeLog

Blame
  • To find the state of this project's repository at the time of any of these versions, check out the tags.
    ffRouter.cpp 35.22 KiB
    /**
     * \file        ffRouter.h
     * \date        Feb 19, 2016
     * \version     v0.8
     * \copyright   <2016-2022> Forschungszentrum Jülich GmbH. All rights reserved.
     *
     * \section License
     * This file is part of JuPedSim.
     *
     * JuPedSim is free software: you can redistribute it and/or modify
     * it under the terms of the GNU Lesser General Public License as published by
     * the Free Software Foundation, either version 3 of the License, or
     * any later version.
     *
     * JuPedSim is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     * GNU General Public License for more details.
     *
     * You should have received a copy of the GNU Lesser General Public License
     * along with JuPedSim. If not, see <http://www.gnu.org/licenses/>.
     *
     * \section Description
     * This router is an update of the former Router.{cpp, h} - Global-, Quickest
     * Router System. In the __former__ version, a graph was created with doors and
     * hlines as nodes and the distances of (doors, hlines), connected with a line-
     * of-sight, was used as edge-costs. If there was no line-of-sight, there was no
     * connecting edge. On the resulting graph, the Floyd-Warshall algorithm was
     * used to find any paths. In the "quickest-___" variants, the edge cost was not
     * determined by the distance, but by the distance multiplied by a speed-
     * estimate, to find the path with minimum travel times. This whole construct
     * worked pretty well, but dependend on hlines to create paths with line-of-
     * sights to the next target (hline/door).
     *
     * In the ffRouter, we want to overcome hlines by using floor fields to
     * determine the distances. A line of sight is not required any more. We hope to
     * reduce the graph complexity and the preparation-needs for new geometries.
     *
     * To find a counterpart for the "quickest-____" router, we can either use
     * __special__ floor fields, that respect the travel time in the input-speed map,
     * or take the distance-floor field and multiply it by a speed-estimate (analog
     * to the former construct.
     *
     * We will derive from the <Router> class to fit the interface.
     *
     **/
    
    #include <cfloat>
    #include <algorithm>
    #include "ffRouter.h"
    //#include "FloorfieldViaFM.h"
    //#include "../../geometry/Building.h"
    #include "../../pedestrian/Pedestrian.h"
    #include "../../IO/OutputHandler.h"
    
    #include <chrono>
    
    int FFRouter::_cnt = 0;
    
    FFRouter::FFRouter()
    {
    
    }
    
    FFRouter::FFRouter(int id, RoutingStrategy s, bool hasSpecificGoals, Configuration* config):Router(id,s) {
         _config = config;
         _building = nullptr;
         _hasSpecificGoals = hasSpecificGoals;
         _globalFF = nullptr;
         _targetWithinSubroom = true; //depending on exit_strat 8 => false, depending on exit_strat 9 => true;
         if (s == ROUTING_FF_QUICKEST) {
              _mode = quickest;
              _recalc_interval = _config->get_recalc_interval();
         } else if (s == ROUTING_FF_LOCAL_SHORTEST) {
              _mode = local_shortest;
              _localShortestSafedPeds.clear();
              _localShortestSafedPeds.reserve(500);
         } else if (s == ROUTING_FF_GLOBAL_SHORTEST) {
              _mode = global_shortest;
         }
    }
    
    //FFRouter::FFRouter(const Building* const building)
    
    FFRouter::~FFRouter()
    {
         if (_globalFF) {
              delete _globalFF;
         }
         //delete localffs
         std::map<int, UnivFFviaFM*>::reverse_iterator delIter;
         for (delIter = _locffviafm.rbegin();
              delIter != _locffviafm.rend();
              ++delIter) {
              delete (*delIter).second;
         }
    }
    
    bool FFRouter::Init(Building* building)
    {
         _building = building;
         if (_hasSpecificGoals) {
              std::vector<int> goalIDs;
              goalIDs.clear();
              //get global field to manage goals (which are not in a subroom)
              _globalFF = new FloorfieldViaFM(building, 0.25, 0.25, 0.0, false, true);
              for (auto &itrGoal : building->GetAllGoals()) {
                   _globalFF->createMapEntryInLineToGoalID(itrGoal.first);
                   goalIDs.emplace_back(itrGoal.first);
              }
              _goalToLineUIDmap = _globalFF->getGoalToLineUIDmap();
              _goalToLineUIDmap2 = _globalFF->getGoalToLineUIDmap2();
              _goalToLineUIDmap3 = _globalFF->getGoalToLineUIDmap3();
              //_globalFF->writeGoalFF("goal.vtk", goalIDs);
         }
         //get all door UIDs
         _allDoorUIDs.clear();
         _TransByUID.clear();
         _ExitsByUID.clear();
         _CroTrByUID.clear();
         auto& allTrans = building->GetAllTransitions();
         auto& allCross = building->GetAllCrossings();
         std::vector<std::pair<int, int>> roomAndCroTrVector;
         roomAndCroTrVector.clear();
         for (auto& pair:allTrans) {
              if (pair.second->IsOpen()) {
                   _allDoorUIDs.emplace_back(pair.second->GetUniqueID());
                   _CroTrByUID.insert(std::make_pair(pair.second->GetUniqueID(), pair.second));
                   if (pair.second->IsExit()) {
                        _ExitsByUID.insert(std::make_pair(pair.second->GetUniqueID(), pair.second));
                   }
                   Room* room1 = pair.second->GetRoom1();
                   if (room1) roomAndCroTrVector.emplace_back(std::make_pair(room1->GetID(), pair.second->GetUniqueID()));
                   Room* room2 = pair.second->GetRoom2();
                   if (room2) roomAndCroTrVector.emplace_back(std::make_pair(room2->GetID(), pair.second->GetUniqueID()));
              }
         }
         for (auto& pair:allCross) {
              if (pair.second->IsOpen()) {
                   _allDoorUIDs.emplace_back(pair.second->GetUniqueID());
                   _CroTrByUID.insert(std::make_pair(pair.second->GetUniqueID(), pair.second));
                   Room* room1 = pair.second->GetRoom1();
                   if (room1) roomAndCroTrVector.emplace_back(std::make_pair(room1->GetID(), pair.second->GetUniqueID()));
              }
         }
         //make unique
         _allDoorUIDs.erase( std::unique(_allDoorUIDs.begin(),_allDoorUIDs.end()), _allDoorUIDs.end());
    
         //cleanse maps
         _distMatrix.clear();
         _pathsMatrix.clear();
    
         //init, yet no distances, only create map entries
         for(auto& id1 : _allDoorUIDs) {
              for(auto& id2 : _allDoorUIDs){
                   std::pair<int, int> key   = std::make_pair(id1, id2);
                   double              value = (id1 == id2)? 0.0 : DBL_MAX;
                   //distMatrix[i][j] = 0,   if i==j
                   //distMatrix[i][j] = max, else
                   _distMatrix.insert(std::make_pair( key , value));
                   //pathsMatrix[i][j] = i or j ? (follow wiki:path_reconstruction, it should be j)
                   _pathsMatrix.insert(std::make_pair( key , id2 ));
                   _subroomMatrix.insert(std::make_pair(key, nullptr));
              }
         }
    
         //prepare all room-floor-fields-objects (one room = one instance)
         _locffviafm.clear();
         //type of allRooms: const std::map<int, std::unique_ptr<Room> >&
         const std::map<int, std::shared_ptr<Room> >& allRooms = _building->GetAllRooms();
    
    
         for (unsigned int i = 0; i < allRooms.size(); ++i) {
    
    #ifdef DEBUG
              std::cerr << "Creating Floorfield for Room: " << pair.first << std::endl;
    #endif
    
              auto pairRoomIt = allRooms.begin();
              std::advance(pairRoomIt, i);
              UnivFFviaFM *locffptr = nullptr;
              locffptr = new UnivFFviaFM(pairRoomIt->second.get(), building, 0.125, 0.0, false);
    //               Log->Write("INFO: \tusing %s in ffRouter::Init", _useCentrePointDistance ? "CentrePointLocalFFViaFm" : "LocalFloorfieldViaFM");
    //               if (_useCentrePointDistance) {
    //                    locffptr = new CentrePointLocalFFViaFM(pairRoomIt->second.get(), building, 0.125, 0.125, 0.0, false);
    //               } else {
    //                    locffptr = new LocalFloorfieldViaFM(pairRoomIt->second.get(), building, 0.125, 0.125, 0.0, false);
    //               }
              locffptr->setUser(DISTANCE_MEASUREMENTS_ONLY);
              locffptr->setMode(CENTERPOINT);
              locffptr->setSpeedMode(FF_HOMO_SPEED);
              locffptr->addAllTargetsParallel();
              //locffptr->writeFF("UnivFF"+std::to_string(pairRoomIt->first)+".vtk", locffptr->getKnownDoorUIDs());
              Log->Write("INFO: \tAdding distances in Room %d to matrix", (*pairRoomIt).first);
    //#pragma omp critical(_locffviafm)
              _locffviafm.insert(std::make_pair((*pairRoomIt).first, locffptr));
         }
    
    
         // nowait, because the parallel region ends directly afterwards
    //#pragma omp for nowait
         //@todo: @ar.graf: it would be easier to browse thru doors of each field directly after "addAllTargetsParallel" as
         //                 we do only want doors of same subroom anyway. BUT the router would have to switch from room-scope
         //                 to subroom-scope. Nevertheless, we could omit the room info (used to acces correct field), if we
         //                 do it like in "ReInit()".
         for (unsigned int i = 0; i < roomAndCroTrVector.size(); ++i) {
              auto rctIt = roomAndCroTrVector.begin();
              std::advance(rctIt, i);
    
              ////loop over upper triangular matrice (i,j) and write to (j,i) as well
              for (auto otherDoor : roomAndCroTrVector) {
                   if (otherDoor.first != rctIt->first) continue; // we only want doors with one room in common
                   if (otherDoor.second <= rctIt->second) continue; // calculate every path only once
                   // if we exclude otherDoor.second == rctIt->second, the program loops forever
    
                   //if the door is closed, then don't calc distances
                   //if (!_CroTrByUID.at(*otherDoor)->IsOpen()) {
                   //     continue;
                   //}
    
                   // if the two doors are not within the same subroom, do not consider (ar.graf)
                   // should fix problems of oscillation caused by doorgaps in the distancegraph
                   int thisUID1 = (_CroTrByUID.at(rctIt->second)->GetSubRoom1()) ? _CroTrByUID.at(rctIt->second)->GetSubRoom1()->GetUID() : -1 ;
                   int thisUID2 = (_CroTrByUID.at(rctIt->second)->GetSubRoom2()) ? _CroTrByUID.at(rctIt->second)->GetSubRoom2()->GetUID() : -2 ;
                   int otherUID1 = (_CroTrByUID.at(otherDoor.second)->GetSubRoom1()) ? _CroTrByUID.at(otherDoor.second)->GetSubRoom1()->GetUID() : -3 ;
                   int otherUID2 = (_CroTrByUID.at(otherDoor.second)->GetSubRoom2()) ? _CroTrByUID.at(otherDoor.second)->GetSubRoom2()->GetUID() : -4 ;
    
                   if (
                             (thisUID1 != otherUID1) &&
                             (thisUID1 != otherUID2) &&
                             (thisUID2 != otherUID1) &&
                             (thisUID2 != otherUID2)      ) {
                        continue;
                   }
    
                   UnivFFviaFM* locffptr = _locffviafm[rctIt->first];
                   double tempDistance = locffptr->getCostToDestination(rctIt->second,
                                                                        _CroTrByUID.at(otherDoor.second)->GetCentre());
    
                   if (tempDistance < locffptr->getGrid()->Gethx()) {
                        //Log->Write("WARNING:\tDistance of doors %d and %d is too small: %f",*otherDoor, *innerPtr, tempDistance);
                        //Log->Write("^^^^^^^^\tIf there are scattered subrooms, which are not connected, this is ok.");
                        continue;
                   }
    //
                   std::pair<int, int> key_ij = std::make_pair(otherDoor.second, rctIt->second);
                   std::pair<int, int> key_ji = std::make_pair(rctIt->second, otherDoor.second);
    //                    SubRoom *subroom = nullptr;
    //
    //                    auto cr1 = _CroTrByUID[rctIt->second];
    //                    auto cr2 = _CroTrByUID[otherDoor.second];
    //
    //                    // If the crossings are the same, we write nullptr to _subroomMatrix. This entry is never accessed.
    //                    if (cr1 != cr2) {
    //                         switch (int nr_subrooms = cr1->CommonSubroomWith(cr2, subroom)) {
    //                              case 1: {
    //                                   // subroom already set in CommonSubroomWith()
    //                                   break;
    //                              }
    //                              case 2: {
    //                                   SubRoom* subroom2 = cr2->GetOtherSubRoom(subroom->GetRoomID(), subroom->GetSubRoomID());
    //                                   Point grad;
    //                                   long int grid_key = _locffviafm.at(subroom->GetRoomID())->getGrid()->getKeyAtPoint(cr2->GetCentre());
    //                                   _locffviafm.at(subroom->GetRoomID())->getDirectionToUID(cr1->GetUniqueID(), grid_key, grad);
    //                                   // When two doors share both subrooms, we use the gradient to determine which way is shorter.
    //                                   Point point_in_subroom = cr2->GetCentre() + grad;
    //                                   bool s1 = subroom->IsInSubRoom(point_in_subroom);
    //                                   bool s2 = subroom2->IsInSubRoom(point_in_subroom);
    //                                   // With a symmetric geometry, it is possible that the gradient is parallel to the doors/the wall between them.
    //                                   // If this is the case, we just take one of the subrooms (the ways have the same lengths).
    //                                   // I cannot imagine a case where the point is in none of the subrooms, so issue an error. --f.mack
    //                                   if (!(s1 || s2)) {
    //                                        Log->Write("ERROR \tffRouter::Init(): %f, %f is neither in subroom [%d/%d] nor in [%d/%d]",
    //                                                   point_in_subroom._x, point_in_subroom._y,
    //                                                   subroom->GetRoomID(), subroom->GetSubRoomID(),
    //                                                   subroom2->GetRoomID(), subroom2->GetSubRoomID());
    //                                   }
    //                                   if (s2) subroom = subroom2; // we have to take the other one
    //                                   break;
    //                              }
    //                              default: {
    //                                   // subroom will stay nullptr if nr_subrooms == 0
    //                                   Log->Write("ERROR \tffRouter::Init(): unexpected numbers of common subrooms: %d for doorUIDs %d and %d", nr_subrooms, cr1->GetUniqueID(), cr2->GetUniqueID());
    //                                   break;
    //                              }
    //                         }
    //                    }
    
    //#pragma omp critical(_distMatrix)
                   if (_distMatrix.at(key_ij) > tempDistance) {
                        _distMatrix.erase(key_ij);
                        _distMatrix.erase(key_ji);
                        _distMatrix.insert(std::make_pair(key_ij, tempDistance));
                        _distMatrix.insert(std::make_pair(key_ji, tempDistance));
    //#pragma omp critical(_subroomMatrix)
    //                         {
    //                              _subroomMatrix.erase(key_ij);
    //                              _subroomMatrix.erase(key_ji);
    //                              _subroomMatrix.insert(std::make_pair(key_ij, subroom));
    //                              _subroomMatrix.insert(std::make_pair(key_ji, subroom));
    //                         }
    
                   }
                   //}
              } // otherDoor
         } // roomAndCroTrVector
    
         FloydWarshall();
    
         //debug output in file
    //     _locffviafm[4]->writeFF("ffTreppe.vtk", _allDoorUIDs);
    
         //int roomTest = (*(_locffviafm.begin())).first;
         //int transTest = (building->GetRoom(roomTest)->GetAllTransitionsIDs())[0];
         //auto test = _CroTrByUID.at(1253);
    
         if (_config->get_write_VTK_files()) {
              for (unsigned int i = 0; i < _locffviafm.size(); ++i) {
                   auto iter = _locffviafm.begin();
                   std::advance(iter, i);
                   int roomNr = iter->first;
                   iter->second->writeFF("ffrouterOfRoom" + std::to_string(roomNr) + ".vtk", _allDoorUIDs);
              }
         }
    
    //     std::ofstream matrixfile;
    //     matrixfile.open("Matrix.txt");
    //
    //     for (auto mapItem : _distMatrix) {
    //          matrixfile << mapItem.first.first << " to " << mapItem.first.second << " : " << mapItem.second << "\t via \t" << _pathsMatrix[mapItem.first];
    //          matrixfile << "\t" << _CroTrByUID.at(mapItem.first.first)->GetID() << " to " << _CroTrByUID.at(mapItem.first.second)->GetID() << "\t via \t";
    //          matrixfile << _CroTrByUID.at(_pathsMatrix[mapItem.first])->GetID();
    ////          auto sub = _subroomMatrix.at(mapItem.first);
    ////          if (sub) {
    ////               matrixfile << std::string("\tSubroom: UID ") << sub->GetUID() << " (room: " << sub->GetRoomID() << " subroom ID: " << sub->GetSubRoomID() << ")" << std::endl;
    ////          } else {
    ////               matrixfile << std::string("\tSubroom is nullptr") << std::endl;
    ////          }
    //     }
    //     matrixfile.close();
         Log->Write("INFO: \tFF Router Init done.");
         return true;
    }
    
    bool FFRouter::ReInit()
    {
         //cleanse maps
         _distMatrix.clear();
         _pathsMatrix.clear();
    
         //init, yet no distances, only create map entries
         for(auto& id1 : _allDoorUIDs) {
              for(auto& id2 : _allDoorUIDs){
                   std::pair<int, int> key   = std::make_pair(id1, id2);
                   double              value = (id1 == id2)? 0.0 : DBL_MAX;
                   //distMatrix[i][j] = 0,   if i==j
                   //distMatrix[i][j] = max, else
                   _distMatrix.insert(std::make_pair( key , value));
                   //pathsMatrix[i][j] = i or j ? (follow wiki:path_reconstruction, it should be j)
                   _pathsMatrix.insert(std::make_pair( key , id2 ));
                   _subroomMatrix.insert(std::make_pair(key, nullptr));
              }
         }
    
         for (auto floorfield : _locffviafm) {
              floorfield.second->setSpeedMode(FF_PED_SPEED);
              //@todo: ar.graf: create a list of local ped-ptr instead of giving all peds-ptr
              floorfield.second->createPedSpeed(_building->GetAllPedestrians().data(), _building->GetAllPedestrians().size(), _mode, 1.);
              floorfield.second->recreateAllForQuickest();
              std::vector<int> allDoors(floorfield.second->getKnownDoorUIDs());
              for (auto firstDoor : allDoors) {
                   for (auto secondDoor : allDoors) {
                        if (secondDoor <= firstDoor) continue; // calculate every path only once
                        // if the two doors are not within the same subroom, do not consider (ar.graf)
                        // should fix problems of oscillation caused by doorgaps in the distancegraph
                        int thisUID1 = (_CroTrByUID.at(firstDoor)->GetSubRoom1()) ? _CroTrByUID.at(firstDoor)->GetSubRoom1()->GetUID() : -1 ;
                        int thisUID2 = (_CroTrByUID.at(firstDoor)->GetSubRoom2()) ? _CroTrByUID.at(firstDoor)->GetSubRoom2()->GetUID() : -2 ;
                        int otherUID1 = (_CroTrByUID.at(secondDoor)->GetSubRoom1()) ? _CroTrByUID.at(secondDoor)->GetSubRoom1()->GetUID() : -3 ;
                        int otherUID2 = (_CroTrByUID.at(secondDoor)->GetSubRoom2()) ? _CroTrByUID.at(secondDoor)->GetSubRoom2()->GetUID() : -4 ;
    
                        if (
                                  (thisUID1 != otherUID1) &&
                                  (thisUID1 != otherUID2) &&
                                  (thisUID2 != otherUID1) &&
                                  (thisUID2 != otherUID2)      ) {
                             continue;
                        }
    
                        double tempDistance = floorfield.second->getCostToDestination(firstDoor, _CroTrByUID.at(secondDoor)->GetCentre());
                        if (tempDistance < floorfield.second->getGrid()->Gethx()) {
                             //Log->Write("WARNING:\tDistance of doors %d and %d is too small: %f",*otherDoor, *innerPtr, tempDistance);
                             //Log->Write("^^^^^^^^\tIf there are scattered subrooms, which are not connected, this is ok.");
                             continue;
                        }
                        std::pair<int, int> key_ij = std::make_pair(secondDoor, firstDoor);
                        std::pair<int, int> key_ji = std::make_pair(firstDoor, secondDoor);
                        if (_distMatrix.at(key_ij) > tempDistance) {
                             _distMatrix.erase(key_ij);
                             _distMatrix.erase(key_ji);
                             _distMatrix.insert(std::make_pair(key_ij, tempDistance));
                             _distMatrix.insert(std::make_pair(key_ji, tempDistance));
                        }
                   } //secondDoor(s)
              } //firstDoor(s)
         } //allRooms
         FloydWarshall();
         _plzReInit = false;
         return true;
    }
    
    
    
    int FFRouter::FindExit(Pedestrian* p)
    {
    //     if (_mode == local_shortest) {
    //          if ((_locffviafm.at(p->GetRoomID())->getGrid()->includesPoint(p->GetPos())) &&
    //              (p->GetSubRoomUID() != _locffviafm.at(p->GetRoomID())->getSubroomUIDAt(p->GetPos()))) {
    //               //pedestrian is still in the room, but changed subroom
    //               _localShortestSafedPeds.emplace_back(p->GetID());
    //          }
    //
    //          //if needed: quickest-mechanic part 2 of 2
    //          if (!(_locffviafm.at(p->GetRoomID())->getGrid()->includesPoint(p->GetPos()))) {
    //               //pedestrian left the room and therefore changed subroom
    //               _localShortestSafedPeds.emplace_back(p->GetID());
    //          }
    //     }
         if (_mode == quickest) {
              //new version: recalc densityspeed every x seconds
              if ((p->GetGlobalTime() > _timeToRecalc) && (p->GetGlobalTime() > Pedestrian::GetMinPremovementTime() + _recalc_interval)) {
                   _plzReInit = true;
              }
         }
         double minDist = DBL_MAX;
         int bestDoor = -1;
    
         int goalID = p->GetFinalDestination();
         std::vector<int> validFinalDoor; //UIDs of doors
         validFinalDoor.clear();
         if (goalID == -1) {
              for (auto& pairDoor : _ExitsByUID) {
                   //we add the all exits,
                   validFinalDoor.emplace_back(pairDoor.first); //UID
              }
         } else {  //only one specific goal, goalToLineUIDmap gets
                   //populated in Init()
              if ((_goalToLineUIDmap.count(goalID) == 0) || (_goalToLineUIDmap[goalID] == -1)) {
                   Log->Write("ERROR: \t ffRouter: unknown/unreachable goalID: %d in FindExit(Ped)",goalID);
              } else {
                   validFinalDoor.emplace_back(_goalToLineUIDmap.at(goalID));
              }
         }
    
         std::vector<int> DoorUIDsOfRoom;
         DoorUIDsOfRoom.clear();
         if (_building->GetRoom(p->GetRoomID())->GetSubRoom(p->GetSubRoomID())->IsInSubRoom(p->GetPos())) {
              //ped is in the subroom, according to its member attribs
         } else {
              // find next crossing / transition and set new room to the OTHER
              //candidates of current room (ID) (provided by Room)
              for (auto transUID : _building->GetRoom(p->GetRoomID())->GetAllTransitionsIDs()) {
                   if ((_CroTrByUID.count(transUID) != 0) && (_CroTrByUID[transUID]->IsOpen())) {
                        DoorUIDsOfRoom.emplace_back(transUID);
                   }
              }
              for (auto &subIPair : _building->GetRoom(p->GetRoomID())->GetAllSubRooms()) {
                   for (auto &crossI : subIPair.second->GetAllCrossings()) {
                        if (crossI->IsOpen()) {
                             DoorUIDsOfRoom.emplace_back(crossI->GetUniqueID());
                        }
                   }
              }
              //find closest Door
              int UIDofLinePedStandsOn;
              double UIDsDistance = DBL_MAX;
              for (auto dooruid : DoorUIDsOfRoom) {
                   if (UIDsDistance > _locffviafm[p->GetRoomID()]->getCostToDestination(dooruid, p->GetPos(), _mode)) {
                        UIDofLinePedStandsOn = dooruid;
                        UIDsDistance = _locffviafm[p->GetRoomID()]->getCostToDestination(dooruid, p->GetPos(), _mode);
                   }
              }
    
              //to that doors, find the (room/subroom) tuples of both sides of the door and then choose the one, that is not
              //equal to "pedTupel" (which is false information).
              //@todo: @ar.graf: if no second tupel exists, and pedTupel is false, the agent must be outside, right?
              std::pair<int, int> pedTupel = std::make_pair(p->GetRoomID(), p->GetSubRoomID());
    
              std::pair<int, int> roomNsub1 = std::make_pair(
                             _building->GetTransOrCrossByUID(UIDofLinePedStandsOn)->GetSubRoom1()->GetRoomID(),
                             _building->GetTransOrCrossByUID(UIDofLinePedStandsOn)->GetSubRoom1()->GetSubRoomID());
              std::pair<int, int> roomNsub2;
              if (_building->GetTransOrCrossByUID(UIDofLinePedStandsOn)->GetSubRoom2()) {
                   roomNsub2 = std::make_pair(
                             _building->GetTransOrCrossByUID(UIDofLinePedStandsOn)->GetSubRoom2()->GetRoomID(),
                             _building->GetTransOrCrossByUID(UIDofLinePedStandsOn)->GetSubRoom2()->GetSubRoomID());
              } else { // if no second exists, then door leads to outside and nothing should change, which we do by roomNsub1 == roomNsub2
                   roomNsub2 = std::make_pair(
                             _building->GetTransOrCrossByUID(UIDofLinePedStandsOn)->GetSubRoom1()->GetRoomID(),
                             _building->GetTransOrCrossByUID(UIDofLinePedStandsOn)->GetSubRoom1()->GetSubRoomID());
              }
              if (pedTupel == roomNsub1) {
                   p->SetRoomID(roomNsub2.first, _building->GetRoom(roomNsub2.first)->GetCaption());
                   p->SetSubRoomID(roomNsub2.second);
                   p->SetSubRoomUID(_building->GetRoom(roomNsub2.first)->GetSubRoom(roomNsub2.second)->GetUID());
              } else {
                   p->SetRoomID(roomNsub1.first, _building->GetRoom(roomNsub1.first)->GetCaption());
                   p->SetSubRoomID(roomNsub1.second);
                   p->SetSubRoomUID(_building->GetRoom(roomNsub1.first)->GetSubRoom(roomNsub1.second)->GetUID());
              }
    
              //Log->Write("ERROR: \tffRouter cannot handle incorrect room/subroom attribs of pedestrian %d!!", p->GetID());
         }
         DoorUIDsOfRoom.clear();
         if (!_targetWithinSubroom) {
              //candidates of current room (ID) (provided by Room)
              for (auto transUID : _building->GetRoom(p->GetRoomID())->GetAllTransitionsIDs()) {
                   if ((_CroTrByUID.count(transUID) != 0) && (_CroTrByUID[transUID]->IsOpen())) {
                        DoorUIDsOfRoom.emplace_back(transUID);
                   }
              }
              for (auto &subIPair : _building->GetRoom(p->GetRoomID())->GetAllSubRooms()) {
                   for (auto &crossI : subIPair.second->GetAllCrossings()) {
                        if (crossI->IsOpen()) {
                             DoorUIDsOfRoom.emplace_back(crossI->GetUniqueID());
                        }
                   }
              }
         }
         else
         {
              //candidates of current subroom only
              for (auto &crossI : _building->GetRoom(p->GetRoomID())->GetSubRoom(p->GetSubRoomID())->GetAllCrossings()) {
                   if (crossI->IsOpen()) {
                        DoorUIDsOfRoom.emplace_back(crossI->GetUniqueID());
                   }
              }
    
              for (auto &transI : _building->GetRoom(p->GetRoomID())->GetSubRoom(p->GetSubRoomID())->GetAllTransitions()) {
                   if (transI->IsOpen()) {
                        DoorUIDsOfRoom.emplace_back(transI->GetUniqueID());
                   }
              }
         }
    
         int bestFinalDoor = -1; // to silence the compiler
         for(int finalDoor : validFinalDoor) {
              //with UIDs, we can ask for shortest path
              for (int doorUID : DoorUIDsOfRoom) {
                   double locDistToDoor = _locffviafm[p->GetRoomID()]->getCostToDestination(doorUID, p->GetPos(), _mode);
                   if (locDistToDoor < -J_EPS) {     //for old ff: //this can happen, if the point is not reachable and therefore has init val -7
                        continue;
                   }
                   std::pair<int, int> key = std::make_pair(doorUID, finalDoor);
                   //auto subroomDoors = _building->GetSubRoomByUID(p->GetSubRoomUID())->GetAllGoalIDs();
                   //only consider, if paths exists
                   if (_pathsMatrix.count(key)==0) {
                        Log->Write("no key for %d %d", key.first, key.second);
                        continue;
                   }
    
                   if ((_distMatrix.count(key)!=0) && (_distMatrix.at(key) != DBL_MAX)) {
                        if ((_distMatrix.at(key) + locDistToDoor) < minDist) {
                             minDist = _distMatrix.at(key) + locDistToDoor;
                             bestDoor = key.first; //doorUID
                             bestFinalDoor = key.second;
                        }
                   }
              }
         }
    
         //at this point, bestDoor is either a crossing or a transition
         if ((!_targetWithinSubroom) && (_CroTrByUID.count(bestDoor) != 0)) {
              while (!_CroTrByUID[bestDoor]->IsTransition()) {
                   std::pair<int, int> key = std::make_pair(bestDoor, bestFinalDoor);
                   bestDoor = _pathsMatrix[key];
              }
         }
    
    #pragma omp critical(finalDoors)
         _finalDoors.emplace(std::make_pair(p->GetID(), bestFinalDoor));
    
         if (_CroTrByUID.count(bestDoor)) {
              p->SetExitIndex(bestDoor);
              p->SetExitLine(_CroTrByUID.at(bestDoor));
         }
         //debug
    //     if ((p->GetID() == 15) && ((p->GetSubRoomID() == 24) || (p->GetSubRoomID() == 26))) {
    //          Log->Write("\nBest Door UID %d alias %d to final door %d", bestDoor, _CroTrByUID.at(bestDoor)->GetID(), _CroTrByUID.at(bestGoal)->GetID());
    //          Log->Write("\n(Room) %d\t(Sub) %d \tRouting goes to:", p->GetRoomID(), p->GetSubRoomID());
    //          int temp = bestDoor;
    //          while (temp != bestGoal) {
    //               Log->Write("\t%d", _CroTrByUID.at(temp)->GetID());
    //               std::pair<int, int> key = std::make_pair(temp, bestGoal);
    //               temp = _pathsMatrix[key];
    //          }
    //     }
         return bestDoor; //-1 if no way was found, doorUID of best, if path found
    }
    
    void FFRouter::FloydWarshall()
    {
         int totalnum = _allDoorUIDs.size();
         for(int k = 0; k<totalnum; ++k) {
              for(int i = 0; i<totalnum; ++i) {
                   for(int j= 0; j<totalnum; ++j) {
                        std::pair<int, int> key_ij = std::make_pair(_allDoorUIDs[i], _allDoorUIDs[j]);
                        std::pair<int, int> key_ik = std::make_pair(_allDoorUIDs[i], _allDoorUIDs[k]);
                        std::pair<int, int> key_kj = std::make_pair(_allDoorUIDs[k], _allDoorUIDs[j]);
                        if(_distMatrix[key_ik] + _distMatrix[key_kj] < _distMatrix[key_ij]) {
                             _distMatrix.erase(key_ij);
                             _distMatrix.insert(std::make_pair(key_ij, _distMatrix[key_ik] + _distMatrix[key_kj]));
                             _pathsMatrix.erase(key_ij);
                             _pathsMatrix.insert(std::make_pair(key_ij, _pathsMatrix[key_ik]));
                             _subroomMatrix.erase(key_ij);
                             _subroomMatrix.insert(std::make_pair(key_ij, _subroomMatrix[key_ik]));
                        }
                   }
              }
         }
    }
    
    //void FFRouter::AvoidDoorHopping() {
    //     std::chrono::time_point<std::chrono::system_clock> start, end;
    //     start = std::chrono::system_clock::now();
    //
    //     // it's already very fast (< 0.1s) -- no need to parallelize
    ////#pragma omp parallel for
    //     for (auto pathsIt : _pathsMatrix) {
    //          auto key = pathsIt.first;
    //          if (key.first == key.second) continue;
    //          if (_distMatrix[key] == DBL_MAX) {
    //               continue;
    //          }
    //          auto subroom = _subroomMatrix.at(key);
    //          if (!subroom) continue;
    //
    //          auto nextDoorUID = pathsIt.second;
    //          auto nextDoor = _CroTrByUID.at(nextDoorUID);
    //          auto finalDoor = key.second;
    //
    //          if (_targetWithinSubroom) {
    //               int doorLeavingSubroom = -1; // initialization only needed in case of error
    //
    //               if (_CroTrByUID.at(nextDoorUID)->GetSubRoom1() == subroom || _CroTrByUID.at(nextDoorUID)->GetSubRoom2() == subroom) {
    //                    doorLeavingSubroom = key.first;
    //                    Crossing* doorAfterNext;
    //                    do {
    //                         doorLeavingSubroom = _pathsMatrix.at(std::make_pair(doorLeavingSubroom, finalDoor));
    //                         if (doorLeavingSubroom == finalDoor) break;
    //                         auto doorAfterNextUID = _pathsMatrix.at(std::make_pair(doorLeavingSubroom, finalDoor));
    //                         doorAfterNext = _CroTrByUID.at(doorAfterNextUID);
    //                    } while (doorAfterNext->GetSubRoom1() == subroom || doorAfterNext->GetSubRoom2() == subroom);
    //               } else {
    //                    Log->Write("ERROR \tFFRouter::AvoidDoorHopping: sub is %p (UID %d), nextDoorUID/ID is %d/%d", subroom, subroom?subroom->GetUID():-1, nextDoorUID, nextDoor->GetID());
    //               }
    ////#pragma omp critical(_pathsMatrix)
    //               _pathsMatrix.at(key) = doorLeavingSubroom;
    //               if (_pathsMatrix.at(key) == -1) {
    //                    Log->Write("ERROR \tFFRouter::AvoidDoorHopping(): _pathsMatrix got assigned a value of -1 for key %d, %d", key.first, key.second);
    //               }
    //          } else {
    //               int doorLeavingRoom = -1; // initialization only needed in case of error
    //               auto room = _building->GetRoom(subroom->GetRoomID());
    //
    //               auto tr = dynamic_cast<Transition*>(_CroTrByUID.at(nextDoorUID));
    //               if (room && (_CroTrByUID.at(nextDoorUID)->GetRoom1() == room || (tr && tr->GetRoom2() == room))) {
    //                    Transition* doorAfterNext;
    //                    int doorAfterNextUID = key.first;
    //                    do {
    //                         doorLeavingRoom = doorAfterNextUID;
    //
    //                         do {
    //                              doorAfterNextUID = _pathsMatrix.at(std::make_pair(doorAfterNextUID, finalDoor));
    //                         } while (doorAfterNextUID != finalDoor && !(doorAfterNext = dynamic_cast<Transition*>(_CroTrByUID.at(doorAfterNextUID))));
    //
    //                         if (doorAfterNextUID == finalDoor) {
    //                              if (doorLeavingRoom == key.first) {
    //                                   // handles the case in which in the final door is in the room we are going to enter
    //                                   doorLeavingRoom = finalDoor;
    //                              }
    //                              break;
    //                         }
    //
    //                    } while (doorAfterNext->GetRoom1() == room || doorAfterNext->GetRoom2() == room);
    //               } else {
    //                    Log->Write("ERROR \tFFRouter::AvoidDoorHopping: room is %p (ID %d), nextDoorUID/ID is %d/%d", room, room ? room->GetID() : -1, nextDoorUID, nextDoor->GetID());
    //               }
    ////#pragma omp critical(_pathsMatrix)
    //               _pathsMatrix.at(key) = doorLeavingRoom;
    //               if (_pathsMatrix.at(key) == -1) {
    //                    Log->Write("ERROR \tFFRouter::AvoidDoorHopping(): _pathsMatrix got assigned a value of -1 for key %d, %d", key.first, key.second);
    //               }
    //          }
    //     }
    //
    //     end = std::chrono::system_clock::now();
    //     std::chrono::duration<double> elapsed_seconds = end-start;
    //     Log->Write("INFO: \tTime in AvoidDoorHopping: " + std::to_string(elapsed_seconds.count()));
    //}
    
    void FFRouter::SetMode(std::string s)
    {
         if (s == "global_shortest"){
              _mode = global_shortest;
              return;
         }
    
         if (s == "quickest") {
              _mode = quickest;
              return;
         }
    
         _mode = global_shortest;
         return;
    }
    
    bool FFRouter::MustReInit() {
         return _plzReInit;
    }
    
    void FFRouter::SetRecalc(double t) {
         _timeToRecalc = t + _recalc_interval;
    }