SocialGroupMovementModel.java 16.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
 * Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
 *
 * This file is part of PeerfactSim.KOM.
 * 
 * PeerfactSim.KOM is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * 
 * PeerfactSim.KOM 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.
 * 
 * You should have received a copy of the GNU General Public License
 * along with PeerfactSim.KOM.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package de.tud.kom.p2psim.impl.topology.movement.modularosm;

23
import java.util.LinkedHashMap;
24
25
26
import java.util.LinkedHashSet;

import de.tud.kom.p2psim.api.scenario.ConfigurationException;
27
import de.tud.kom.p2psim.api.topology.Topology;
28
29
30
31
32
33
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.MovementGroupContainer;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.groupencounter.IGroupEncounterBehavior;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.groupforming.IGroupFormingBehavior;
Julian Zobel's avatar
wip    
Julian Zobel committed
34
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.IAttractionAssigmentStrategy;
35
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
36
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
37
import de.tud.kom.p2psim.impl.util.Either;
38
import de.tudarmstadt.maki.simonstrator.api.Binder;
39
import de.tudarmstadt.maki.simonstrator.api.Event;
40
import de.tudarmstadt.maki.simonstrator.api.Monitor;
41
import de.tudarmstadt.maki.simonstrator.api.Time;
42
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.IAttractionPoint;
43
44
45
46
47
48
49
50

/**
 * 
 * @author Julian Zobel
 * @version 1.0, 28.01.2020
 */
public class SocialGroupMovementModel extends ModularMovementModel {

51
52
53
	private final double MEETING_POINT_DISTANCE = 5;
	private final double LEADER_GROUP_DISTANCE = 10;
	
54
55
56
	protected MovementGroupContainer groupContainer;
	protected IGroupFormingBehavior groupFormingBehavior;
	protected IGroupEncounterBehavior groupEncounterBehavior;
57
58
	
	protected IAttractionAssigmentStrategy groupAttractionAssignment;
59
		
60
	private LinkedHashSet<SimLocationActuator> singleHosts = new LinkedHashSet<SimLocationActuator>();
61
	private int numberOfSingleHosts;	
62
63
64
	
	@Override
	public void initialize() {
65
		
66
		if (!initialized) {
67
			
68
69
70
71
72
73
74
75
76
77
78
			groupContainer = MovementGroupContainer.getInstance();
			groupFormingBehavior.initialize(this);
			groupEncounterBehavior.initialize(this);
			
			// Choose single hosts
			if(numberOfSingleHosts > 0) {
				do {
					singleHosts.add(getRandomActuator());
				} while(singleHosts.size() < numberOfSingleHosts);
			}
			
79
80
81
82
83
84
85
			if (modelVisualisation == null) {
				modelVisualisation = new ModularMovementModelViz(this);
			}
			VisualizationInjector.injectComponent(modelVisualisation);
			if (mapVisualization != null) {
				VisualizationInjector.injectComponent(mapVisualization);
			}
86
87
88
89
			if (attractionPointViz != null) {
				System.out.println("insert AP viz");
				VisualizationInjector.injectComponent(attractionPointViz);
			}
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

			checkConfiguration();

			// setWayPointModel
			localMovementStrategy.setObstacleModel(Binder
					.getComponentOrNull(Topology.class).getObstacleModel());
			localMovementStrategy.setWaypointModel(Binder
					.getComponentOrNull(Topology.class).getWaypointModel());

			/*
			 * Scale depending on calculation interval, if interval != 1 Second.
			 */
			localMovementStrategy
					.setScaleFactor(timeBetweenMoveOperation / (double) Time.SECOND);
			
			attractionAssigment.addAttractionAssignmentListener(this);
Julian Zobel's avatar
Julian Zobel committed
106
			attractionAssigment.setAttractionProvider(attractionProvider);
107

108
109
110
			groupAttractionAssignment.addAttractionAssignmentListener(this);
			groupAttractionAssignment.setAttractionProvider(attractionProvider);
			
111
112
113
			// This adds the mobile hosts (smartphones/users) to the transition
			// strategy
			for (SimLocationActuator ms : moveableHosts) {
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
				if(singleHosts.contains(ms)) {
					attractionAssigment.addComponent(ms);
					
					if(placeNodesAtAP) {
						IAttractionPoint assignment = attractionAssigment.getAssignment(ms);
						ms.updateCurrentLocation(this.addOffset(new PositionVector(assignment),
								(assignment.hasRadius() ? Math.max(assignment.getRadius(), 25.0) : 25.0)));	
						attractionAssigment.updateTargetAttractionPoint(ms, assignment);
					}		
				}
				else {
					groupAttractionAssignment.addComponent(ms);
					
					if(placeNodesAtAP) {
						IAttractionPoint assignment = groupAttractionAssignment.getAssignment(ms);
						ms.updateCurrentLocation(this.addOffset(new PositionVector(assignment),
								(assignment.hasRadius() ? Math.max(assignment.getRadius(), 25.0) : 25.0)));	
						groupAttractionAssignment.updateTargetAttractionPoint(ms, assignment);
					}		
				}
//				//attractionAssigment.addComponent(ms);
//				if(placeNodesAtAP) {
//					IAttractionPoint assignment = attractionAssigment.getAssignment(ms);
//					ms.updateCurrentLocation(this.addOffset(new PositionVector(assignment),
//							(assignment.hasRadius() ? Math.max(assignment.getRadius(), 25.0) : 25.0)));	
//					attractionAssigment.updateTargetAttractionPoint(ms, assignment);
//				}								
141
			}
142
						
143
144
			setTimeBetweenMoveOperations(timeBetweenMoveOperation);

145
146
			// Inform analyzer of resolved movement
			if(Monitor.hasAnalyzer(IAttractionBasedMovementAnalyzer.class)) {			
147
				Monitor.getOrNull(IAttractionBasedMovementAnalyzer.class).onAllNodeInitializationCompleted(moveableHosts);
148
149
			}
			
150
151
152
153
			// initial move
			move();

			initialized = true;
154
155
		}
	}
156
		
157
	
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
	/**
	 * Returns a random SimLocationActuator component from the set of moveable hosts.
	 * 
	 * @return SimLocationActuator
	 */
	private SimLocationActuator getRandomActuator() {
		
		int index = rand.nextInt(moveableHosts.size());
		int i = 0;
		for(SimLocationActuator actuator : moveableHosts) {
			if(i == index) {
				return actuator;
			}
			i++;
		}

		return null;
	}
	
	/**
	 * The movement model. 
	 * 1) Updates the number of hosts within each attraction point.
	 * 2) Creates and deletes groups, if necessary.
	 * 3) Applies encounter action to meeting groups.
	 * 4) Moves the hosts using doGroupMovement, movement style depends on role of the host (Leader, Participant, Single)
	 */
	@Override
Julian Zobel's avatar
wip    
Julian Zobel committed
185
	protected void move() {	
186
				
187
188
189
		// Check POIs if groups can be created. Delete groups, if destination reached.
		groupFormingBehavior.manageGroups();
		
190
191
		// Checks if groups encounter each other and applies a specified action to these groups.		
		groupEncounterBehavior.handleEncounters();
192
193
	
		/*	
194
195
		 * Moves all nodes according to definition in group movement method
		 */
196
197
		for (SimLocationActuator host : moveableHosts) {
			assert currentTargets.containsKey(host);
198
						
199
			// Single Host Movement
200
201
202
203
			if(singleHosts.contains(host)) {			
				super.doLocalMovement(host, currentTargets.get(host));
			}
			else if( !groupContainer.isGroupMember(host)) {
204
205
206
207
208
209
210
211
				doLocalMovement(host, currentTargets.get(host));
			}
			else if(groupContainer.isGroupMember(host)){
				doGroupMovement(host, currentTargets.get(host));
			}
			else {
				throw new UnsupportedOperationException("SimLocationActuator " + host + " is neither in a group nor a single node");
			}
212
213
	
			// TODO maybe remodel the group movement to do a whole group?
214
			
215
		}
216
217
		
	
218
219
220
		// TODO Move each group
		
		
221
222
223
		Event.scheduleWithDelay(timeBetweenMoveOperation, this, null, EVENT_MOVE);
	}
		
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
	@Override
	protected void doLocalMovement(SimLocationActuator ms, PositionVector destination) {
		Either<PositionVector, Boolean> either = localMovementStrategy.nextPosition(ms, destination);
		
		if (either.hasLeft()) {
			ms.updateCurrentLocation(either.getLeft());
			if(!checkBoundaries(ms.getRealPosition())) {
				System.err.println("Social Group Movement Model: Host moved outside of simulated area!");
			}				
		} 
		else {
			groupAttractionAssignment.reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint());
		}
	}

	
240
241
242
243
244
245
246
247
248
249
250
	/**
	 * Applies movement of the host according to different circumstances:
	 * 
	 * Towards Destination: Host is not a group member || Group has met at meeting point successfully.
	 * Towards MeetingPoint: Host if group member and has not reached meeting point yet.
	 * No movement: Host reached meeting point, but still waits for group members to arrive.
	 * 
	 * @param SimLocationActuator The host to move.
	 * @param PositionVector Destination of the host.
	 */
	protected void doGroupMovement(SimLocationActuator host, PositionVector destination) {
251
252
253
254
		// This host is a member of a group, thus...
		SocialMovementGroup group = groupContainer.getGroupOfHost(host);	
		
		// if the group is currently gathering at a meeting point...
255
		if(movesToGroupMeetingPoint(host)) {
256
			// if this host has already arrived at the group meeting point..
257
			if(hostIsAtMeetingPoint(host)) {
258
259
260
261
				// ... and if the whole group is also at the meeting point...					
				if(groupGatheredAtMeetingPoint(group)) {				
					// remove the meeting point and thus, start moving towards the actual destination								
					group.setMeetingPoint(null);
262
				}
263
264
265
266
267
268
269
				// ... but the group is not gathered at the meeting point, do nothing and wait for the rest.
				else {								
					// inform analyzer of waiting group members
					if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {						
						Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onMemberWaitAtMeetingPoint(group, host);											
					}					
				}				
270
			}
271
272
			// if the host has not reached the group meeting point, move towards it.
			else {				
273
274
				PositionVector mp = groupContainer.getGroupOfHost(host).getMeetingPoint();
				doLocalMovement(host, mp);
275
276
277
278
279
				
				// inform analyzer group member moves to meeting point
				if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {						
					Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onMoveToMeetingPoint(group, host);								
				}
280
281
			}
		}
282
		// ... but if the group is currently on their way to the destination
283
		else {
284
			// the leader does a local movement
285
			if(groupContainer.isLeader(host)) {
Julian Zobel's avatar
Julian Zobel committed
286
				if(!groupContainer.isWaiting(groupContainer.getGroupOfHost(host))) {		
287
288
289
					// inform analyzer of movement to attraction point
					if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {						
						Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onGroupMovesToAttractionPoint(group);			
Julian Zobel's avatar
Julian Zobel committed
290
291
					}	
					
292
293
294
295
296
297
298
299
300
301
302
303
304
305
					doLocalMovement(host, destination);		
					
					PositionVector leaderPos = host.getRealPosition();					
					LinkedHashSet<SimLocationActuator> groupMembers = groupContainer.getGroupMembers(host);
					groupMembers.remove(host); // remove leader
									
					for (SimLocationActuator groupMember : groupMembers) {
						// Assign small offset to the host depending on the leaders position.						
						PositionVector offset = new PositionVector(rand.nextDouble() * LEADER_GROUP_DISTANCE, rand.nextDouble() * LEADER_GROUP_DISTANCE);
						PositionVector newPos = leaderPos.plus(offset);
					
						// Update location of host, which will be around the leaders location.
						groupMember.updateCurrentLocation(newPos);
					}
306
307
308
309
310
311
				}
				else {
					// inform analyzer of waiting group
					if(Monitor.hasAnalyzer(ISocialGroupMovementAnalyzer.class)) {						
						Monitor.getOrNull(ISocialGroupMovementAnalyzer.class).onGroupWait(group);
					}		
312
313
314
				}
			}
		}
315
		
316
317
	}
	
318
319
320
	@Override
	public void changeTargetLocation(SimLocationActuator actuator, IAttractionPoint ap) {
		if(singleHosts.contains(actuator)) {
321
			super.changeTargetLocation(actuator, ap);
322
323
324
		}
		else {
			groupAttractionAssignment.updateTargetAttractionPoint(actuator, ap);
325
			actuator.setMovementSpeed(this.speedProvider.calculateSpeed());
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
		}
				
	}	
	
	@Override
	public IAttractionPoint getTargetLocation(SimLocationActuator actuator) {		
		if(singleHosts.contains(actuator)) {
			return attractionAssigment.getAssignment(actuator);
		}
		else {
			return groupAttractionAssignment.getAssignment(actuator);
		}
	}
	
	
341
342
343
344
345
346
347
348
349
350
351
352
	/* 
	 * =====================================================================================================
	 * === MEETING POINT FUNCTIONS
	 * =====================================================================================================
	 */
	/**
	 * Checks if a host is currently on its way to a meeting point or to its destination.
	 * Returns true if moving towards meeting point, false else.
	 * 
	 * @param SimLocationActuator The host to be checked.
	 * @return Boolean
	 */
353
	private boolean movesToGroupMeetingPoint(SimLocationActuator host) {
354
355
356
357
358
		PositionVector meetingpoint = groupContainer.getGroupOfHost(host).getMeetingPoint();
		
		if(meetingpoint == null) 
			return false;		
		else if(meetingpoint != groupContainer.getGroupOfHost(host).getDestination())
359
			return true;
360
361
		else		
			return false;
362
363
364
365
366
367
368
369
	}

	/**
	 * Returns true, if all group members of a host including the host itself reached the meeting point, false else.
	 * 
	 * @param SimLocationActuator The host to be checked.
	 * @return Boolean
	 */
370
371
372
373
374
	private boolean groupGatheredAtMeetingPoint(SocialMovementGroup group) {
	
		for(SimLocationActuator participant : group.getMembers()) {
			if(!hostIsAtMeetingPoint(participant)) {
				return false;
375
376
			}
		}
377
378
		
		return true;
379
380
381
382
383
384
385
386
387
	}

	/**
	 * Returns true if the host reached its current meeting point, false else.
	 * 
	 * @param SimLocationActuator The host to be checked.
	 * @return Boolean
	 * 
	 */
388
	private boolean hostIsAtMeetingPoint(SimLocationActuator host) {
389
390
391
		PositionVector meetingpoint = groupContainer.getGroupOfHost(host).getMeetingPoint();
	
		if(host.getLastLocation().distanceTo(meetingpoint) <= MEETING_POINT_DISTANCE) 			
392
			return true;
393
394
		else
			return false;
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
	}

	/* 
	 * =====================================================================================================
	 * === MOVEMENT FUNCTIONS
	 * =====================================================================================================
	 */
	

	/**
	 * Host position adapts to leaders position by taking the leader position and adding a small offset
	 * 
	 * @param SimLocationActuator The host to be moved.
	 */
	private void followLeader(SimLocationActuator host) {
		SimLocationActuator leader = groupContainer.getGroupOfHost(host).getLeader();
411
						
412
413
		// Assign small offset to the host depending on the leaders position.
		PositionVector leaderPos = leader.getRealPosition();
414
		PositionVector offset = new PositionVector(rand.nextDouble() * LEADER_GROUP_DISTANCE, rand.nextDouble() * LEADER_GROUP_DISTANCE);
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
		PositionVector newPos = leaderPos.plus(offset);

		// Update location of host, which will be around the leaders location.
		host.updateCurrentLocation(newPos);
	}


	/* 
	 * =====================================================================================================
	 * === GETTER AND SETTER FUNCTIONS
	 * =====================================================================================================
	 */
	
	public void setGroupFormingBehavior(IGroupFormingBehavior defaultGroupForming) {
		if (defaultGroupForming == null) {
			throw new ConfigurationException(
					"GroupFormingStrategy is missing in ModularMovementModel!");
		}
		this.groupFormingBehavior = defaultGroupForming;
	}

	public void setGroupEncounterBehavior(IGroupEncounterBehavior defaultGroupEncounterBehavior) {
		if (defaultGroupEncounterBehavior == null) {
			throw new ConfigurationException(
					"GroupEncounterStrategy is missing in ModularMovementModel!");
		}
		this.groupEncounterBehavior = defaultGroupEncounterBehavior;
	}

Julian Zobel's avatar
wip    
Julian Zobel committed
444
	public IAttractionAssigmentStrategy getAttractionAssignmentStrategy() {
445
		return this.groupAttractionAssignment;
Julian Zobel's avatar
wip    
Julian Zobel committed
446
447
448
449
	}
	
	public IGroupFormingBehavior getGroupFormingBehavior() {
		return groupFormingBehavior;
450
451
452
453
454
455
456
457
458
459
	}

	public LocalMovementStrategy getMovementStrategy() {
		return localMovementStrategy;
	}
	
	public void setNumberOfSingleHosts(int numberOfSingleHosts) {
		this.numberOfSingleHosts = numberOfSingleHosts;
	}
	
460
	public LinkedHashSet<SimLocationActuator> getSingleHosts(){
461
462
463
		return singleHosts;
	}	

464
	public LinkedHashMap<SimLocationActuator, PositionVector> getCurrentTargets(){
465
466
		return currentTargets;
	}
467
468
469
470
471
472
473
474
475
	
	public void setGroupAttractionAssignmentStrategy(IAttractionAssigmentStrategy groupAttractionAssignment) {
		if (groupAttractionAssignment == null) {
			throw new ConfigurationException(
					"IAttractionAssigmentStrategy for Groups is missing in SocialGroupMovementModel!");
		}
		
		this.groupAttractionAssignment = groupAttractionAssignment;
	}
476
}