Simulation.cpp 18.1 KB
Newer Older
1
/**
Weichen's avatar
Weichen committed
2 3
 * \file        Simulation.cpp
 * \date        Dec 15, 2010
4
 * \version     v0.6
Weichen's avatar
Weichen committed
5
 * \copyright   <2009-2014> Forschungszentrum Jülich GmbH. All rights reserved.
6
 *
Weichen's avatar
Weichen committed
7
 * \section License
8 9 10
 * This file is part of JuPedSim.
 *
 * JuPedSim is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Lesser General Public License as published by
12 13 14 15 16 17 18 19
 * 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.
 *
20
 * You should have received a copy of the GNU Lesser General Public License
Weichen's avatar
Weichen committed
21
 * along with JuPedSim. If not, see <http://www.gnu.org/licenses/>.
22
 *
23
 * \section Description
24 25 26 27
 * The Simulation class represents a simulation of pedestrians
 * based on a certain model in a specific scenario. A simulation is defined by
 * various parameters and functions.
 *
Weichen's avatar
Weichen committed
28 29 30
 *
 **/

Ulrich Kemloh's avatar
Ulrich Kemloh committed
31 32
#include "Simulation.h"

Ulrich Kemloh's avatar
Ulrich Kemloh committed
33 34
#include "math/GCFMModel.h"
#include "math/GompertzModel.h"
35
#include "pedestrian/AgentsQueue.h"
36
#include "pedestrian/AgentsSourcesManager.h"
37 38

#ifdef _USE_PROTOCOL_BUFFER
39
#include "matsim/HybridSimulationManager.h"
40
#endif
41 42 43

#ifdef _OPENMP
#include <omp.h>
44

45 46 47 48 49
#else
#define omp_get_thread_num() 0
#define omp_get_max_threads()  1
#endif

Ulrich Kemloh's avatar
Ulrich Kemloh committed
50
using namespace std;
Ulrich Kemloh's avatar
Ulrich Kemloh committed
51

52 53
OutputHandler* Log;

54
Simulation::Simulation(const ArgumentParser& args)
55 56
{
     _nPeds = 0;
57
     _seed = 8091983;
58
     _deltaT = 0;
Oliver Schmidts's avatar
Oliver Schmidts committed
59
     _building = nullptr;
60
     //_direction = NULL;
Oliver Schmidts's avatar
Oliver Schmidts committed
61 62
     _operationalModel = nullptr;
     _solver = nullptr;
63
     _iod = new IODispatcher();
64
     _fps = 1;
Oliver Schmidts's avatar
Oliver Schmidts committed
65
     _em = nullptr;
66
     _argsParser = args;
Ulrich Kemloh's avatar
Ulrich Kemloh committed
67 68
}

69 70 71 72 73
Simulation::~Simulation()
{
     delete _solver;
     delete _iod;
     delete _em;
Ulrich Kemloh's avatar
Ulrich Kemloh committed
74 75
}

Oliver Schmidts's avatar
Oliver Schmidts committed
76
long Simulation::GetPedsNumber() const
77 78
{
     return _nPeds;
Ulrich Kemloh's avatar
Ulrich Kemloh committed
79 80
}

81
bool Simulation::InitArgs(const ArgumentParser& args)
82 83 84 85
{
     char tmp[CLENGTH];
     string s = "Parameter:\n";

86
     switch (args.GetLog())
87
     {
88 89 90 91 92
     case 0:
          // no log file
          //Log = new OutputHandler();
          break;
     case 1:
93 94
          if (Log)
               delete Log;
95 96 97
          Log = new STDIOHandler();
          break;
     case 2: {
98
          char name[CLENGTH] = "";
99
          sprintf(name, "%s.P0.dat", args.GetErrorLogFile().c_str());
100 101
          if (Log)
               delete Log;
102 103
          Log = new FileHandler(name);
     }
104
     break;
105 106
     default:
          printf("Wrong option for Logfile!\n\n");
107
          return false;
108 109
     }

110 111
     if (args.GetPort() != -1) {
          switch (args.GetFileFormat())
112
          {
113 114
          case FORMAT_XML_PLAIN_WITH_MESH:
          case FORMAT_XML_PLAIN: {
115 116
               OutputHandler* travisto = new SocketHandler(args.GetHostname(),
                         args.GetPort());
117
               Trajectories* output = new TrajectoriesJPSV06();
118 119
               output->SetOutputHandler(travisto);
               _iod->AddIO(output);
120 121 122
               break;
          }
          case FORMAT_XML_BIN: {
123 124
               Log->Write(
                         "INFO: \tFormat xml-bin not yet supported in streaming\n");
Ulrich Kemloh's avatar
Ulrich Kemloh committed
125
               //exit(0);
126 127 128
               break;
          }
          case FORMAT_PLAIN: {
129 130 131
               Log->Write(
                         "INFO: \tFormat plain not yet supported in streaming\n");
               return false;
132 133
          }
          case FORMAT_VTK: {
134 135 136
               Log->Write(
                         "INFO: \tFormat vtk not yet supported in streaming\n");
               return false;
137
          }
138 139 140
          default: {
               return false;
          }
141 142 143 144 145
          }

          s.append("\tonline streaming enabled \n");
     }

146 147
     if (args.GetTrajectoriesFile().empty() == false) {
          switch (args.GetFileFormat())
148
          {
149
          case FORMAT_XML_PLAIN: {
150
               OutputHandler* tofile = new FileHandler(
151
                         args.GetTrajectoriesFile().c_str());
152
               Trajectories* output = new TrajectoriesJPSV05();
153 154
               output->SetOutputHandler(tofile);
               _iod->AddIO(output);
155 156 157
               break;
          }
          case FORMAT_PLAIN: {
158
               OutputHandler* file = new FileHandler(
159
                         args.GetTrajectoriesFile().c_str());
160
               Trajectories* output = new TrajectoriesFLAT();
161 162
               output->SetOutputHandler(file);
               _iod->AddIO(output);
163 164 165 166
               break;
          }
          case FORMAT_VTK: {
               Log->Write("INFO: \tFormat vtk not yet supported\n");
167
               OutputHandler* file = new FileHandler(
168
                         (args.GetTrajectoriesFile() + ".vtk").c_str());
169
               Trajectories* output = new TrajectoriesVTK();
170 171 172 173
               output->SetOutputHandler(file);
               _iod->AddIO(output);
               break;
          }
174

175 176 177 178 179 180 181 182 183 184 185 186
          case FORMAT_XML_PLAIN_WITH_MESH: {
               //OutputHandler* tofile = new FileHandler(args->GetTrajectoriesFile().c_str());
               //if(_iod) delete _iod;
               //_iod = new TrajectoriesXML_MESH();
               //_iod->AddIO(tofile);
               break;
          }
          case FORMAT_XML_BIN: {
               // OutputHandler* travisto = new SocketHandler(args->GetHostname(), args->GetPort());
               // Trajectories* output= new TrajectoriesJPSV06();
               // output->SetOutputHandler(travisto);
               // _iod->AddIO(output);
187 188
               break;
          }
189 190 191
          default: {
               break;
          }
192 193 194
          }
     }

Oliver Schmidts's avatar
Oliver Schmidts committed
195

196

197
     _operationalModel = args.GetModel();
198
     s.append(_operationalModel->GetDescription());
199

200
     // ODE solver which is never used!
201
     auto solver = args.GetSolver();
202
     sprintf(tmp, "\tODE Solver: %d\n", solver);
203
     s.append(tmp);
204

205
     sprintf(tmp, "\tnCPU: %d\n", args.GetMaxOpenMPThreads());
Mohcine Chraibi's avatar
Mohcine Chraibi committed
206
     s.append(tmp);
207
     sprintf(tmp, "\tt_max: %f\n", args.GetTmax());
208
     s.append(tmp);
209
     _deltaT = args.Getdt();
210 211 212
     sprintf(tmp, "\tdt: %f\n", _deltaT);
     s.append(tmp);

213
     _fps = args.Getfps();
214 215
     sprintf(tmp, "\tfps: %f\n", _fps);
     s.append(tmp);
216
     //Log->Write(s.c_str());
217

Oliver Schmidts's avatar
Oliver Schmidts committed
218 219
     _routingEngine = args.GetRoutingEngine();
     auto distributor = std::unique_ptr<PedDistributor>(new PedDistributor(_argsParser.GetProjectFile(), _argsParser.GetAgentsParameters(),_argsParser.GetSeed()));
220
     // IMPORTANT: do not change the order in the following..
Oliver Schmidts's avatar
Oliver Schmidts committed
221
     _building = std::unique_ptr<Building>(new Building(args.GetProjectFile(), args.GetProjectRootDir(), *_routingEngine, *distributor, args.GetLinkedCellSize()));
222

223
     // Initialize the agents sources that have been collected in the pedestrians distributor
224
     _agentSrcManager.SetBuilding(_building.get());
225 226 227
     for (const auto& src: distributor->GetAgentsSources())
     {
          _agentSrcManager.AddSource(src);
228
          //src->Dump();
229 230
     }

231
#ifdef _USE_PROTOCOL_BUFFER
232 233 234 235
     //iniitalize the hybridmode if defined
     if(nullptr!=(_hybridSimManager=args.GetHybridSimManager()))
     {
          _hybridSimManager->Init(_building.get());
236
     }
237
#endif
238

239 240 241
     //perform customs initialisation, like computing the phi for the gcfm
     //this should be called after the routing engine has been initialised
     // because a direction is needed for this initialisation.
Oliver Schmidts's avatar
Oliver Schmidts committed
242
     if(_operationalModel->Init(_building.get())==false)
243
          return false;
244 245

     //other initializations
246 247 248 249
     const vector<Pedestrian*>& allPeds = _building->GetAllPedestrians();
     for (Pedestrian *ped : allPeds) {
          ped->Setdt(_deltaT);
     }
Oliver Schmidts's avatar
Oliver Schmidts committed
250
     _nPeds = allPeds.size();
251 252 253
     //pBuilding->WriteToErrorLog();

     //get the seed
254
     _seed = args.GetSeed();
255

256
     //size of the cells/GCFM/Gompertz
257
     if (args.GetDistEffMaxPed() > args.GetLinkedCellSize()) {
258 259
          Log->Write(
                    "ERROR: the linked-cell size [%f] should be bigger than the force range [%f]",
260
                    args.GetLinkedCellSize(), args.GetDistEffMaxPed());
261
          return false;
262
     }
263

Ulrich Kemloh's avatar
Ulrich Kemloh committed
264
     //read and initialize events
Oliver Schmidts's avatar
Oliver Schmidts committed
265
     _em = new EventManager(_building.get());
Ulrich Kemloh's avatar
Ulrich Kemloh committed
266 267 268 269
     if(_em->ReadEventsXml()==false)
     {
          Log->Write("ERROR: \tCould not initialize events handling");
     }
Ulrich Kemloh's avatar
Ulrich Kemloh committed
270
     _em->ListEvents();
271

272
     //_building->SaveGeometry("test.sav.xml");
Ulrich Kemloh's avatar
Ulrich Kemloh committed
273

274 275 276
     //if(_building->SanityCheck()==false)
     //     return false;

277 278 279
     //everything went fine
     return true;
}
Ulrich Kemloh's avatar
Ulrich Kemloh committed
280

281 282
int Simulation::RunStandardSimulation(double maxSimTime)
{
283
     RunHeader(_nPeds + _agentSrcManager.GetMaxAgentNumber());
284 285 286 287 288
     double t=RunBody(maxSimTime);
     RunFooter();
     return (int)t;

}
Ulrich Kemloh's avatar
Ulrich Kemloh committed
289

290
void Simulation::UpdateRoutesAndLocations()
291
{
292 293 294
     //pedestrians to be deleted
     //you should better create this in the constructor and allocate it once.
     vector<Pedestrian*> pedsToRemove;
295
     pedsToRemove.reserve(500); //just reserve some space
296 297

     // collect all pedestrians in the simulation.
298 299
     const vector<Pedestrian*>& allPeds = _building->GetAllPedestrians();
     const map<int, Goal*>& goals = _building->GetAllGoals();
300

301
     unsigned long nSize = allPeds.size();
302 303 304 305 306 307 308 309 310 311 312
     int nThreads = omp_get_max_threads();
     int partSize = nSize / nThreads;

#pragma omp parallel  default(shared) num_threads(nThreads)
     {
          const int threadID = omp_get_thread_num();
          int start = threadID * partSize;
          int end = (threadID + 1) * partSize - 1;
          if ((threadID == nThreads - 1))
               end = nSize - 1;

313
          for (int p = start; p <= end; ++p) {
314 315
               Pedestrian* ped = allPeds[p];
               Room* room = _building->GetRoom(ped->GetRoomID());
316
               SubRoom* sub0 = room->GetSubRoom(ped->GetSubRoomID());
317 318 319

               //set the new room if needed
               if ((ped->GetFinalDestination() == FINAL_DEST_OUT)
320
                         && (room->GetCaption() == "outside")) {
321 322
#pragma omp critical
                    pedsToRemove.push_back(ped);
323 324 325
               } else if ((ped->GetFinalDestination() != FINAL_DEST_OUT)
                         && (goals.at(ped->GetFinalDestination())->Contains(
                                   ped->GetPos()))) {
326 327 328 329 330 331 332
#pragma omp critical
                    pedsToRemove.push_back(ped);
               }

               // reposition in the case the pedestrians "accidently left the room" not via the intended exit.
               // That may happen if the forces are too high for instance
               // the ped is removed from the simulation, if it could not be reassigned
333
               else if (!sub0->IsInSubRoom(ped))
334
               {
335
                    bool assigned = false;
336 337 338
                    auto& allRooms = _building->GetAllRooms();

                    for (auto&& it_room : allRooms)
339
                    {
340 341
                         auto&& room=it_room.second;
                         for (auto&& it_sub : room->GetAllSubRooms())
342
                         {
343 344 345
                              auto&& sub=it_sub.second;
                              auto&& old_room =allRooms.at(ped->GetRoomID());
                              auto&& old_sub =old_room->GetSubRoom(
346
                                        ped->GetSubRoomID());
347 348
                              if ((sub->IsInSubRoom(ped->GetPos()))
                                        && (sub->IsDirectlyConnectedWith(
349 350
                                                  old_sub)))
                              {
351 352 353
                                   ped->SetRoomID(room->GetID(),
                                             room->GetCaption());
                                   ped->SetSubRoomID(sub->GetSubRoomID());
354 355
                                   ped->ClearMentalMap(); // reset the destination
                                   //ped->FindRoute();
356

357 358
                                   //the agent left the old iroom
                                   //actualize the egress time for that iroom
359 360
                                   old_room->SetEgressTime(ped->GetGlobalTime());

361 362 363 364
                                   assigned = true;
                                   break;
                              }
                         }
365
                         if (assigned)
366 367 368
                              break; // stop the loop
                    }

369
                    if (!assigned) {
370 371
#pragma omp critical
                         pedsToRemove.push_back(ped);
372
                         //the agent left the old room
Ulrich Kemloh's avatar
Ulrich Kemloh committed
373
                         //actualize the eggress time for that room
374
                         allRooms.at(ped->GetRoomID())->SetEgressTime(ped->GetGlobalTime());
375

376 377 378 379 380 381
                    }
               }

               //finally actualize the route
               if (ped->FindRoute() == -1) {
                    //a destination could not be found for that pedestrian
382
                    Log->Write("ERROR: \tCould not find a route for pedestrian %d",ped->GetID());
383
                    //exit(EXIT_FAILURE);
384 385 386 387 388 389
#pragma omp critical
                    pedsToRemove.push_back(ped);
               }
          }
     }

390 391 392 393 394 395 396 397 398 399 400 401 402

     if (_hybridSimManager)
     {
          AgentsQueueOut::Add(pedsToRemove);
     }
     else
     {
          // remove the pedestrians that have left the building
          for (unsigned int p = 0; p < pedsToRemove.size(); p++)
          {
               _building->DeletePedestrian(pedsToRemove[p]);
          }

403 404 405 406 407 408 409 410
     }

     //    temporary fix for the safest path router
     //    if (dynamic_cast<SafestPathRouter*>(_routingEngine->GetRouter(1)))
     //    {
     //         SafestPathRouter* spr = dynamic_cast<SafestPathRouter*>(_routingEngine->GetRouter(1));
     //         spr->ComputeAndUpdateDestinations(_allPedestians);
     //    }
Ulrich Kemloh's avatar
Ulrich Kemloh committed
411
}
Ulrich Kemloh's avatar
Ulrich Kemloh committed
412

413 414
void Simulation::PrintStatistics()
{
415 416
     Log->Write("\nRooms Egress Time:");
     Log->Write("==================");
417 418
     Log->Write("id\tcaption\tegress time (s)");

419
     for(const auto& it:_building->GetAllRooms())
420
     {
421
          auto&& room=it.second;
422
          if(room->GetCaption()!="outside")
423
               Log->Write("%d\t%s\t%.2f",room->GetID(),room->GetCaption().c_str(),room->GetEgressTime());
424 425
     }

426 427
     Log->Write("\nUsage of Exits");
     Log->Write("==========");
428
     for (const auto& itr : _building->GetAllTransitions()) {
429
          Transition* goal = itr.second;
430 431 432 433 434
          if (goal->IsExit()) {
               Log->Write(
                         "Exit ID [%d] used by [%d] pedestrians. Last passing time [%0.2f] s",
                         goal->GetID(), goal->GetDoorUsage(),
                         goal->GetLastPassingTime());
435 436
          }
     }
437 438

     Log->Write("\n");
Ulrich Kemloh's avatar
Ulrich Kemloh committed
439
}
440

441 442 443 444 445 446 447 448 449 450 451 452
void Simulation::RunHeader(long nPed)
{
     // writing the header
     if(nPed==-1) nPed=_nPeds;
     _iod->WriteHeader(nPed, _fps, _building.get(), _seed);
     _iod->WriteGeometry(_building.get());
     _iod->WriteFrame(0, _building.get());

     //first initialisation needed by the linked-cells
      UpdateRoutesAndLocations();
      ProcessAgentsQueue();
}
453

454
int Simulation::RunBody(double maxSimTime)
455
{
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
     //needed to control the execution time PART 1
     //in the case you want to run in no faster than realtime
     //time_t starttime, endtime;
     //time(&starttime);

     //frame number. This function can be called many times,
     static int frameNr = 1; // Frame Number
     int writeInterval = (int) ((1. / _fps) / _deltaT + 0.5);
     writeInterval = (writeInterval <= 0) ? 1 : writeInterval; // mustn't be <= 0

     //take the current time from the pedestrian
     double t=Pedestrian::GetGlobalTime();

     //process the queue for incoming pedestrians
     //important since the number of peds is used
     //to break the main simulation loop
     ProcessAgentsQueue();
     _nPeds = _building->GetAllPedestrians().size();

     // main program loop
     while ( (_nPeds || !_agentSrcManager.IsCompleted() ) && t < maxSimTime)
     {
          t = 0 + (frameNr - 1) * _deltaT;

          //process the queue for incoming pedestrians
          ProcessAgentsQueue();

483 484 485
          //update the linked cells
          _building->UpdateGrid();

486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
          // update the positions
          _operationalModel->ComputeNextTimeStep(t, _deltaT, _building.get());

          //update the routes and locations
          UpdateRoutesAndLocations();

          //update the events
          //_em->Update_Events(t);
          _em->ProcessEvent();

          //other updates
          //someone might have left the building
          _nPeds = _building->GetAllPedestrians().size();


          // update the global time
          Pedestrian::SetGlobalTime(t);

          // write the trajectories
          if (0 == frameNr % writeInterval) {
               _iod->WriteFrame(frameNr / writeInterval, _building.get());
          }

          // needed to control the execution time PART 2
          // time(&endtime);
          // double timeToWait=t-difftime(endtime, starttime);
          // clock_t goal = timeToWait*1000 + clock();
          // while (goal > clock());
          ++frameNr;
     }
     return (int) t;
517 518
}

519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
void Simulation::RunFooter()
{
     // writing the footer
     _iod->WriteFooter();

     //temporary work around since the total number of frame is only available at the end of the simulation.
     if (_argsParser.GetFileFormat() == FORMAT_XML_BIN)
     {
          delete _iod;
          _iod = NULL;
          //reopen the file and write the missing information

          // char tmp[CLENGTH];
          // int f= frameNr / writeInterval ;
          // sprintf(tmp,"<frameCount>%07d</frameCount>",f);
          // string frameCount (tmp);

          //char replace[CLENGTH];
          // open the file and replace the 8th line
          //sprintf(replace, "sed -i '9s/.*/ %d /' %s", frameNr / writeInterval,
          //          _argsParser.GetTrajectoriesFile().c_str());
          //int result = system(replace);
          //Log->Write("INFO:\t Updating the framenumber exits with code [%d]", result);
     }
}



547 548
void Simulation::ProcessAgentsQueue()
{
549 550

     //incoming pedestrians
551
     vector<Pedestrian*> peds;
552
     AgentsQueueIn::GetandClear(peds);
553 554 555 556
     for(auto&& ped: peds)
     {
          _building->AddPedestrian(ped);
     }
557
#ifdef _USE_PROTOCOL_BUFFER
558 559 560 561 562
     //outgoing pedestrians
     if (_hybridSimManager)
     {
          _hybridSimManager->ProcessOutgoingAgent();
     }
563
#endif
564
}
565

566
AgentsSourcesManager& Simulation::GetAgentSrcManager()
567 568 569
{
     return _agentSrcManager;
}