Commit 0e5c688f authored by Ulrich Kemloh's avatar Ulrich Kemloh

Refactoring events manager and part merging of the information sharing.

parent 5c9d5b77
......@@ -26,7 +26,7 @@ the implied warranties of merchantability and fitness for a particular purpose.
The software and accompanying documentation, if any, provided hereunder is
provided “as is”. JuPedSim has no obligation to provide maintenance, support,
updates, enhancements, or modifications.
Forschungszentrum J ̈ulich GmbH makes no warranty, expressed or implied,
Forschungszentrum Julich GmbH makes no warranty, expressed or implied,
to users of JuPedSim, and accepts no responsibility for its use. Users of JuPedSim
assume sole responsibility for determining the appropriateness of its use; and for
any actions taken or not taken as a result of analyses performed using this tool.
......
......@@ -292,15 +292,15 @@ int Simulation::RunSimulation()
// update the positions
_operationalModel->ComputeNextTimeStep(t, _deltaT, _building.get());
// update the routes and locations
//Update();
//update the routes and locations
UpdateRoutesAndLocations();
//update the events
_em->Update_Events(t, _deltaT);
_em->Update_Events(t);
//_em->ProcessEvent();
//other updates
//someone might have leave the building
//someone might have left the building
_nPeds = _building->GetAllPedestrians().size();
//update the linked cells
......
......@@ -30,10 +30,13 @@
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <fstream>
#include <vector>
#include <math.h>
#include <stdio.h>
#include "../pedestrian/Pedestrian.h"
#include "../mpi/LCGrid.h"
#include "../geometry/Building.h"
#include "../geometry/SubRoom.h"
#include "../geometry/Transition.h"
......@@ -43,6 +46,13 @@
#include "../IO/IODispatcher.h"
#include "../routing/RoutingEngine.h"
#include "../pedestrian/Pedestrian.h"
#include "../routing/GlobalRouter.h"
#include "../routing/QuickestPathRouter.h"
#include "../routing/GraphRouter.h"
#include "../routing/MeshRouter.h"
#include "../routing/DummyRouter.h"
#include "../routing/SafestPathRouter.h"
#include "../routing/CognitiveMapRouter.h"
#include "EventManager.h"
using namespace std;
......@@ -59,34 +69,26 @@ EventManager::EventManager(Building *_b)
_event_types = vector<string>();
_event_states = vector<string>();
_event_ids = vector<int>();
_projectFilename = "";
_building = _b;
_eventCounter = 0;
_dynamic = false;
_file = fopen("../events/events.txt", "r");
_lastUpdateTime = 0;
_deltaT = 0;
this->SetProjectFilename(_building->GetProjectFilename());
this->SetProjectRootDir(_building->GetProjectRootDir());
//_deltaT = 0;
_projectFilename=_building->GetProjectFilename();
_projectRootDir=_building->GetProjectRootDir();
_file = fopen("../events/events.txt", "r");
if (!_file) {
Log->Write(
"INFO:\tFiles 'events.txt' missing. Realtime interaction with the simulation not possible.");
Log->Write("INFO:\tFiles 'events.txt' missing. "
"Realtime interaction with the simulation not possible.");
} else {
Log->Write(
"INFO:\tFile 'events.txt' will be monitored for new events.");
Log->Write("INFO:\tFile 'events.txt' will be monitored for new events.");
_dynamic = true;
}
}
void EventManager::SetProjectFilename(const std::string &filename)
{
_projectFilename = filename;
}
void EventManager::SetProjectRootDir(const std::string &filename)
{
_projectRootDir = filename;
//save the first graph
CreateRoutingEngine(_b, true);
}
bool EventManager::ReadEventsXml()
......@@ -143,27 +145,18 @@ bool EventManager::ReadEventsXml()
_event_states.push_back(e->Attribute("state"));
_event_ids.push_back(atoi(e->Attribute("id")));
}
Log->Write("INFO: \tEvents were initialized\n");
Log->Write("INFO: \tEvents were initialized");
return true;
}
void EventManager::ListEvents()
{
if (_event_times.size() == 0) {
//this notification was already printed ealier
//Log->Write("INFO: \tNo events in the events.xml");
} else {
char buf[10], buf2[10];
for (unsigned int i = 0; i < _event_times.size(); i++) {
sprintf(buf, "%f", _event_times[i]);
sprintf(buf2, "%d", _event_ids[i]);
Log->Write(
"INFO: \tAfter " + string(buf) + " sec: "
+ _event_types[i] + " " + string(buf2) + " "
+ _event_states[i]);
}
for (unsigned int i = 0; i < _event_times.size(); i++)
{
Log->Write("INFO: \tAfter %.2f sec, %s door %d", _event_times[i],
_event_states[i].c_str(), _event_ids[i]);
}
}
void EventManager::ReadEventsTxt(double time)
......@@ -176,7 +169,7 @@ void EventManager::ReadEventsTxt(double time)
Log->Write("WARNING: \tCould not read the event file");
return;
}
if (cstring[0] != '#') { // keine Kommentarzeile
if (cstring[0] != '#') {// skip comments
lines++;
if (lines > _eventCounter) {
Log->Write("INFO:\tEvent: after %f sec: ", time);
......@@ -191,7 +184,175 @@ void EventManager::ReadEventsTxt(double time)
Update
**********/
void EventManager::Update_Events(double time, double d)
bool EventManager::UpdateAgentKnowledge(Building* _b)
{
#pragma omp parallel
for(auto&& ped:_b->GetAllPedestrians())
{
for (auto&& door: _b->GetAllTransitions())
{
if(door.second->DistTo(ped->GetPos())<0.2) //TODO: put 0.c metre in macro
{
//actualize the information about the newly closed door
if(door.second->IsOpen()==false)
ped->AddKnownClosedDoor(door.first, Pedestrian::GetGlobalTime());
}
}
}
for(auto&& ped1:_b->GetAllPedestrians())
{
vector<Pedestrian*> neighbourhood;
_b->GetGrid()->GetNeighbourhood(ped1,neighbourhood);
for(auto&& ped2:neighbourhood)
{
if( (ped1->GetPos()-ped2->GetPos()).Norm()<J_EPS_INFO_DIST)
{
//maybe same room and subroom ?
//if(_b->IsVisible(ped1->GetPos(),ped2->GetPos()))
MergeKnowledge(ped1, ped2);
}
}
}
//update the routers based on the configurations
//#pragma omp parallel
for(auto&& ped:_b->GetAllPedestrians())
{
if(UpdateRoute(ped)==false)
{
//Clear the memory and attempt to reroute
//this can happen if all doors are known to be closed
ped->ClearKnowledge();
if(UpdateRoute(ped)==false)
{
Log->Write("ERROR: \t cannot reroute the pedestrian. unknown problem");
//return false;
exit(EXIT_FAILURE);
}
}
}
return true;
}
bool EventManager::UpdateRoute(Pedestrian* ped)
{
//create the key as string.
//map are sorted by default
string key="";
for(auto&& knowledge:ped->GetKnownledge())
{
int door=knowledge.first;
if(key.empty())
key.append(std::to_string(door));
else
key.append(":"+std::to_string(door));
}
//get the router engine corresponding to the actual configuration
bool status=true;
if (_eventEngineStorage.count(key)>0)
{
RoutingEngine* engine=_eventEngineStorage[key];
//retrieve the old strategy
RoutingStrategy strategy=ped->GetRouter()->GetStrategy();
//retrieve the new router
Router*rout =engine->GetRouter(strategy);
//check for validity
ped->SetRouter(rout);
//overwrite/update the pedestrian router
if(!rout) status= false;
}
else
{
Log->Write("ERROR: \t unknown configuration %s", key.c_str());
Log->Write("ERROR: \t [%d] router available", _eventEngineStorage.size());
status= false;
}
return status;
}
void EventManager::MergeKnowledge(Pedestrian* p1, Pedestrian* p2)
{
const map<int, NavLineState>& old_info1=p1->GetKnownledge();
const map<int, NavLineState>& old_info2=p2->GetKnownledge();
map<int, NavLineState> merge_info;
//map<int, double> merge_info;
//collect the most recent knowledge
for (auto&& info1 : old_info1)
{
merge_info[info1.first] = info1.second;
}
for (auto&& info2:old_info2)
{
//update infos according to a newest time
if(merge_info.count(info2.first)>0)
{
if(info2.second.GetTime()>merge_info[info2.first].GetTime())
{
merge_info[info2.first]=info2.second;
}
}
else //just add
{
merge_info[info2.first]=info2.second;
}
}
//synchronize the knowledge
p1->ClearKnowledge();
p2->ClearKnowledge();
for (auto&& info : merge_info)
{
p1->AddKnownClosedDoor(info.first,info.second.GetTime());
p2->AddKnownClosedDoor(info.first,info.second.GetTime());
}
}
void EventManager::ProcessEvent()
{
//const vector<Pedestrian*>& _allPeds = _building->GetAllPedestrians();
if (_event_times.size() == 0) return;
int current_time = Pedestrian::GetGlobalTime();
if ( (current_time != _lastUpdateTime) &&
((current_time % UPDATE_FREQUENCY) == 0))
{
//update knowledge about closed doors
//share the information between the pedestrians
UpdateAgentKnowledge(_building);
//actualize based on the new knowledge
_lastUpdateTime = current_time;
//cout<<"updating..."<<currentTime<<endl<<endl;
}
//update the building state
// the time is needed as double
double current_time_d = Pedestrian::GetGlobalTime();
for (unsigned int i = 0; i < _event_times.size(); i++)
{
if (fabs(_event_times[i] - current_time_d) < J_EPS_EVENT) {
//Event with current time stamp detected
Log->Write("INFO:\tEvent: after %f sec: ", current_time_d);
if (_event_states[i].compare("close") == 0) {
CloseDoor(_event_ids[i]);
} else {
OpenDoor(_event_ids[i]);
}
}
}
if (_dynamic)
ReadEventsTxt(current_time);
}
void EventManager::Update_Events(double time )
{
//1. pruefen ob in _event_times der zeitstempel time zu finden ist. Wenn ja zu 2. sonst zu 3.
//2. Event aus _event_times und _event_values verarbeiten (Tuere schliessen/oeffnen, neues Routing)
......@@ -199,51 +360,47 @@ void EventManager::Update_Events(double time, double d)
//3. .txt Datei auf neue Zeilen pruefen. Wenn es neue gibt diese Events verarbeiten ( Tuere schliessen/oeffnen,
// neues Routing) ansonsten fertig
_deltaT = d;
//_deltaT = d;
const vector<Pedestrian*>& _allPeds = _building->GetAllPedestrians();
//zuerst muss geprueft werden, ob die Peds, die die neuen Infos schon haben sie an andere Peds weiter-
//leiten muessen (wenn diese sich in der naechsten Umgebung befinden)
int currentTime = _allPeds[0]->GetGlobalTime();
if (currentTime != _lastUpdateTime)
if ((currentTime % UPDATE_FREQUENCY) == 0) {
for (unsigned int p1 = 0; p1 < _allPeds.size(); p1++) {
Pedestrian* ped1 = _allPeds[p1];
if (ped1->GetNewEventFlag()) {
int rID = ped1->GetRoomID();
int srID = ped1->GetSubRoomID();
for (unsigned int p2 = 0; p2 < _allPeds.size(); p2++) {
Pedestrian* ped2 = _allPeds[p2];
//same room and subroom
if (rID == ped2->GetRoomID()
&& srID == ped2->GetSubRoomID()) {
if (!ped2->GetNewEventFlag()
&& ped2->GetReroutingTime()
> 2.0) {
//wenn der Pedestrian die neuen Infos noch nicht hat und eine Reroutingtime von > 2 Sekunden hat, pruefen ob er nah genug ist
Point pos1 = ped1->GetPos();
Point pos2 = ped2->GetPos();
double distX = pos1.GetX()
- pos2.GetX();
double distY = pos1.GetY()
- pos2.GetY();
double dist = sqrt(
distX * distX
+ distY * distY);
if (dist <= J_EPS_INFO_DIST) { // wenn er nah genug (weniger als 2m) ist, Info weitergeben (Reroutetime auf 2 Sek)
//ped->RerouteIn(2.0);
ped2->RerouteIn(0.0);
}
//int currentTime = _allPeds[0]->GetGlobalTime();
int currentTime = Pedestrian::GetGlobalTime();
if ( (currentTime != _lastUpdateTime) &&
((currentTime % UPDATE_FREQUENCY) == 0))
{
for (unsigned int p1 = 0; p1 < _allPeds.size(); p1++) {
Pedestrian* ped1 = _allPeds[p1];
if (ped1->GetNewEventFlag()) {
int rID = ped1->GetRoomID();
int srID = ped1->GetSubRoomID();
for (unsigned int p2 = 0; p2 < _allPeds.size(); p2++) {
Pedestrian* ped2 = _allPeds[p2];
//same room and subroom
if (rID == ped2->GetRoomID()
&& srID == ped2->GetSubRoomID()) {
if (!ped2->GetNewEventFlag()
&& ped2->GetReroutingTime()
> 2.0) {
//wenn der Pedestrian die neuen Infos noch nicht hat und eine Reroutingtime von > 2 Sekunden hat, pruefen ob er nah genug ist
double dist= (ped1->GetPos()-ped2->GetPos()).Norm();
if (dist <= J_EPS_INFO_DIST) { // wenn er nah genug (weniger als 2m) ist, Info weitergeben (Reroutetime auf 2 Sek)
//ped->RerouteIn(2.0);
ped2->RerouteIn(0.0);
}
}
}
}
}
_lastUpdateTime = currentTime;
//cout<<"updating..."<<currentTime<<endl<<endl;
}
_lastUpdateTime = currentTime;
//cout<<"updating..."<<currentTime<<endl<<endl;
}
//dann muss die Reroutingzeit der Peds, die die neuen Infos noch nicht haben, aktualisiert werden:
for (unsigned int p1 = 0; p1 < _allPeds.size(); p1++) {
......@@ -259,7 +416,7 @@ void EventManager::Update_Events(double time, double d)
//Events finden
for (unsigned int i = 0; i < _event_times.size(); i++) {
if (fabs(_event_times[i] - time) < J_EPS_EVENT) {
//Event findet statt
//Event with current time stamp detected
Log->Write("INFO:\tEvent: after %f sec: ", time);
if (_event_states[i].compare("close") == 0) {
CloseDoor(_event_ids[i]);
......@@ -268,18 +425,18 @@ void EventManager::Update_Events(double time, double d)
}
}
}
if (_dynamic)
ReadEventsTxt(time);
}
/***************
Eventhandling
Event handling
**************/
//close the door if it was open and relaunch the routing procedure
void EventManager::CloseDoor(int id)
{
Transition *t = _building->GetTransition(id);
if (t->IsOpen()) {
t->Close();
......@@ -306,49 +463,37 @@ void EventManager::OpenDoor(int id)
void EventManager::ChangeRouting(int id, const std::string& state)
{
RoutingEngine* routingEngine = _building->GetRoutingEngine();
routingEngine->Init(_building);
//_building->InitPhiAllPeds(_deltaT);
const vector<Pedestrian*>& _allPedestrians =
_building->GetAllPedestrians();
unsigned int nSize = _allPedestrians.size();
//Pedestrians sollen, damit es realitaetsnaeher wird, je nachdem wo sie stehen erst spaeter(abh. von der
//Entfernung zur Tuer) merken, dass sich Tueren aendern. Oder sie bekommen die Info von anderen Pedestrians
Transition *t = _building->GetTransition(id);
//Abstand der aktuellen Position des Pedestrians zur entsprechenden Tuer: Tuer als Linie sehen und mit
//DistTo(ped.GetPos()) den Abstand messen. Reroutezeit dann aus Entfernung und Geschwindigkeit berechnen.
Line* l = new Line(t->GetPoint1(), t->GetPoint2());
for (unsigned int p = 0; p < nSize; ++p) {
for(auto&& ped:_building->GetAllPedestrians())
{
//if(_allPedestrians[p]->GetExitIndex()==t->GetUniqueID()){
_allPedestrians[p]->SetNewEventFlag(false);
double dist = l->DistTo(_allPedestrians[p]->GetPos());
Point v = _allPedestrians[p]->GetV();
double norm = sqrt((v.GetX() * v.GetX()) + (v.GetY() * v.GetY()));
ped->SetNewEventFlag(false);
double dist = t->DistTo(ped->GetPos());
const Point& v = ped->GetV();
double norm = v.Norm();
if (norm == 0.0) {
norm = 0.01;
}
double time = dist / norm;
if (time < 1.0) {
_allPedestrians[p]->ClearMentalMap();
_allPedestrians[p]->ResetRerouting();
_allPedestrians[p]->SetNewEventFlag(true);
ped->ClearMentalMap();
ped->ResetRerouting();
ped->SetNewEventFlag(true);
} else {
_allPedestrians[p]->RerouteIn(time);
ped->RerouteIn(time);
}
//if(dist>0.0&&dist<0.5){
// _allPedestrians[p]->ClearMentalMap();
//}
//else if(dist>=0.5&&dist<3.0){
// _allPedestrians[p]->RerouteIn(1.0);
//}
//else{
// _allPedestrians[p]->RerouteIn(2.0);
//}
//}
//else{
// _allPedestrians[p]->ClearMentalMap();
//}
}
//Create and save a graph corresponding to the actual state of the building.
if(CreateRoutingEngine(_building)==false)
{
Log->Write("ERROR: \tcannot create a routing engine with the new event");
}
}
......@@ -381,3 +526,116 @@ void EventManager::GetEvent(char* c)
OpenDoor(atoi(id.c_str()));
}
}
bool EventManager::CreateRoutingEngine(Building* _b, int first_engine)
{
std::vector<int> closed_doors;
for(auto&& t:_b->GetAllTransitions())
{
if(t.second->IsOpen()==false)
closed_doors.push_back(t.second->GetID());
}
std::sort(closed_doors.begin(), closed_doors.end());
//create the key as string.
string key="";
for(int door:closed_doors)
{
if(key.empty())
key.append(std::to_string(door));
else
key.append(":"+std::to_string(door));
}
//the first (default) engine was created in the simulation
// collect the defined routers
if(first_engine)
{
RoutingEngine* engine=_b->GetRoutingEngine();
_eventEngineStorage[key]=engine;
for(auto&& rout: engine->GetAvailableRouters())
{
_availableRouters.push_back(rout->GetStrategy());
}
Log->Write("INFO: \tAdding a new routing Engine with the key: "+key+"\n");
return true;
}
// the engine was not created
// create a new one with the actual configuration
if (_eventEngineStorage.count(key)==0)
{
//std::shared_ptr<RoutingEngine> engine = std::shared_ptr<RoutingEngine>(new RoutingEngine());
//engine.get()->Init(_b);
//_eventEngineStorage[key]=engine.get();
//populate the engine with the routers defined in the ini file
//and initialize
RoutingEngine* engine= new RoutingEngine();
for(auto&& rout:_availableRouters)
{
engine->AddRouter(CreateRouter(rout));
}
if(engine->Init(_b)==false)
return false;
//save the configuration
_eventEngineStorage[key]=engine;
Log->Write("INFO: \tAdding a new routing Engine with the key: "+key+"\n");
}
else
{
Log->Write("INFO: \tA routing already exits with the key: "+key+"\n");
}
return true;
}
Router * EventManager::CreateRouter(const RoutingStrategy& strategy)
{
Router * rout=NULL;
switch(strategy)
{
case ROUTING_LOCAL_SHORTEST:
rout = new GlobalRouter(ROUTING_LOCAL_SHORTEST, ROUTING_LOCAL_SHORTEST);
break;
case ROUTING_GLOBAL_SHORTEST:
rout = new GlobalRouter(ROUTING_GLOBAL_SHORTEST, ROUTING_GLOBAL_SHORTEST);
break;
case ROUTING_QUICKEST:
rout = new QuickestPathRouter(ROUTING_QUICKEST, ROUTING_QUICKEST);
break;
case ROUTING_DYNAMIC:
rout = new GraphRouter(ROUTING_DYNAMIC, ROUTING_DYNAMIC);
break;
case ROUTING_NAV_MESH:
rout = new MeshRouter(ROUTING_NAV_MESH, ROUTING_NAV_MESH);
break;
case ROUTING_DUMMY:
rout = new DummyRouter(ROUTING_DUMMY, ROUTING_DUMMY);
break;
case ROUTING_SAFEST:
rout = new SafestPathRouter(ROUTING_SAFEST, ROUTING_SAFEST);
break;
case ROUTING_COGNITIVEMAP:
rout = new CognitiveMapRouter(ROUTING_COGNITIVEMAP, ROUTING_COGNITIVEMAP);
break;
default:
Log->Write("ERROR: \twrong value for routing strategy [%d]!!!\n", strategy );
break;
}
return rout;
}
......@@ -29,6 +29,10 @@
#include <string>
class Building;
class Router;
class GlobalRouter;
class QuickestPathRouter;
class RoutingEngine;
extern OutputHandler* Log;
......@@ -42,22 +46,83 @@ private:
std::string _projectFilename;
std::string _projectRootDir;
Building *_building;
double _deltaT;
FILE *_file;
bool _dynamic;
int _eventCounter;
long int _lastUpdateTime;
//save the router corresponding to the actual state of the building
std::map<std::string, RoutingEngine*> _eventEngineStorage;
//save the available routers defined in the simulation
std::vector<RoutingStrategy> _availableRouters;
private:
/**
* collect the close doors and generate a new graph
* @param _building
*/
bool CreateRoutingEngine(Building* _b, int first_engine=false);
/**
* Create a router corresponding to the given strategy
* @param strategy
* @return a router/NULL for invalid strategies
*/
Router * CreateRouter(const RoutingStrategy& strategy);
/**
* Update the knowledge about closed doors.
* Each pedestrian who is xx metres from a closed door,
* will save that information
* @param _b, the building object
*/
bool UpdateAgentKnowledge(Building* _b);
/**
* Merge the knowledge of the two pedestrians.
* The information with the newest timestamp
* is always accepted with a probability of one.
* @param p1, first pedestrian
* @param p2, second pedestrian
*/
void MergeKnowledge(Pedestrian* p1, Pedestrian* p2);
/**
* Update the pedestrian route based on the new information
* @param p1
* @return
*/
bool UpdateRoute(Pedestrian* p1);
public:
//constructor
///constructor
EventManager(Building *_b);
void SetProjectFilename(const std::string &filename);
void SetProjectRootDir(const std::string &filename);
/**
* Read and parse the events
* @return false if an error occured
*/
bool ReadEventsXml();
/**
* Print the parsed events
*/
void ListEvents();
/**
* Read and parse events from a text file
* @param time
*/
void ReadEventsTxt(double time);
//Update
void Update_Events(double time, double d);
/**
* Process the events at runtime
* @param time
*/
void Update_Events(double time);
//process the event using the current time stamp
//from the pedestrian class
void ProcessEvent();
//Eventhandling
void CloseDoor(int id);
void OpenDoor(int id);
......
......@@ -699,7 +699,7 @@ void Building::AddHline(Hline* line)