19
19
import org .matsim .core .population .PopulationUtils ;
20
20
import org .matsim .core .router .TripStructureUtils ;
21
21
import org .matsim .core .utils .geometry .CoordUtils ;
22
+ import org .matsim .core .utils .misc .OptionalTime ;
22
23
import picocli .CommandLine ;
23
24
24
25
import java .nio .file .Files ;
25
26
import java .nio .file .Path ;
26
27
import java .util .*;
27
- import java .util .stream .Collectors ;
28
28
29
29
@ CommandLine .Command (
30
30
name = "check-population" ,
@@ -121,16 +121,16 @@ public Integer call() throws Exception {
121
121
122
122
List <? extends Person > agents = population .getPersons ().values ().stream ()
123
123
.filter (filter )
124
- .collect ( Collectors . toList () );
124
+ .toList ();
125
125
126
126
// agents with trips
127
127
List <? extends Person > mobileAgents = agents .stream ()
128
- .filter (a -> TripStructureUtils .getTrips (a .getSelectedPlan ()).size () > 0 )
129
- .collect ( Collectors . toList () );
128
+ .filter (a -> ! TripStructureUtils .getTrips (a .getSelectedPlan ()).isEmpty () )
129
+ .toList ();
130
130
131
131
List <TripStructureUtils .Trip > trips = agents .stream ().flatMap (
132
132
agent -> TripStructureUtils .getTrips (agent .getSelectedPlan ().getPlanElements ()).stream ()
133
- ).collect ( Collectors . toList () );
133
+ ).toList ();
134
134
135
135
log .info ("Number of trips: \t \t {}" , trips .size ());
136
136
log .info ("Avg. trips per agent: \t {}" , (double ) trips .size () / agents .size ());
@@ -154,6 +154,8 @@ public Integer call() throws Exception {
154
154
counts .forEach ((k , v ) -> log .info ("\t {}-m: {} ({}%)" , k .intValue (), v , Math .round ((v * 1000d ) / trips .size ()) / 10d ));
155
155
156
156
sep ();
157
+ log .info ("Activities:" );
158
+ log .info ("" );
157
159
158
160
Object2IntMap <String > acts = new Object2IntAVLTreeMap <>();
159
161
Object2IntMap <String > firstAct = new Object2IntAVLTreeMap <>();
@@ -164,35 +166,98 @@ public Integer call() throws Exception {
164
166
165
167
List <TripStructureUtils .Subtour > subtours = new ArrayList <>();
166
168
169
+ NavigableSet <Double > timeGroups = new TreeSet <>(List .of (0d , 1d , 2d , 3d , 4d , 5d , 6d , 7d , 8d , 9d , 10d , 11d ,
170
+ 12d , 13d , 14d , 15d , 16d , 17d , 18d , 19d , 20d , 21d , 22d , 23d ));
171
+ Map <String , Double2IntMap > actStartTimes = new HashMap <>();
172
+ Map <String , Double2IntMap > actEndTimes = new HashMap <>();
173
+ int noStartTime = 0 ;
174
+ int noEndTime = 0 ;
175
+ int noStartAndEndTime = 0 ;
176
+ int zeroDurationActs = 0 ;
177
+ int numberOfActs = 0 ;
178
+
167
179
for (Person agent : agents ) {
168
180
169
181
// if there are no facility or link ids. the coordinate is used as proxy id.
170
182
for (PlanElement el : agent .getSelectedPlan ().getPlanElements ()) {
171
- if (el instanceof Activity ) {
172
- Activity act = (Activity ) el ;
173
- if (act .getFacilityId () == null && act .getLinkId () == null ) {
174
- act .setLinkId (Id .createLinkId (act .getCoord ().toString ()));
175
- }
183
+ if (el instanceof Activity act && act .getFacilityId () == null && act .getLinkId () == null ) {
184
+ act .setLinkId (Id .createLinkId (act .getCoord ().toString ()));
176
185
}
177
186
}
178
187
179
188
subtours .addAll (TripStructureUtils .getSubtours (agent .getSelectedPlan ()));
180
189
181
- List <String > activities = TripStructureUtils .getActivities (agent .getSelectedPlan (), TripStructureUtils .StageActivityHandling .ExcludeStageActivities )
182
- .stream ().map (CheckPopulation ::actName ).collect (Collectors .toList ());
190
+ List <Activity > activities = new ArrayList <>(TripStructureUtils .getActivities (agent .getSelectedPlan (), TripStructureUtils .StageActivityHandling .ExcludeStageActivities ));
183
191
184
- if (activities .size () == 0 )
192
+ if (activities .isEmpty () )
185
193
continue ;
186
194
187
- firstAct .mergeInt (activities .get (0 ), 1 , Integer ::sum );
188
- lastAct .mergeInt (activities .get (activities .size () - 1 ), 1 , Integer ::sum );
189
- activities .forEach (act -> acts .mergeInt (act , 1 , Integer ::sum ));
195
+ firstAct .mergeInt (actName (activities .getFirst ()), 1 , Integer ::sum );
196
+ lastAct .mergeInt (actName (activities .getLast ()), 1 , Integer ::sum );
197
+ activities .forEach (act -> acts .mergeInt (actName (act ), 1 , Integer ::sum ));
198
+
199
+ for (Activity act : Sets .newHashSet (activities )) {
200
+ String name = actName (act );
201
+ haveActivity .mergeInt (name , 1 , Integer ::sum );
202
+
203
+ boolean hasNoStartTime = false ;
204
+ boolean hasNoEndTime = false ;
205
+
206
+ // find time bin for start and end of act or increase counter if no start or end time is defined
207
+ hasNoStartTime = categorizeTime (act .getStartTime (), timeGroups , actStartTimes , name , hasNoStartTime );
208
+ hasNoEndTime = categorizeTime (act .getEndTime (), timeGroups , actEndTimes , name , hasNoEndTime );
209
+
210
+ // increase counters
211
+ if (hasNoStartTime || hasNoEndTime ) {
212
+ noStartTime += hasNoStartTime ? 1 : 0 ;
213
+ noEndTime += hasNoEndTime ? 1 : 0 ;
214
+ noStartAndEndTime += (hasNoStartTime && hasNoEndTime ) ? 1 : 0 ;
215
+ }
190
216
191
- for (String act : Sets .newHashSet (activities )) {
192
- haveActivity .mergeInt (act , 1 , Integer ::sum );
217
+ double duration = 0. ;
218
+ if (act .getStartTime ().isDefined () && act .getEndTime ().isDefined ()) {
219
+ duration = act .getEndTime ().seconds () - act .getStartTime ().seconds ();
220
+ } else if (act .getStartTime ().isDefined () && !act .getEndTime ().isDefined ()) {
221
+ // initiate as 24h in case act is the last act of a plan
222
+ double previousActStart = 24 * 3600. ;
223
+
224
+ if (activities .indexOf (act ) != activities .indexOf (activities .getLast ())) {
225
+ previousActStart = activities .get (activities .indexOf (act ) + 1 ).getStartTime ().seconds ();
226
+ }
227
+ duration = previousActStart - act .getStartTime ().seconds ();
228
+ } else if (act .getEndTime ().isDefined () && !act .getStartTime ().isDefined ()) {
229
+ // initiate as 0 in case act is first act of a plan
230
+ double previousActEnd = 0. ;
231
+ if (activities .indexOf (act ) != activities .indexOf (activities .getFirst ())) {
232
+ previousActEnd = activities .get (activities .indexOf (act ) - 1 ).getEndTime ().seconds ();
233
+ }
234
+ duration = act .getEndTime ().seconds () - previousActEnd ;
235
+ }
236
+
237
+ if (duration <= 0. ) {
238
+ zeroDurationActs ++;
239
+ }
240
+ numberOfActs ++;
193
241
}
194
242
}
195
243
244
+ log .info ("Activity type start time distributions:" );
245
+ log .info ("" );
246
+
247
+ logActTimes (actStartTimes );
248
+
249
+ log .info ("Activity type end time distributions:" );
250
+ log .info ("" );
251
+
252
+ logActTimes (actEndTimes );
253
+
254
+ log .info ("Activities without start time: {}" , noStartTime );
255
+ log .info ("Activities without end time: {}" , noEndTime );
256
+ log .info ("Activities without start AND end time: {}" , noStartAndEndTime );
257
+ log .info ("Activities with duration of <=0s: {} ({}%)" , zeroDurationActs , String .format ("%.2f" , ((double ) zeroDurationActs / numberOfActs ) * 100 ));
258
+ log .info ("" );
259
+
260
+
196
261
log .info ("Number of persons having at least one activity:" );
197
262
haveActivity .forEach ((k , v ) -> log .info ("\t {}: {} ({}%)" , k , v , Math .round ((v * 1000d ) / agents .size ()) / 10d ));
198
263
@@ -210,14 +275,36 @@ public Integer call() throws Exception {
210
275
211
276
long closed = subtours .stream ().filter (TripStructureUtils .Subtour ::isClosed ).count ();
212
277
213
- if (subtours .size () > 0 )
278
+ if (! subtours .isEmpty () )
214
279
log .info ("Closed subtours estimate: \t {}%" , Math .round ((closed * 1000d ) / subtours .size ()) / 10d );
215
280
else
216
281
log .info ("No info about subtours (link or facilities ids missing)" );
217
282
218
283
return 0 ;
219
284
}
220
285
286
+ private static void logActTimes (Map <String , Double2IntMap > actTimesMap ) {
287
+ actTimesMap .forEach ((k , v ) -> {
288
+ double total = v .values ().intStream ().sum ();
289
+
290
+ // Iterate again to log each entry
291
+ v .forEach ((subKey , subValue ) -> log .info ("{} - {}h: {} ({}%)" , k , subKey , subValue , String .format ("%.2f" , (subValue / total ) * 100 )));
292
+ log .info ("" );
293
+ });
294
+ }
295
+
296
+ private boolean categorizeTime (OptionalTime time , NavigableSet <Double > timeGroups , Map <String , Double2IntMap > timesMap , String name , boolean timeNotDefined ) {
297
+ if (time .isDefined ()) {
298
+ double group = timeGroups .floor (Math .floor (time .seconds ()/3600 ));
299
+
300
+ timesMap .putIfAbsent (name , new Double2IntAVLTreeMap ());
301
+ timesMap .get (name ).mergeInt (group , 1 , Integer ::sum );
302
+ } else {
303
+ timeNotDefined = true ;
304
+ }
305
+ return timeNotDefined ;
306
+ }
307
+
221
308
private static String actName (Activity act ) {
222
309
223
310
int idx = act .getType ().lastIndexOf ("_" );
0 commit comments