Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/od/ODMatrix.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2006-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file ODMatrix.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @author Yun-Pang Floetteroed
19
/// @author Mirko Barthauer
20
/// @date 05 Apr. 2006
21
///
22
// An O/D (origin/destination) matrix
23
/****************************************************************************/
24
#include <config.h>
25
26
#include <iostream>
27
#include <algorithm>
28
#include <list>
29
#include <iterator>
30
#include <utils/options/OptionsCont.h>
31
#include <utils/common/FileHelpers.h>
32
#include <utils/common/StdDefs.h>
33
#include <utils/common/MsgHandler.h>
34
#include <utils/common/ToString.h>
35
#include <utils/common/RandHelper.h>
36
#include <utils/common/StringUtils.h>
37
#include <utils/common/StringUtils.h>
38
#include <utils/common/StringTokenizer.h>
39
#include <utils/common/SUMOTime.h>
40
#include <utils/iodevices/OutputDevice.h>
41
#include <utils/importio/LineReader.h>
42
#include <utils/xml/SUMOSAXHandler.h>
43
#include <utils/xml/XMLSubSys.h>
44
#include <router/RORoute.h>
45
#include "ODAmitranHandler.h"
46
#include "ODMatrix.h"
47
48
49
// ===========================================================================
50
// method definitions
51
// ===========================================================================
52
ODMatrix::ODMatrix(const ODDistrictCont& dc, double scale) :
53
myDistricts(dc),
54
myNumLoaded(0),
55
myNumWritten(0),
56
myNumDiscarded(0),
57
myBegin(-1),
58
myEnd(-1),
59
myScale(scale)
60
{}
61
62
63
ODMatrix::~ODMatrix() {
64
for (ODCell* const cell : myContainer) {
65
for (RORoute* const r : cell->pathsVector) {
66
delete r;
67
}
68
delete cell;
69
}
70
myContainer.clear();
71
}
72
73
74
bool
75
ODMatrix::add(double vehicleNumber, const std::pair<SUMOTime, SUMOTime>& beginEnd,
76
const std::string& origin, const std::string& destination,
77
const std::string& vehicleType, const bool originIsEdge, const bool destinationIsEdge,
78
bool noScaling) {
79
if (vehicleNumber == 0) {
80
return false;
81
}
82
myNumLoaded += vehicleNumber;
83
if (!originIsEdge && !destinationIsEdge && myDistricts.get(origin) == nullptr && myDistricts.get(destination) == nullptr) {
84
WRITE_WARNINGF(TL("Missing origin '%' and destination '%' (% vehicles)."), origin, destination, toString(vehicleNumber));
85
myNumDiscarded += vehicleNumber;
86
myMissingDistricts.insert(origin);
87
myMissingDistricts.insert(destination);
88
return false;
89
} else if (!originIsEdge && myDistricts.get(origin) == 0) {
90
WRITE_ERRORF(TL("Missing origin '%' (% vehicles)."), origin, toString(vehicleNumber));
91
myNumDiscarded += vehicleNumber;
92
myMissingDistricts.insert(origin);
93
return false;
94
} else if (!destinationIsEdge && myDistricts.get(destination) == 0) {
95
WRITE_ERRORF(TL("Missing destination '%' (% vehicles)."), destination, toString(vehicleNumber));
96
myNumDiscarded += vehicleNumber;
97
myMissingDistricts.insert(destination);
98
return false;
99
}
100
if (!originIsEdge && myDistricts.get(origin)->sourceNumber() == 0) {
101
WRITE_ERRORF(TL("District '%' has no source."), origin);
102
myNumDiscarded += vehicleNumber;
103
return false;
104
} else if (!destinationIsEdge && myDistricts.get(destination)->sinkNumber() == 0) {
105
WRITE_ERRORF(TL("District '%' has no sink."), destination);
106
myNumDiscarded += vehicleNumber;
107
return false;
108
}
109
ODCell* cell = new ODCell();
110
cell->begin = beginEnd.first;
111
cell->end = beginEnd.second;
112
cell->origin = origin;
113
cell->destination = destination;
114
cell->vehicleType = vehicleType;
115
cell->vehicleNumber = vehicleNumber * (noScaling ? 1 : myScale);
116
cell->originIsEdge = originIsEdge;
117
cell->destinationIsEdge = destinationIsEdge;
118
myContainer.push_back(cell);
119
if (myBegin == -1 || cell->begin < myBegin) {
120
myBegin = cell->begin;
121
}
122
if (cell->end > myEnd) {
123
myEnd = cell->end;
124
}
125
return true;
126
}
127
128
129
bool
130
ODMatrix::add(const SUMOVehicleParameter& veh, bool originIsEdge, bool destinationIsEdge) {
131
const std::string fromTaz = veh.fromTaz;
132
const std::string toTaz = veh.toTaz;
133
if (myMissingDistricts.count(fromTaz) > 0 || myMissingDistricts.count(toTaz) > 0) {
134
myNumLoaded += 1.;
135
myNumDiscarded += 1.;
136
return false;
137
}
138
// we start looking from the end because there is a high probability that the input is sorted by time
139
std::vector<ODCell*>& odList = myShortCut[std::make_pair(fromTaz, toTaz)];
140
ODCell* cell = nullptr;
141
for (std::vector<ODCell*>::const_reverse_iterator c = odList.rbegin(); c != odList.rend(); ++c) {
142
if ((*c)->begin <= veh.depart && (*c)->end > veh.depart && (*c)->vehicleType == veh.vtypeid) {
143
cell = *c;
144
break;
145
}
146
}
147
if (cell == nullptr) {
148
const SUMOTime interval = string2time(OptionsCont::getOptions().getString("aggregation-interval"));
149
const int intervalIdx = (int)(veh.depart / interval);
150
// single vehicles are already scaled
151
if (add(1., std::make_pair(intervalIdx * interval, (intervalIdx + 1) * interval),
152
fromTaz, toTaz, veh.vtypeid, originIsEdge, destinationIsEdge, true)) {
153
cell = myContainer.back();
154
odList.push_back(cell);
155
} else {
156
return false;
157
}
158
} else {
159
myNumLoaded += 1.;
160
cell->vehicleNumber += 1.;
161
}
162
cell->departures[veh.depart].push_back(veh);
163
return true;
164
}
165
166
167
double
168
ODMatrix::computeDeparts(ODCell* cell,
169
int& vehName, std::vector<ODVehicle>& into,
170
const bool uniform, const bool differSourceSink,
171
const std::string& prefix) {
172
int vehicles2insert = (int) cell->vehicleNumber;
173
// compute whether the fraction forces an additional vehicle insertion
174
if (RandHelper::rand() < cell->vehicleNumber - (double)vehicles2insert) {
175
vehicles2insert++;
176
}
177
if (vehicles2insert == 0) {
178
return cell->vehicleNumber;
179
}
180
181
const double offset = (double)(cell->end - cell->begin) / (double) vehicles2insert / (double) 2.;
182
for (int i = 0; i < vehicles2insert; ++i) {
183
ODVehicle veh;
184
veh.id = prefix + toString(vehName++);
185
186
if (uniform) {
187
veh.depart = cell->begin + (SUMOTime)(offset + ((double)(cell->end - cell->begin) * (double) i / (double) vehicles2insert));
188
} else {
189
veh.depart = (SUMOTime)RandHelper::rand(cell->begin, cell->end);
190
}
191
const bool canDiffer = myDistricts.get(cell->origin)->sourceNumber() > 1 || myDistricts.get(cell->destination)->sinkNumber() > 1;
192
do {
193
veh.from = myDistricts.getRandomSourceFromDistrict(cell->origin);
194
veh.to = myDistricts.getRandomSinkFromDistrict(cell->destination);
195
} while (canDiffer && differSourceSink && (veh.to == veh.from));
196
if (!canDiffer && differSourceSink && (veh.to == veh.from)) {
197
WRITE_WARNINGF(TL("Cannot find different source and sink edge for origin '%' and destination '%'."), cell->origin, cell->destination);
198
}
199
veh.cell = cell;
200
into.push_back(veh);
201
}
202
return cell->vehicleNumber - vehicles2insert;
203
}
204
205
206
void
207
ODMatrix::writeDefaultAttrs(OutputDevice& dev, const bool noVtype,
208
const ODCell* const cell) {
209
const OptionsCont& oc = OptionsCont::getOptions();
210
if (!noVtype && cell->vehicleType != "") {
211
dev.writeAttr(SUMO_ATTR_TYPE, cell->vehicleType);
212
}
213
dev.writeAttr(SUMO_ATTR_FROM_TAZ, cell->origin).writeAttr(SUMO_ATTR_TO_TAZ, cell->destination);
214
if (oc.isSet("departlane") && oc.getString("departlane") != "default") {
215
dev.writeAttr(SUMO_ATTR_DEPARTLANE, oc.getString("departlane"));
216
}
217
if (oc.isSet("departpos")) {
218
dev.writeAttr(SUMO_ATTR_DEPARTPOS, oc.getString("departpos"));
219
}
220
if (oc.isSet("departspeed") && oc.getString("departspeed") != "default") {
221
dev.writeAttr(SUMO_ATTR_DEPARTSPEED, oc.getString("departspeed"));
222
}
223
if (oc.isSet("arrivallane")) {
224
dev.writeAttr(SUMO_ATTR_ARRIVALLANE, oc.getString("arrivallane"));
225
}
226
if (oc.isSet("arrivalpos")) {
227
dev.writeAttr(SUMO_ATTR_ARRIVALPOS, oc.getString("arrivalpos"));
228
}
229
if (oc.isSet("arrivalspeed")) {
230
dev.writeAttr(SUMO_ATTR_ARRIVALSPEED, oc.getString("arrivalspeed"));
231
}
232
}
233
234
235
void
236
ODMatrix::write(SUMOTime begin, const SUMOTime end,
237
OutputDevice& dev, const bool uniform,
238
const bool differSourceSink, const bool noVtype,
239
const std::string& prefix, const bool stepLog,
240
bool pedestrians, bool persontrips,
241
const std::string& modes) {
242
if (myContainer.size() == 0) {
243
return;
244
}
245
std::map<std::pair<std::string, std::string>, double> fractionLeft;
246
int vehName = 0;
247
sortByBeginTime();
248
// recheck begin time
249
begin = MAX2(begin, myContainer.front()->begin);
250
std::vector<ODCell*>::iterator next = myContainer.begin();
251
std::vector<ODVehicle> vehicles;
252
SUMOTime lastOut = -DELTA_T;
253
254
const OptionsCont& oc = OptionsCont::getOptions();
255
std::string personDepartPos = oc.isSet("departpos") ? oc.getString("departpos") : "random";
256
std::string personArrivalPos = oc.isSet("arrivalpos") ? oc.getString("arrivalpos") : "random";
257
SumoXMLAttr fromAttr = oc.getBool("junctions") ? SUMO_ATTR_FROM_JUNCTION : SUMO_ATTR_FROM;
258
SumoXMLAttr toAttr = oc.getBool("junctions") ? SUMO_ATTR_TO_JUNCTION : SUMO_ATTR_TO;
259
const std::string vType = oc.isSet("vtype") ? oc.getString("vtype") : "";
260
261
// go through the time steps
262
for (SUMOTime t = begin; t < end;) {
263
if (stepLog && t - lastOut >= DELTA_T) {
264
std::cout << "Parsing time " + time2string(t) << '\r';
265
lastOut = t;
266
}
267
// recheck whether a new cell got valid
268
bool changed = false;
269
while (next != myContainer.end() && (*next)->begin <= t && (*next)->end > t) {
270
std::pair<std::string, std::string> odID = std::make_pair((*next)->origin, (*next)->destination);
271
// check whether the current cell must be extended by the last fraction
272
if (fractionLeft.find(odID) != fractionLeft.end()) {
273
(*next)->vehicleNumber += fractionLeft[odID];
274
fractionLeft[odID] = 0;
275
}
276
// get the new departures (into tmp)
277
const int oldSize = (int)vehicles.size();
278
const double fraction = computeDeparts(*next, vehName, vehicles, uniform, differSourceSink, prefix);
279
if (oldSize != (int)vehicles.size()) {
280
changed = true;
281
}
282
if (fraction != 0) {
283
fractionLeft[odID] = fraction;
284
}
285
++next;
286
}
287
if (changed) {
288
sort(vehicles.begin(), vehicles.end(), descending_departure_comperator());
289
}
290
291
for (std::vector<ODVehicle>::reverse_iterator i = vehicles.rbegin(); i != vehicles.rend() && (*i).depart == t; ++i) {
292
if (t >= begin) {
293
myNumWritten++;
294
if (pedestrians) {
295
dev.openTag(SUMO_TAG_PERSON).writeAttr(SUMO_ATTR_ID, (*i).id).writeAttr(SUMO_ATTR_DEPART, time2string(t));
296
dev.writeAttr(SUMO_ATTR_DEPARTPOS, personDepartPos);
297
if (!noVtype && vType.size() > 0) {
298
dev.writeAttr(SUMO_ATTR_TYPE, vType);
299
}
300
dev.openTag(SUMO_TAG_WALK);
301
dev.writeAttr(fromAttr, (*i).from);
302
dev.writeAttr(toAttr, (*i).to);
303
dev.writeAttr(SUMO_ATTR_FROM_TAZ, (*i).cell->origin).writeAttr(SUMO_ATTR_TO_TAZ, (*i).cell->destination);
304
dev.writeAttr(SUMO_ATTR_ARRIVALPOS, personArrivalPos);
305
dev.closeTag();
306
dev.closeTag();
307
} else if (persontrips) {
308
dev.openTag(SUMO_TAG_PERSON).writeAttr(SUMO_ATTR_ID, (*i).id).writeAttr(SUMO_ATTR_DEPART, time2string(t));
309
dev.writeAttr(SUMO_ATTR_DEPARTPOS, personDepartPos);
310
dev.openTag(SUMO_TAG_PERSONTRIP);
311
dev.writeAttr(fromAttr, (*i).from);
312
dev.writeAttr(toAttr, (*i).to);
313
dev.writeAttr(SUMO_ATTR_FROM_TAZ, (*i).cell->origin).writeAttr(SUMO_ATTR_TO_TAZ, (*i).cell->destination);
314
dev.writeAttr(SUMO_ATTR_ARRIVALPOS, personArrivalPos);
315
if (modes != "") {
316
dev.writeAttr(SUMO_ATTR_MODES, modes);
317
}
318
dev.closeTag();
319
dev.closeTag();
320
} else {
321
dev.openTag(SUMO_TAG_TRIP).writeAttr(SUMO_ATTR_ID, (*i).id).writeAttr(SUMO_ATTR_DEPART, time2string(t));
322
dev.writeAttr(fromAttr, (*i).from);
323
dev.writeAttr(toAttr, (*i).to);
324
writeDefaultAttrs(dev, noVtype, i->cell);
325
dev.closeTag();
326
}
327
}
328
}
329
while (vehicles.size() != 0 && vehicles.back().depart == t) {
330
vehicles.pop_back();
331
}
332
if (!vehicles.empty()) {
333
t = vehicles.back().depart;
334
}
335
if (next != myContainer.end() && (t > (*next)->begin || vehicles.empty())) {
336
t = (*next)->begin;
337
}
338
if (next == myContainer.end() && vehicles.empty()) {
339
break;
340
}
341
}
342
}
343
344
345
void
346
ODMatrix::writeFlows(const SUMOTime begin, const SUMOTime end,
347
OutputDevice& dev, bool noVtype,
348
const std::string& prefix,
349
bool asProbability, bool pedestrians, bool persontrips,
350
const std::string& modes) {
351
if (myContainer.size() == 0) {
352
return;
353
}
354
int flowName = 0;
355
sortByBeginTime();
356
// recheck begin time
357
for (std::vector<ODCell*>::const_iterator i = myContainer.begin(); i != myContainer.end(); ++i) {
358
const ODCell* const c = *i;
359
if (c->end > begin && c->begin < end) {
360
const double probability = asProbability ? float(c->vehicleNumber) / STEPS2TIME(c->end - c->begin) : 1;
361
if (probability <= 0) {
362
continue;
363
}
364
//Person flows
365
if (pedestrians) {
366
dev.openTag(SUMO_TAG_PERSONFLOW).writeAttr(SUMO_ATTR_ID, prefix + toString(flowName++));
367
dev.writeAttr(SUMO_ATTR_BEGIN, time2string(c->begin)).writeAttr(SUMO_ATTR_END, time2string(c->end));
368
if (!asProbability) {
369
dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
370
} else {
371
if (probability > 1) {
372
WRITE_WARNINGF(TL("Flow density of % vehicles per second, cannot be represented with a simple probability. Falling back to even spacing."), toString(probability));
373
dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
374
} else {
375
dev.setPrecision(6);
376
dev.writeAttr(SUMO_ATTR_PROB, probability);
377
dev.setPrecision();
378
}
379
}
380
dev.openTag(SUMO_TAG_WALK);
381
dev.writeAttr(SUMO_ATTR_FROM_TAZ, c->origin).writeAttr(SUMO_ATTR_TO_TAZ, c->destination);
382
dev.writeAttr(SUMO_ATTR_ARRIVALPOS, "random");
383
dev.closeTag();
384
dev.closeTag();
385
} else if (persontrips) {
386
dev.openTag(SUMO_TAG_PERSONFLOW).writeAttr(SUMO_ATTR_ID, prefix + toString(flowName++));
387
dev.writeAttr(SUMO_ATTR_BEGIN, time2string(c->begin)).writeAttr(SUMO_ATTR_END, time2string(c->end));
388
if (!asProbability) {
389
dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
390
} else {
391
if (probability > 1) {
392
WRITE_WARNINGF(TL("Flow density of % vehicles per second, cannot be represented with a simple probability. Falling back to even spacing."), toString(probability));
393
dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
394
} else {
395
dev.setPrecision(6);
396
dev.writeAttr(SUMO_ATTR_PROB, probability);
397
dev.setPrecision();
398
}
399
}
400
dev.openTag(SUMO_TAG_PERSONTRIP);
401
dev.writeAttr(SUMO_ATTR_FROM_TAZ, c->origin).writeAttr(SUMO_ATTR_TO_TAZ, c->destination);
402
dev.writeAttr(SUMO_ATTR_ARRIVALPOS, "random");
403
if (modes != "") {
404
dev.writeAttr(SUMO_ATTR_MODES, modes);
405
}
406
dev.closeTag();
407
dev.closeTag();
408
} else {
409
// Normal flow output
410
dev.openTag(SUMO_TAG_FLOW).writeAttr(SUMO_ATTR_ID, prefix + toString(flowName++));
411
dev.writeAttr(SUMO_ATTR_BEGIN, time2string(c->begin));
412
dev.writeAttr(SUMO_ATTR_END, time2string(c->end));
413
414
if (!asProbability) {
415
dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
416
} else {
417
if (probability > 1) {
418
WRITE_WARNINGF(TL("Flow density of % vehicles per second, cannot be represented with a simple probability. Falling back to even spacing."), toString(probability));
419
dev.writeAttr(SUMO_ATTR_NUMBER, int(c->vehicleNumber));
420
} else {
421
dev.setPrecision(6);
422
dev.writeAttr(SUMO_ATTR_PROB, probability);
423
dev.setPrecision();
424
}
425
}
426
writeDefaultAttrs(dev, noVtype, *i);
427
dev.closeTag();
428
}
429
}
430
}
431
}
432
433
434
std::string
435
ODMatrix::getNextNonCommentLine(LineReader& lr) {
436
while (lr.good() && lr.hasMore()) {
437
const std::string line = lr.readLine();
438
if (line[0] != '*') {
439
return StringUtils::prune(line);
440
}
441
}
442
throw ProcessError(TLF("End of file while reading %.", lr.getFileName()));
443
}
444
445
446
SUMOTime
447
ODMatrix::parseSingleTime(const std::string& time) {
448
if (time.find('.') == std::string::npos) {
449
throw NumberFormatException("no separator");
450
}
451
const std::string hours = time.substr(0, time.find('.'));
452
const std::string minutes = time.substr(time.find('.') + 1);
453
return TIME2STEPS(StringUtils::toInt(hours) * 3600 + StringUtils::toInt(minutes) * 60);
454
}
455
456
457
std::pair<SUMOTime, SUMOTime>
458
ODMatrix::readTime(LineReader& lr) {
459
std::string line = getNextNonCommentLine(lr);
460
try {
461
StringTokenizer st(line, StringTokenizer::WHITECHARS);
462
const SUMOTime begin = parseSingleTime(st.next());
463
const SUMOTime end = parseSingleTime(st.next());
464
if (begin >= end) {
465
throw ProcessError("Matrix begin time " + time2string(begin) + " is larger than end time " + time2string(end) + ".");
466
}
467
return std::make_pair(begin, end);
468
} catch (OutOfBoundsException&) {
469
throw ProcessError(TLF("Broken period definition '%'.", line));
470
} catch (NumberFormatException& e) {
471
throw ProcessError("Broken period definition '" + line + "' (" + e.what() + ").");
472
}
473
}
474
475
476
double
477
ODMatrix::readFactor(LineReader& lr, double scale) {
478
std::string line = getNextNonCommentLine(lr);
479
double factor = -1;
480
try {
481
factor = StringUtils::toDouble(line) * scale;
482
} catch (NumberFormatException&) {
483
throw ProcessError(TLF("Broken factor: '%'.", line));
484
}
485
return factor;
486
}
487
488
void
489
ODMatrix::readV(LineReader& lr, double scale,
490
std::string vehType, bool matrixHasVehType) {
491
PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as VMR");
492
// parse first defs
493
std::string line;
494
if (matrixHasVehType) {
495
line = getNextNonCommentLine(lr);
496
if (vehType == "") {
497
vehType = StringUtils::prune(line);
498
}
499
}
500
501
const std::pair<SUMOTime, SUMOTime> beginEnd = readTime(lr);
502
const double factor = readFactor(lr, scale);
503
504
// districts
505
line = getNextNonCommentLine(lr);
506
const int numDistricts = StringUtils::toInt(StringUtils::prune(line));
507
// parse district names (normally ints)
508
std::vector<std::string> names;
509
while ((int)names.size() != numDistricts && lr.hasMore()) {
510
line = getNextNonCommentLine(lr);
511
StringTokenizer st2(line, StringTokenizer::WHITECHARS);
512
while (st2.hasNext()) {
513
names.push_back(st2.next());
514
}
515
}
516
if (!lr.hasMore()) {
517
throw ProcessError(TLF("Missing line with % district names.", toString(numDistricts)));
518
}
519
520
// parse the cells
521
for (std::vector<std::string>::iterator si = names.begin(); si != names.end(); ++si) {
522
std::vector<std::string>::iterator di = names.begin();
523
do {
524
try {
525
line = getNextNonCommentLine(lr);
526
} catch (ProcessError&) {
527
throw ProcessError(TLF("Missing line for district %.", (*si)));
528
}
529
if (line.length() == 0) {
530
continue;
531
}
532
try {
533
StringTokenizer st2(line, StringTokenizer::WHITECHARS);
534
while (st2.hasNext()) {
535
assert(di != names.end());
536
double vehNumber = StringUtils::toDouble(st2.next()) * factor;
537
if (vehNumber != 0) {
538
add(vehNumber, beginEnd, *si, *di, vehType);
539
}
540
if (di == names.end()) {
541
throw ProcessError(TL("More entries than districts found."));
542
}
543
++di;
544
}
545
} catch (NumberFormatException&) {
546
throw ProcessError(TLF("Not numeric vehicle number in line '%'.", line));
547
}
548
if (!lr.hasMore()) {
549
break;
550
}
551
} while (di != names.end());
552
}
553
PROGRESS_DONE_MESSAGE();
554
}
555
556
557
void
558
ODMatrix::readO(LineReader& lr, double scale,
559
std::string vehType, bool matrixHasVehType) {
560
PROGRESS_BEGIN_MESSAGE("Reading matrix '" + lr.getFileName() + "' stored as OR");
561
// parse first defs
562
std::string line;
563
if (matrixHasVehType) {
564
line = getNextNonCommentLine(lr);
565
int type = StringUtils::toInt(StringUtils::prune(line));
566
if (vehType == "") {
567
vehType = toString(type);
568
}
569
}
570
571
const std::pair<SUMOTime, SUMOTime> beginEnd = readTime(lr);
572
const double factor = readFactor(lr, scale);
573
574
// parse the cells
575
while (lr.hasMore()) {
576
line = getNextNonCommentLine(lr);
577
if (line.length() == 0) {
578
continue;
579
}
580
StringTokenizer st2(line, StringTokenizer::WHITECHARS);
581
if (st2.size() == 0) {
582
continue;
583
}
584
try {
585
std::string sourceD = st2.next();
586
std::string destD = st2.next();
587
double vehNumber = StringUtils::toDouble(st2.next()) * factor;
588
if (vehNumber != 0) {
589
add(vehNumber, beginEnd, sourceD, destD, vehType);
590
}
591
} catch (OutOfBoundsException&) {
592
throw ProcessError(TLF("Missing at least one information in line '%'.", line));
593
} catch (NumberFormatException&) {
594
throw ProcessError(TLF("Not numeric vehicle number in line '%'.", line));
595
}
596
}
597
PROGRESS_DONE_MESSAGE();
598
}
599
600
601
602
double
603
ODMatrix::getNumLoaded() const {
604
return myNumLoaded;
605
}
606
607
608
double
609
ODMatrix::getNumWritten() const {
610
return myNumWritten;
611
}
612
613
614
double
615
ODMatrix::getNumDiscarded() const {
616
return myNumDiscarded;
617
}
618
619
620
void
621
ODMatrix::applyCurve(const Distribution_Points& ps, ODCell* cell, std::vector<ODCell*>& newCells) {
622
const std::vector<double>& times = ps.getVals();
623
for (int i = 0; i < (int)times.size() - 1; ++i) {
624
ODCell* ncell = new ODCell();
625
ncell->begin = TIME2STEPS(times[i]);
626
ncell->end = TIME2STEPS(times[i + 1]);
627
ncell->origin = cell->origin;
628
ncell->destination = cell->destination;
629
ncell->vehicleType = cell->vehicleType;
630
ncell->vehicleNumber = cell->vehicleNumber * ps.getProbs()[i] / ps.getOverallProb();
631
newCells.push_back(ncell);
632
}
633
}
634
635
636
void
637
ODMatrix::applyCurve(const Distribution_Points& ps) {
638
std::vector<ODCell*> oldCells = myContainer;
639
myContainer.clear();
640
for (std::vector<ODCell*>::iterator i = oldCells.begin(); i != oldCells.end(); ++i) {
641
std::vector<ODCell*> newCells;
642
applyCurve(ps, *i, newCells);
643
copy(newCells.begin(), newCells.end(), back_inserter(myContainer));
644
delete *i;
645
}
646
}
647
648
649
void
650
ODMatrix::loadMatrix(OptionsCont& oc) {
651
std::vector<std::string> files = oc.getStringVector("od-matrix-files");
652
for (std::vector<std::string>::iterator i = files.begin(); i != files.end(); ++i) {
653
LineReader lr(*i);
654
if (!lr.good()) {
655
throw ProcessError(TLF("Could not open '%'.", (*i)));
656
}
657
std::string type = lr.readLine();
658
// get the type only
659
if (type.find(';') != std::string::npos) {
660
type = type.substr(0, type.find(';'));
661
}
662
// parse type-dependant
663
if (type.length() > 1 && type[1] == 'V') {
664
// process ptv's 'V'-matrices
665
if (type.find('N') != std::string::npos) {
666
throw ProcessError(TLF("'%' does not contain the needed information about the time described.", *i));
667
}
668
readV(lr, 1, oc.getString("vtype"), type.find('M') != std::string::npos);
669
} else if (type.length() > 1 && type[1] == 'O') {
670
// process ptv's 'O'-matrices
671
if (type.find('N') != std::string::npos) {
672
throw ProcessError(TLF("'%' does not contain the needed information about the time described.", *i));
673
}
674
readO(lr, 1, oc.getString("vtype"), type.find('M') != std::string::npos);
675
} else {
676
throw ProcessError("'" + *i + "' uses an unknown matrix type '" + type + "'.");
677
}
678
}
679
std::vector<std::string> amitranFiles = oc.getStringVector("od-amitran-files");
680
for (std::vector<std::string>::iterator i = amitranFiles.begin(); i != amitranFiles.end(); ++i) {
681
if (!FileHelpers::isReadable(*i)) {
682
throw ProcessError(TLF("Could not access matrix file '%' to load.", *i));
683
}
684
PROGRESS_BEGIN_MESSAGE("Loading matrix in Amitran format from '" + *i + "'");
685
ODAmitranHandler handler(*this, *i);
686
if (!XMLSubSys::runParser(handler, *i)) {
687
PROGRESS_FAILED_MESSAGE();
688
} else {
689
PROGRESS_DONE_MESSAGE();
690
}
691
}
692
myVType = oc.getString("vtype");
693
for (std::string file : oc.getStringVector("tazrelation-files")) {
694
if (!FileHelpers::isReadable(file)) {
695
throw ProcessError(TLF("Could not access matrix file '%' to load.", file));
696
}
697
PROGRESS_BEGIN_MESSAGE("Loading matrix in tazRelation format from '" + file + "'");
698
699
std::vector<SAXWeightsHandler::ToRetrieveDefinition*> retrieverDefs;
700
retrieverDefs.push_back(new SAXWeightsHandler::ToRetrieveDefinition(oc.getString("tazrelation-attribute"), true, *this));
701
SAXWeightsHandler handler(retrieverDefs, "");
702
if (!XMLSubSys::runParser(handler, file)) {
703
PROGRESS_FAILED_MESSAGE();
704
} else {
705
PROGRESS_DONE_MESSAGE();
706
}
707
}
708
}
709
710
void
711
ODMatrix::addTazRelWeight(const std::string intervalID, const std::string& from, const std::string& to,
712
double val, double beg, double end) {
713
add(val, std::make_pair(TIME2STEPS(beg), TIME2STEPS(end)), from, to, myVType == "" ? intervalID : myVType);
714
}
715
716
717
void
718
ODMatrix::loadRoutes(OptionsCont& oc, SUMOSAXHandler& handler) {
719
std::vector<std::string> routeFiles = oc.getStringVector("route-files");
720
for (std::vector<std::string>::iterator i = routeFiles.begin(); i != routeFiles.end(); ++i) {
721
if (!FileHelpers::isReadable(*i)) {
722
throw ProcessError(TLF("Could not access route file '%' to load.", *i));
723
}
724
PROGRESS_BEGIN_MESSAGE("Loading routes and trips from '" + *i + "'");
725
if (!XMLSubSys::runParser(handler, *i)) {
726
PROGRESS_FAILED_MESSAGE();
727
} else {
728
PROGRESS_DONE_MESSAGE();
729
}
730
}
731
}
732
733
734
Distribution_Points
735
ODMatrix::parseTimeLine(const std::vector<std::string>& def, bool timelineDayInHours) {
736
Distribution_Points result("N/A");
737
if (timelineDayInHours) {
738
if (def.size() != 24) {
739
throw ProcessError(TLF("Assuming 24 entries for a day timeline, but got %.", toString(def.size())));
740
}
741
for (int chour = 0; chour < 24; ++chour) {
742
result.add(chour * 3600., StringUtils::toDouble(def[chour]));
743
}
744
result.add(24 * 3600., 0.); // dummy value to finish the last interval
745
} else {
746
for (int i = 0; i < (int)def.size(); i++) {
747
StringTokenizer st2(def[i], ":");
748
if (st2.size() != 2) {
749
throw ProcessError(TLF("Broken time line definition: missing a value in '%'.", def[i]));
750
}
751
const double time = StringUtils::toDouble(st2.next());
752
result.add(time, StringUtils::toDouble(st2.next()));
753
}
754
}
755
return result;
756
}
757
758
759
void
760
ODMatrix::sortByBeginTime() {
761
std::sort(myContainer.begin(), myContainer.end(), cell_by_begin_comparator());
762
}
763
764
765
/****************************************************************************/
766
767