Simulation.cpp 17.3 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 36
#include "pedestrian/AgentsSourcesManager.h"
#include "pedestrian/AgentsQueue.h"
37 38 39

#ifdef _OPENMP
#include <omp.h>
40

41 42 43 44 45
#else
#define omp_get_thread_num() 0
#define omp_get_max_threads()  1
#endif

Ulrich Kemloh's avatar
Ulrich Kemloh committed
46
using namespace std;
Ulrich Kemloh's avatar
Ulrich Kemloh committed
47

48 49
OutputHandler* Log;

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

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

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

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

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

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

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

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

174 175 176 177 178 179 180 181 182 183 184 185
          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);
186 187
               break;
          }
188 189 190
          default: {
               break;
          }
191 192 193
          }
     }

Oliver Schmidts's avatar
Oliver Schmidts committed
194

195

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

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

204
     sprintf(tmp, "\tnCPU: %d\n", args.GetMaxOpenMPThreads());
Mohcine Chraibi's avatar
Mohcine Chraibi committed
205
     s.append(tmp);
206
     _tmax = args.GetTmax();
207 208
     sprintf(tmp, "\tt_max: %f\n", _tmax);
     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 232 233
     //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
234
     if(_operationalModel->Init(_building.get())==false)
235
          return false;
236 237

     //other initializations
238 239 240 241
     const vector<Pedestrian*>& allPeds = _building->GetAllPedestrians();
     for (Pedestrian *ped : allPeds) {
          ped->Setdt(_deltaT);
     }
Oliver Schmidts's avatar
Oliver Schmidts committed
242
     _nPeds = allPeds.size();
243 244 245
     //pBuilding->WriteToErrorLog();

     //get the seed
246
     _seed = args.GetSeed();
247

248
     //size of the cells/GCFM/Gompertz
249
     if (args.GetDistEffMaxPed() > args.GetLinkedCellSize()) {
250 251
          Log->Write(
                    "ERROR: the linked-cell size [%f] should be bigger than the force range [%f]",
252
                    args.GetLinkedCellSize(), args.GetDistEffMaxPed());
253
          return false;
254
     }
255

Ulrich Kemloh's avatar
Ulrich Kemloh committed
256
     //read and initialize events
Oliver Schmidts's avatar
Oliver Schmidts committed
257
     _em = new EventManager(_building.get());
Ulrich Kemloh's avatar
Ulrich Kemloh committed
258 259 260 261
     if(_em->ReadEventsXml()==false)
     {
          Log->Write("ERROR: \tCould not initialize events handling");
     }
Ulrich Kemloh's avatar
Ulrich Kemloh committed
262
     _em->ListEvents();
263 264

     //which hpc-architecture?
265
     _hpc = args.GetHPCFlag();
266 267 268 269 270
     //if programming model = ocl create buffers and make the setup
     //if(_hpc==1){
     //((GPU_ocl_GCFMModel*) _model)->CreateBuffer(_building->GetNumberOfPedestrians());
     //((GPU_ocl_GCFMModel*) _model)->initCL(_building->GetNumberOfPedestrians());
     //}
271
     //_building->SaveGeometry("test.sav.xml");
Ulrich Kemloh's avatar
Ulrich Kemloh committed
272

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

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

280 281 282 283 284
int Simulation::RunSimulation()
{
     int frameNr = 1; // Frame Number
     int writeInterval = (int) ((1. / _fps) / _deltaT + 0.5);
     writeInterval = (writeInterval <= 0) ? 1 : writeInterval; // mustn't be <= 0
285
     double t = 0.0;
Ulrich Kemloh's avatar
Ulrich Kemloh committed
286

287
     // writing the header
Oliver Schmidts's avatar
Oliver Schmidts committed
288 289 290
     _iod->WriteHeader(_nPeds, _fps, _building.get(), _seed);
     _iod->WriteGeometry(_building.get());
     _iod->WriteFrame(0, _building.get());
Ulrich Kemloh's avatar
Ulrich Kemloh committed
291

292
     //first initialisation needed by the linked-cells
293
     UpdateRoutesAndLocations();
294
     ProcessAgentsQueue();
Ulrich Kemloh's avatar
Ulrich Kemloh committed
295

296 297 298 299
     //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);
Ulrich Kemloh's avatar
Ulrich Kemloh committed
300

301
     // main program loop
302
     while ( (_nPeds || !_agentSrcManager.IsCompleted() ) && t < _tmax)
303
     {
304
          t = 0 + (frameNr - 1) * _deltaT;
305

306
          //process the queue for incoming pedestrians
307 308
          ProcessAgentsQueue();

309
          // update the positions
Oliver Schmidts's avatar
Oliver Schmidts committed
310
          _operationalModel->ComputeNextTimeStep(t, _deltaT, _building.get());
311

312
          //update the routes and locations
313 314 315
          UpdateRoutesAndLocations();

          //update the events
316 317
          //_em->Update_Events(t);
          _em->ProcessEvent();
318 319

          //other updates
320
          //someone might have left the building
321
          _nPeds = _building->GetAllPedestrians().size();
322 323 324 325 326

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

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

          // write the trajectories
330
          if (0 == frameNr % writeInterval) {
Oliver Schmidts's avatar
Oliver Schmidts committed
331
               _iod->WriteFrame(frameNr / writeInterval, _building.get());
332
          }
333

334 335 336 337 338
          // 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());
339
          ++frameNr;
340 341 342
     }
     // writing the footer
     _iod->WriteFooter();
Ulrich Kemloh's avatar
Ulrich Kemloh committed
343

344
     //if(_hpc==1)
345
     //  ((GPU_GCFMModel*) _model)->DeleteBuffers();
346

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

Ulrich Kemloh's avatar
Ulrich Kemloh committed
354 355 356 357
          // char tmp[CLENGTH];
          // int f= frameNr / writeInterval ;
          // sprintf(tmp,"<frameCount>%07d</frameCount>",f);
          // string frameCount (tmp);
358

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

368 369
     //return the evacuation time
     return (int) t;
Ulrich Kemloh's avatar
Ulrich Kemloh committed
370 371
}

372
void Simulation::UpdateRoutesAndLocations()
373
{
374 375 376 377 378 379
     //pedestrians to be deleted
     //you should better create this in the constructor and allocate it once.
     vector<Pedestrian*> pedsToRemove;
     pedsToRemove.reserve(100); //just reserve some space

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

383
     unsigned long nSize = allPeds.size();
384 385 386 387 388 389 390 391 392 393 394
     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;

395
          for (int p = start; p <= end; ++p) {
396 397
               Pedestrian* ped = allPeds[p];
               Room* room = _building->GetRoom(ped->GetRoomID());
398
               SubRoom* sub0 = room->GetSubRoom(ped->GetSubRoomID());
399 400 401

               //set the new room if needed
               if ((ped->GetFinalDestination() == FINAL_DEST_OUT)
402
                         && (room->GetCaption() == "outside")) {
403 404
#pragma omp critical
                    pedsToRemove.push_back(ped);
405 406 407
               } else if ((ped->GetFinalDestination() != FINAL_DEST_OUT)
                         && (goals.at(ped->GetFinalDestination())->Contains(
                                   ped->GetPos()))) {
408 409 410 411 412 413 414
#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
415
               else if (!sub0->IsInSubRoom(ped))
416
               {
417
                    bool assigned = false;
418 419 420
                    auto& allRooms = _building->GetAllRooms();

                    for (auto&& it_room : allRooms)
421
                    {
422 423
                         auto&& room=it_room.second;
                         for (auto&& it_sub : room->GetAllSubRooms())
424
                         {
425 426 427
                              auto&& sub=it_sub.second;
                              auto&& old_room =allRooms.at(ped->GetRoomID());
                              auto&& old_sub =old_room->GetSubRoom(
428
                                        ped->GetSubRoomID());
429 430
                              if ((sub->IsInSubRoom(ped->GetPos()))
                                        && (sub->IsDirectlyConnectedWith(
431 432
                                                  old_sub)))
                              {
433 434 435
                                   ped->SetRoomID(room->GetID(),
                                             room->GetCaption());
                                   ped->SetSubRoomID(sub->GetSubRoomID());
436 437
                                   ped->ClearMentalMap(); // reset the destination
                                   //ped->FindRoute();
438

439 440
                                   //the agent left the old iroom
                                   //actualize the egress time for that iroom
441 442
                                   old_room->SetEgressTime(ped->GetGlobalTime());

443 444 445 446
                                   assigned = true;
                                   break;
                              }
                         }
447
                         if (assigned)
448 449 450
                              break; // stop the loop
                    }

451
                    if (!assigned) {
452 453
#pragma omp critical
                         pedsToRemove.push_back(ped);
454 455
                         //the agent left the old room
                         //actualize the egress time for that room
456
                         allRooms.at(ped->GetRoomID())->SetEgressTime(ped->GetGlobalTime());
457

458 459 460 461 462 463
                    }
               }

               //finally actualize the route
               if (ped->FindRoute() == -1) {
                    //a destination could not be found for that pedestrian
464
                    Log->Write("ERROR: \tCould not find a route for pedestrian %d",ped->GetID());
465
                    //exit(EXIT_FAILURE);
466 467 468 469 470 471 472
#pragma omp critical
                    pedsToRemove.push_back(ped);
               }
          }
     }

     // remove the pedestrians that have left the building
473
     for (unsigned int p = 0; p < pedsToRemove.size(); p++) {
474 475 476 477 478 479 480 481 482
          _building->DeletePedestrian(pedsToRemove[p]);
     }

     //    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
483
}
Ulrich Kemloh's avatar
Ulrich Kemloh committed
484

485 486
void Simulation::PrintStatistics()
{
487 488
     Log->Write("\nRooms Egress Time:");
     Log->Write("==================");
489 490
     Log->Write("id\tcaption\tegress time (s)");

491
     for(const auto& it:_building->GetAllRooms())
492
     {
493
          auto&& room=it.second;
494
          if(room->GetCaption()!="outside")
495
               Log->Write("%d\t%s\t%.2f",room->GetID(),room->GetCaption().c_str(),room->GetEgressTime());
496 497
     }

498 499
     Log->Write("\nUsage of Exits");
     Log->Write("==========");
500
     for (const auto& itr : _building->GetAllTransitions()) {
501
          Transition* goal = itr.second;
502 503 504 505 506
          if (goal->IsExit()) {
               Log->Write(
                         "Exit ID [%d] used by [%d] pedestrians. Last passing time [%0.2f] s",
                         goal->GetID(), goal->GetDoorUsage(),
                         goal->GetLastPassingTime());
507 508
          }
     }
509 510

     Log->Write("\n");
Ulrich Kemloh's avatar
Ulrich Kemloh committed
511
}
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528


const AgentsSourcesManager& Simulation::GetAgentSrcManager()
{
     return _agentSrcManager;
}

void Simulation::ProcessAgentsQueue()
{
     vector<Pedestrian*> peds;
     AgentsQueue::GetandClear(peds);

     for(auto&& ped: peds)
     {
          _building->AddPedestrian(ped);
     }
}