Commit 6ccbc90e authored by Julian Zobel's avatar Julian Zobel
Browse files

First adaptations for social group movement

parent acff5b18
...@@ -93,9 +93,9 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction ...@@ -93,9 +93,9 @@ import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Attraction
*/ */
public class ModularMovementModel implements MovementModel, EventHandler, AttractionAssignmentListener { public class ModularMovementModel implements MovementModel, EventHandler, AttractionAssignmentListener {
private final int EVENT_MOVE = 1; protected final int EVENT_MOVE = 1;
private final int EVENT_INIT = 2; protected final int EVENT_INIT = 2;
protected PositionVector worldDimensions; protected PositionVector worldDimensions;
...@@ -107,25 +107,24 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -107,25 +107,24 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
protected IMapVisualization mapVisualization; protected IMapVisualization mapVisualization;
private ModularMovementModelViz modelVisualisation; protected ModularMovementModelViz modelVisualisation;
protected Set<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>(); protected Set<SimLocationActuator> moveableHosts = new LinkedHashSet<SimLocationActuator>();
private Map<SimLocationActuator, PositionVector> currentTarget = new LinkedHashMap<>(); protected Map<SimLocationActuator, PositionVector> currentTargets = new LinkedHashMap<>();
private Map<SimLocationActuator, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>(); protected Map<SimLocationActuator, RouteSensorComponent> routeSensorComponents = new LinkedHashMap<>();
private boolean initialized = false; protected boolean initialized = false;
private long timeBetweenMoveOperation = Simulator.SECOND_UNIT; protected long timeBetweenMoveOperation = Simulator.SECOND_UNIT;
private Random rand; protected Random rand = Randoms.getRandom(ModularMovementModel.class);
public ModularMovementModel() { public ModularMovementModel() {
this.worldDimensions = Binder.getComponentOrNull(Topology.class) this.worldDimensions = Binder.getComponentOrNull(Topology.class)
.getWorldDimensions(); .getWorldDimensions();
this.rand = Randoms.getRandom(ModularMovementModel.class);
// scheduling initalization! // scheduling initalization!
Event.scheduleImmediately(this, null, EVENT_INIT); Event.scheduleImmediately(this, null, EVENT_INIT);
} }
...@@ -137,6 +136,9 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -137,6 +136,9 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
public void initialize() { public void initialize() {
if (!initialized) { if (!initialized) {
System.out.println("init modular movement model");
if (modelVisualisation == null) { if (modelVisualisation == null) {
modelVisualisation = new ModularMovementModelViz(this); modelVisualisation = new ModularMovementModelViz(this);
} }
...@@ -188,12 +190,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -188,12 +190,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
@Override @Override
public void changeTargetLocation(SimLocationActuator actuator, AttractionPoint ap) { public void changeTargetLocation(SimLocationActuator actuator, AttractionPoint ap) {
transition.updateTargetAttractionPoint(actuator, ap); transition.updateTargetAttractionPoint(actuator, ap);
} }
@Override
public AttractionPoint getTargetLocation(SimLocationActuator actuator) {
return transition.getAssignment(actuator);
}
private void checkConfiguration() { private void checkConfiguration() {
if (localMovementStrategy == null) { if (localMovementStrategy == null) {
...@@ -217,21 +214,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -217,21 +214,7 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
routeSensorComponents.put(comp, new RouteSensorComponent(comp)); routeSensorComponents.put(comp, new RouteSensorComponent(comp));
} }
} }
public Set<SimLocationActuator> getAllLocationActuators() {
return moveableHosts;
}
@Override
public void setTimeBetweenMoveOperations(long time) {
if (time > 0) {
this.timeBetweenMoveOperation = time;
} else {
throw new ConfigurationException(
"time is negative for the Move Operations");
}
}
@Override @Override
public void updatedAttractionAssignment(SimLocationActuator component, public void updatedAttractionAssignment(SimLocationActuator component,
AttractionPoint newAssignment) { AttractionPoint newAssignment) {
...@@ -270,13 +253,13 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -270,13 +253,13 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
tries++; tries++;
} while (destination == null); } while (destination == null);
currentTarget.put(component, destination); currentTargets.put(component, destination);
} }
protected void move() { protected void move() {
for (SimLocationActuator component : moveableHosts) { for (SimLocationActuator component : moveableHosts) {
assert currentTarget.containsKey(component); assert currentTargets.containsKey(component);
doLocalMovement(component, currentTarget.get(component)); doLocalMovement(component, currentTargets.get(component));
} }
Event.scheduleWithDelay(timeBetweenMoveOperation, this, null, Event.scheduleWithDelay(timeBetweenMoveOperation, this, null,
EVENT_MOVE); EVENT_MOVE);
...@@ -291,40 +274,90 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -291,40 +274,90 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
* @param ms * @param ms
* @param destination * @param destination
*/ */
protected void doLocalMovement(SimLocationActuator ms, protected void doLocalMovement(SimLocationActuator ms, PositionVector destination) {
PositionVector destination) { Either<PositionVector, Boolean> either = localMovementStrategy.nextPosition(ms, destination);
Either<PositionVector, Boolean> either = localMovementStrategy
.nextPosition(ms, destination);
if (either.hasLeft()) { if (either.hasLeft()) {
ms.updateCurrentLocation(either.getLeft()); ms.updateCurrentLocation(either.getLeft());
/* checkBoundaries(ms);
* Check for negative or out of bound coordinates! }
*/ else {
assert ms.getRealPosition().getX() >= 0.0
&& ms.getRealPosition().getX() <= Binder
.getComponentOrNull(Topology.class)
.getWorldDimensions().getX();
assert ms.getRealPosition().getY() >= 0.0
&& ms.getRealPosition().getY() <= Binder
.getComponentOrNull(Topology.class)
.getWorldDimensions().getY();
} else {
transition.reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint()); transition.reachedAttractionPoint(ms, ms.getCurrentTargetAttractionPoint());
} }
} }
public void setIAttractionGenerator( /*
IAttractionGenerator attractionGenerator) { * =====================================================================================================
* === HELPER FUNCTIONS
* =====================================================================================================
*/
/**
* Notifies the user if a hosts position lies outside of the specified world size.
* Enable asserts to get the notification
*
* @param SimLocationActuator The host to be checked
*/
public void checkBoundaries(SimLocationActuator ms) {
assert ms.getRealPosition().getX() >= 0.0
&& ms.getRealPosition().getX() <= Binder
.getComponentOrNull(Topology.class)
.getWorldDimensions().getX();
assert ms.getRealPosition().getY() >= 0.0
&& ms.getRealPosition().getY() <= Binder
.getComponentOrNull(Topology.class)
.getWorldDimensions().getY();
}
@Override
public void eventOccurred(Object content, int type) {
if (type == EVENT_INIT) {
initialize();
} else if (type == EVENT_MOVE) {
move();
}
}
/*
* =====================================================================================================
* === GETTER AND SETTER FUNCTIONS
* =====================================================================================================
*/
public Set<SimLocationActuator> getAllLocationActuators() {
return moveableHosts;
}
@Override
public void setTimeBetweenMoveOperations(long time) {
if (time > 0) {
this.timeBetweenMoveOperation = time;
} else {
throw new ConfigurationException(
"time is negative for the Move Operations");
}
}
public void setIAttractionGenerator(IAttractionGenerator attractionGenerator) {
if (attractionGenerator == null) {
throw new ConfigurationException(
"AttractionGenerator is missing in ModularMovementModel!");
}
this.attractionGenerator = attractionGenerator; this.attractionGenerator = attractionGenerator;
} }
public void setLocalMovementStrategy( public void setLocalMovementStrategy(LocalMovementStrategy localMovementStrategy) {
LocalMovementStrategy localMovementStrategy) { if (localMovementStrategy == null) {
throw new ConfigurationException(
"LocalMovementStrategy is missing in ModularMovementModel!");
}
this.localMovementStrategy = localMovementStrategy; this.localMovementStrategy = localMovementStrategy;
} }
public void setITransitionStrategy(ITransitionStrategy transition) { public void setITransitionStrategy(ITransitionStrategy transition) {
if (transition == null) {
throw new ConfigurationException(
"TransitionStrategy is missing in ModularMovementModel!");
}
this.transition = transition; this.transition = transition;
} }
...@@ -339,14 +372,10 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac ...@@ -339,14 +372,10 @@ public class ModularMovementModel implements MovementModel, EventHandler, Attrac
} }
@Override @Override
public void eventOccurred(Object content, int type) { public AttractionPoint getTargetLocation(SimLocationActuator actuator) {
if (type == EVENT_INIT) { return transition.getAssignment(actuator);
initialize();
} else if (type == EVENT_MOVE) {
move();
}
} }
/** /**
* Only for visualization! * Only for visualization!
* *
......
/*
* 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;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Vector;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.topology.Topology;
import de.tud.kom.p2psim.api.topology.movement.MovementModel;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.api.topology.movement.local.LocalMovementStrategy;
import de.tud.kom.p2psim.api.topology.placement.PlacementModel;
import de.tud.kom.p2psim.impl.simengine.Simulator;
import de.tud.kom.p2psim.impl.topology.TopologyFactory;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionGenerator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.hostcount.IAttractionPointHostCounter;
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;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.mapvisualization.IMapVisualization;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy.AttractionAssignmentListener;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.topology.views.VisualizationTopologyView.VisualizationInjector;
import de.tud.kom.p2psim.impl.util.Either;
import de.tudarmstadt.maki.simonstrator.api.Binder;
import de.tudarmstadt.maki.simonstrator.api.Event;
import de.tudarmstadt.maki.simonstrator.api.EventHandler;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
/**
*
* @author Julian Zobel
* @version 1.0, 28.01.2020
*/
public class SocialGroupMovementModel extends ModularMovementModel {
protected MovementGroupContainer groupContainer;
protected IGroupFormingBehavior groupFormingBehavior;
protected IGroupEncounterBehavior groupEncounterBehavior;
protected IAttractionPointHostCounter attractionPointHostCounter;
private Set<SimLocationActuator> singleHosts = new LinkedHashSet<SimLocationActuator>();
private int numberOfSingleHosts;
@Override
public void initialize() {
if (!initialized) {
System.out.println("init social group movement");
groupContainer = MovementGroupContainer.getInstance();
attractionPointHostCounter.initialize(this);
groupFormingBehavior.initialize(this);
groupEncounterBehavior.initialize(this);
// Choose single hosts
if(numberOfSingleHosts > 0) {
do {
singleHosts.add(getRandomActuator());
} while(singleHosts.size() < numberOfSingleHosts);
}
super.initialize();
}
}
/**
* Returns a random SimLocationActuator component from the set of moveable hosts.
*
* @return SimLocationActuator
*
* @author Marcel Verst
*/
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)
*
* @author Marcel Verst
*/
@Override
protected void move() {
System.out.println("social group : move");
// Update the number of hosts within each attraction point.
attractionPointHostCounter.updateHostCount();
// Check POIs if groups can be created. Delete groups, if destination reached.
groupFormingBehavior.manageGroups();
// Checks if groups encounter each other and applies a specified action to these groups.
Set<SocialMovementGroup[]> encounteringGroups = groupEncounterBehavior.getEncounteringGroups();
groupEncounterBehavior.handleEncounters(encounteringGroups);
/**
* Moves all nodes according to definition in group movement method
*/
for (SimLocationActuator component : moveableHosts) {
assert currentTargets.containsKey(component);
doGroupMovement(component, currentTargets.get(component));
}
Event.scheduleWithDelay(timeBetweenMoveOperation, this, null, EVENT_MOVE);
}
/**
* 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.
*
* @author Marcel Verst
*/
protected void doGroupMovement(SimLocationActuator host, PositionVector destination) {
// Single Host Movement
if(singleHosts.contains(host) && !groupContainer.isGroupMember(host)) {
System.out.println("local movement");
doLocalMovement(host, destination);
}
// Group Related Movement
else if(groupContainer.isGroupMember(host)){
if(movesToMP(host)) {
if(atMP(host)) {
if(groupAtMP(host)) {
SocialMovementGroup group = groupContainer.getGroupOfHost(host);
AttractionPoint currAp = group.getLeader().getCurrentTargetAttractionPoint();
PositionVector currDest = group.getDestination();
group.setMeetingPoint(currDest);
for(SimLocationActuator participant : group.getMembers()) {
transition.updateTargetAttractionPoint(participant, currAp);
}
}
}
// MP not reached. Move to MP.
else {
PositionVector mp = groupContainer.getGroupOfHost(host).getMeetingPoint();
doLocalMovement(host, mp);
}
}
// MP reached. Move to destination.
else {
if(groupContainer.isLeader(host)) {
if(!groupContainer.isWaiting(groupContainer.getGroupOfHost(host))) {
doLocalMovement(host, destination);
}
}
else {
followLeader(host);
}
}
}
}
/*
* =====================================================================================================
* === 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
*
* @author Marcel Verst
*/
private boolean movesToMP(SimLocationActuator host) {
PositionVector mp = groupContainer.getGroupOfHost(host).getMeetingPoint();
PositionVector dest = groupContainer.getGroupOfHost(host).getDestination();
if(mp != dest) {
return true;
}
return false;
}
/**
* 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
*
* @author Marcel Verst
*/
private boolean groupAtMP(SimLocationActuator host) {
Set<SimLocationActuator> participants = groupContainer.getGroupMembers(host);
int counter = 0;
for(SimLocationActuator participant : participants) {
if(atMP(participant)) {
counter++;
}
}
if(counter == participants.size()) {
return true;
}
return false;
}
/**
* Returns true if the host reached its current meeting point, false else.
*
* @param SimLocationActuator The host to be checked.
* @return Boolean
*
* @author Marcel Verst
*/
private boolean atMP(SimLocationActuator host) {
PositionVector currMP = groupContainer.getGroupOfHost(host).getMeetingPoint();
// Setting the required distance to the meeting point to maximum of 2 meters
// This is equivalent to a distance of group members in real life
double distance = host.getLastLocation().distanceTo(currMP);
if(distance <= 2) {
return true;
}
return false;
}
/*
* =====================================================================================================
* === 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.
*
* @author Marcel Verst
*/
private void followLeader(SimLocationActuator host) {
SimLocationActuator leader = groupContainer.getGroupOfHost(host).getLeader();
AttractionPoint leaderDestination = leader.getCurrentTargetAttractionPoint();
AttractionPoint hostDestination = host.getCurrentTargetAttractionPoint();
// Update target attraction point if not already done
if(hostDestination != leaderDestination) {
transition.updateTargetAttractionPoint(host, leaderDestination);
}
// Assign small offset to the host depending on the leaders position.
PositionVector leaderPos = leader.getRealPosition();
PositionVector offset = new PositionVector(rand.nextInt(2), rand.nextInt(2));
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;
}
public void setAttractionPointHostCounter(IAttractionPointHostCounter attractionPointHostCounter) {
if (attractionPointHostCounter == null) {
throw new ConfigurationException(
"HostCountStrategy is missing in ModularMovementModel!");
}
this.attractionPointHostCounter = attractionPointHostCounter;
}
public ITransitionStrategy getTransition() {
return transition;
}
public LocalMovementStrategy getMovementStrategy() {
return localMovementStrategy;
}
public IAttractionPointHostCounter getAttractionPointHostCounter() {
return attractionPointHostCounter;
}
public void setNumberOfSingleHosts(int numberOfSingleHosts) {
this.numberOfSingleHosts = numberOfSingleHosts;
}
public Set<SimLocationActuator> getSingleHosts(){
return singleHosts;
}
/**
* Only for visualization!
*
* @return
*/
public List<AttractionPoint> getAttractionPoints() {
return new Vector<AttractionPoint>(IAttractionGenerator.attractionPoints);
}
public Map<SimLocationActuator, PositionVector> getCurrentTargets(){
return currentTargets;
}
}
...@@ -43,8 +43,8 @@ public class AttractionPointImpl extends BasicAttractionPoint { ...@@ -43,8 +43,8 @@ public class AttractionPointImpl extends BasicAttractionPoint {
protected static Random rnd = Randoms.getRandom(AttractionPoint.class); protected static Random rnd = Randoms.getRandom(AttractionPoint.class);
protected static Map<String, AttractionPointImpl> instances = new LinkedHashMap<>(); protected static Map<String, AttractionPointImpl> instances = new LinkedHashMap<>();
protected long pauseTimeMin = 0; protected long pauseTimeMin = -1;
protected long pauseTimeMax = 0; protected long pauseTimeMax = -1;
protected double weight = 0; protected double weight = 0;
protected double radius = 0; protected double radius = 0;
...@@ -152,7 +152,11 @@ public class AttractionPointImpl extends BasicAttractionPoint { ...@@ -152,7 +152,11 @@ public class AttractionPointImpl extends BasicAttractionPoint {
@Override @Override
public boolean hasPauseTime() { public boolean hasPauseTime() {
return true; if(pauseTimeMax >= 0 || pauseTimeMin >= 0) {
return true;
}
else
return false;
} }
@Override @Override
......
/*
* 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.attraction.hostcount;
import java.util.Map;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
/**
* This abstract {@link IAttractionPointHostCounter} class provides methods for the basic functionality to count hosts in {@link AttractionPoint} areas.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*
* @author Julian Zobel
* @version 1.1, 27.01.2020
*
*/
public abstract class AbstractHostCounter implements IAttractionPointHostCounter {
protected ModularMovementModel movementModel;
protected Map<AttractionPoint, Set<SimLocationActuator>> attractionPointHosts;
/**
* Adds a specific host to a specific attraction point.
*
* @param SimLocationActuator The host to be added.
* @param AttractionPoint The attraction point to which the host is added
*/
protected void addHostToAttractionPoint(SimLocationActuator host, AttractionPoint poi) {
Set<SimLocationActuator> hosts = attractionPointHosts.get(poi);
hosts.add(host);
attractionPointHosts.put(poi, hosts);
}
/**
* Removes a specific host from its currently assigned poi.
*
* @param SimLocationActuator The host to be removed.
* @param AttractionPoint The attraction point from which the host is removed
*/
protected void removeHostFromAttractionPoint(SimLocationActuator host, AttractionPoint poi) {
Set<SimLocationActuator> hosts = attractionPointHosts.get(poi);
hosts.remove(host);
attractionPointHosts.put(poi, hosts);
}
/**
* Compares the locations of a given {@link Host} and a given {@link AttractionPoint} and checks if the host lies within the radius of the {@link AttractionPoint}.
* Returns true, if the hosts location is within the radius of the {@link AttractionPoint}, false otherwise.
*
* @param SimLocationActuator The host to be checked.
* @param AttractionPoint
* @return Boolean
*/
public boolean isHostInAttractionPointArea(SimLocationActuator host, AttractionPoint attractionPoint) {
PositionVector hostLocation = host.getRealPosition();
if(attractionPoint.distanceTo(hostLocation) <= attractionPoint.getRadius()) {
return true;
}
return false;
}
/**
* Returns the number of hosts within a specific {@link AttractionPoint}
*
* @param AttractionPoint The {@link AttractionPoint} to be checked.
* @return Integer
*/
@Override
public int getHostCountOfAttractionPoint(AttractionPoint attractionPoint) {
if(attractionPointHosts.get(attractionPoint) == null) {
return 0;
}
return attractionPointHosts.get(attractionPoint).size();
}
/**
* Returns a set of all hosts currently located within a specific {@link AttractionPoint} area.
*
* @param AttractionPoint The {@link AttractionPoint} to be checked.
* @return Set<SimLocationActuator>
*/
@Override
public Set<SimLocationActuator> getHostsOfAttractionPoint(AttractionPoint attractionPoint) {
return attractionPointHosts.get(attractionPoint);
}
}
/*
* 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.attraction.hostcount;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionGenerator;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
/**
* This class checks each {@link AttractionPoint} defined in the simulation and counts the number of hosts within their radius.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*
* @author Julian Zobel
* @version 1.1, 27.01.2020
*/
public class DefaultHostCounter extends AbstractHostCounter {
@Override
public void initialize(ModularMovementModel movementModel) {
this.movementModel = movementModel;
attractionPointHosts = new LinkedHashMap<>();
for(AttractionPoint ap : IAttractionGenerator.attractionPoints) {
attractionPointHosts.put(ap, new LinkedHashSet<>());
}
}
@Override
public void updateHostCount() {
Set<SimLocationActuator> moveableHosts = movementModel.getAllLocationActuators();
for(SimLocationActuator host : moveableHosts) {
for(AttractionPoint ap : attractionPointHosts.keySet()) {
if(isHostInAttractionPointArea(host, ap)) {
if(!registeredAtAttractionPoint(host, ap)) {
addHostToAttractionPoint(host, ap);
}
}
else {
if(registeredAtAttractionPoint(host, ap)) {
removeHostFromAttractionPoint(host, ap);
}
}
}
}
}
/*
* =====================================================================================================
* === HELPER FUNCTIONS
* =====================================================================================================
*/
/**
* Checks, if a specific host is NOT yet registered to a specific poi.
* Returns true, if host is NOT yet registered to a poi, false if already registered.
*
* @param SimLocationActuator The host to be checked.
* @param AttractionPoint The poi in which the host is expected.
* @return boolean
*/
private boolean registeredAtAttractionPoint(SimLocationActuator host, AttractionPoint poi) {
if(attractionPointHosts.get(poi).contains(host)) {
return true;
}
else return false;
}
}
/*
* 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.attraction.hostcount;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
/**
* Serves as an interface to count the number of hosts currently within POI areas.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public interface IAttractionPointHostCounter {
/**
* Initializes class variables.
*
* @author Marcel Verst
*/
public void initialize(ModularMovementModel movementModel);
/**
* Calculates the current number of hosts within each POI.
*
* Adds host to a POI, if the host is within POI area, but not already registered to the POI.
* Removes host from the POI, if the host is not within the POI area, but still registered to the POI.
*
* @author Marcel Verst
*/
public void updateHostCount();
/**
* Returns the number of hosts within a specific POI.
*
* @param AttractionPoint The POI to be checked.
* @return Integer
*
* @author Marcel Verst
*/
public int getHostCountOfAttractionPoint(AttractionPoint attractionPoint);
/**
* Returns a set of all hosts currently located within a specific POI area.
*
* @param AttractionPoint The POI to be checked.
* @return Set<SimLocationActuator>
*
* @author Marcel Verst
*/
public Set<SimLocationActuator> getHostsOfAttractionPoint(AttractionPoint attractionPoint);
}
\ No newline at end of file
/*
* 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.groups;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.util.Tuple;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* This class serves as a container to store variables of groups, which are used by multiple classes and interfaces.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public class MovementGroupContainer {
private static MovementGroupContainer instance;
private Set<SocialMovementGroup> groups;
// Mappings
private Map<SimLocationActuator, Long> leftGroupAtTime;
private Map<SimLocationActuator, Boolean> hasBeenInAGroup;
private Map<SimLocationActuator, Boolean> hasMerged;
private Map<SimLocationActuator, Long> mergedAtTime;
// Config variables
private int minGroupSize;
private int maxGroupSize;
private long waitTime;
// Waiting Groups, used for encounter strategy Wait. Includes remaining waiting time and last update time
public Map<SocialMovementGroup, Tuple<Long, Long>> waitingGroups;
private MovementGroupContainer() {
groups = new LinkedHashSet<>();
leftGroupAtTime = new LinkedHashMap<>();
hasBeenInAGroup = new LinkedHashMap<>();
hasMerged = new LinkedHashMap<>();
mergedAtTime = new LinkedHashMap<>();
waitingGroups = new LinkedHashMap<SocialMovementGroup, Tuple<Long,Long>>();
}
/**
* Returns the one and only instance of this class.
*
* @return GroupContainer
*
* @author Marcel Verst
*/
public static MovementGroupContainer getInstance() {
if(instance == null) {
synchronized (MovementGroupContainer.class) {
if (instance == null) {
instance = new MovementGroupContainer();
}
}
}
return instance;
}
/*
* =====================================================================================================
* === GROUP MODIFIER FUNCTIONS
* =====================================================================================================
*/
/**
* Adds a group to the set of groups.
*
* @param SocialMovementGroup The group to add.
*
* @author Marcel Verst
*/
public void addGroup(SocialMovementGroup group) {
groups.add(group);
}
/**
* Removes a group from the set of groups and sets the leftGroupAtTime variable for all group members.
*
* @param SocialMovementGroup The group to be removed.
*
* @author Marcel Verst
*/
public void removeGroup(SocialMovementGroup group) {
for(SimLocationActuator participant : group.getMembers()) {
leftGroupAtTime.put(participant, Time.getCurrentTime());
}
groups.remove(group);
}
/**
* If a group is changed (e.g. a host left the group) the new group is updated here.
*
* @param SocialMovementGroup The group which had an update.
*
* @author Marcel Verst
*/
public void updateGroupEntry(SocialMovementGroup group) {
if(groups.contains(group)) {
groups.remove(group);
}
groups.add(group);
}
/*
* =====================================================================================================
* === MAP MODIFIER FUNCTIONS
* =====================================================================================================
*/
public void addLeftGroupAtTimeEntry(SimLocationActuator host, Long time) {
leftGroupAtTime.put(host, time);
}
public void removeLeftGroupAtTimeEntry(SimLocationActuator host) {
if(leftGroupAtTime.containsKey(host)) {
leftGroupAtTime.remove(host);
}
}
public void addHasBeenInGroupEntry(SimLocationActuator host, Boolean value) {
hasBeenInAGroup.put(host, value);
}
public void removeHasBeenInGroupEntry(SimLocationActuator host) {
if(hasBeenInAGroup.containsKey(host)) {
hasBeenInAGroup.remove(host);
}
}
public void addHasMergedEntry(SimLocationActuator host, Boolean value) {
hasMerged.put(host, value);
}
public void removeHasMergedEntry(SimLocationActuator host) {
if(hasMerged.containsKey(host)) {
hasMerged.remove(host);
}
}
public void addMergedAtTimeEntry(SimLocationActuator host, Long time) {
mergedAtTime.put(host, time);
}
public void removeMergedAtTimeEntry(SimLocationActuator host) {
if(mergedAtTime.containsKey(host)) {
mergedAtTime.remove(host);
}
}
/*
* =====================================================================================================
* === HELPER FUNCTIONS
* =====================================================================================================
*/
/**
* Returns true, if the host is the leader of a group, false else.
*
* @param SimLocationActuator The host to be checked.
* @return Boolean
*
* @author Marcel Verst
*/
public boolean isLeader(SimLocationActuator host) {
boolean result = false;
SocialMovementGroup group = getGroupOfHost(host);
if(group != null && group.getLeader() == host) {
result = true;
}
return result;
}
/**
* Returns true, if a host is a group member, false else.
*
* @param SimLocationActuator The host to be checked.
* @return Boolean
*
* @author Marcel Verst
*/
public boolean isGroupMember(SimLocationActuator host) {
for(SocialMovementGroup group : groups) {
if(group.hasMember(host)) {
return true;
}
}
return false;
}
/**
* Returns true, if the host is a group member, but not a leader.
*
* @param SimLocationActuator The host to be checked.
* @return Boolean
*
* @author Marcel Verst
*/
public boolean isDependent(SimLocationActuator host) {
return isGroupMember(host) && !isLeader(host);
}
/**
* Returns the GroupInstance of which a host is a member of.
*
* @param SimLocationActuator The host to be checked.
* @return GroupInstance
*
* @author Marcel Verst
*/
public SocialMovementGroup getGroupOfHost(SimLocationActuator host) {
SocialMovementGroup result = null;
for(SocialMovementGroup group : groups) {
if(group.hasMember(host)) {
result = group;
}
}
return result;
}
/**
* Updates the variables if a host has already merged before and when the last merging process happened.
* This function HAS to be called before doing any encounter process.
*
* @param SocialMovementGroup The first group.
* @param SocialMovementGroup The second group.
*
* @author Marcel Verst
*/
public void updateMergeVars(SocialMovementGroup group1, SocialMovementGroup group2) {
Set<SimLocationActuator> all = new LinkedHashSet<>();
all.addAll(group1.getMembers());
all.addAll(group2.getMembers());
for(SimLocationActuator host : all) {
addHasMergedEntry(host, true);
addMergedAtTimeEntry(host, Time.getCurrentTime());
}
}
/**
* Returns true, if the given group is currently waiting.
*
* @param SocialMovementGroup The group to check.
*
* @return Boolean
*
* @author Marcel Verst
*/
public boolean isWaiting(SocialMovementGroup group) {
if(waitingGroups.containsKey(group)) {
return true;
}
return false;
}
/*
* =====================================================================================================
* === GETTER AND SETTER FUNCTIONS
* =====================================================================================================
*/
/**
* Returns a set of SimLocationActuators including the host itself which belong to the group of the host.
*
* @param SimLocationActuator The host to be checked.
* @return Set<SimLocationActuator>
*
* @author Marcel Verst
*/
public Set<SimLocationActuator> getGroupMembers(SimLocationActuator host){
return getGroupOfHost(host).getMembers();
}
public Set<SocialMovementGroup> getGroups() {
return groups;
}
public void setGroups(Set<SocialMovementGroup> groups) {
this.groups = groups;
}
public Map<SimLocationActuator, Long> getLeftGroupAtTime() {
return leftGroupAtTime;
}
public void setLeftGroupAtTime(Map<SimLocationActuator, Long> leftGroupAtTime) {
this.leftGroupAtTime = leftGroupAtTime;
}
public Map<SimLocationActuator, Boolean> getHasBeenInAGroup() {
return hasBeenInAGroup;
}
public void setHasBeenInAGroup(Map<SimLocationActuator, Boolean> hasBeenInAGroup) {
this.hasBeenInAGroup = hasBeenInAGroup;
}
public long getWaitTime() {
return waitTime;
}
public void setWaitTime(long waitTime) {
this.waitTime = waitTime;
}
public Map<SimLocationActuator, Boolean> getHasMerged() {
return hasMerged;
}
public void setHasMerged(Map<SimLocationActuator, Boolean> hasMerged) {
this.hasMerged = hasMerged;
}
public Map<SimLocationActuator, Long> getMergedAtTime() {
return mergedAtTime;
}
public void setMergedAtTime(Map<SimLocationActuator, Long> mergedAtTime) {
this.mergedAtTime = mergedAtTime;
}
public int getMinGroupSize() {
return minGroupSize;
}
public void setMinGroupSize(int minGroupSize) {
this.minGroupSize = minGroupSize;
}
public int getMaxGroupSize() {
return maxGroupSize;
}
public void setMaxGroupSize(int maxGroupSize) {
this.maxGroupSize = maxGroupSize;
}
}
\ No newline at end of file
/*
* 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.groups;
import java.util.LinkedHashSet;
import java.util.Random;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
/**
* This class handles the instance of a group. Each group instance has a leader which sets the behavior. All other
* participants follow the behavior of the leader in terms of speed, velocity, heading etc.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public class SocialMovementGroup {
private SimLocationActuator leader;
private LinkedHashSet<SimLocationActuator> members;
private PositionVector destination;
private PositionVector meetingPoint;
/**
* Initializes the group, sets the participants and groupId, finally chooses a random leader.
*
* @param Set<SimLocationActuator> All participants of the group.
* @param int The ID of the group.
*/
public SocialMovementGroup(Set<SimLocationActuator> participants){
setMembers(participants);
setRandomLeader();
}
/**
* Adds a host to the group. Manually check in {@link ModularMovementModel} class, if group size is exceeded by adding another host.
*
* @param SimLocationActuator The host to be added.
*/
public void addHostToGroup(SimLocationActuator host) {
members.add(host);
}
/**
* Removes a host from the group. If the host was the current leader, a random new leader is chosen from the remaining members.
*
* @param SimLocationActuator The host to be removed.
*/
public void removeHostFromGroup(SimLocationActuator host) {
if(members.contains(host)) {
if(host == leader) {
members.remove(host);
setRandomLeader();
}
else {
members.remove(host);
}
}
}
/**
* Sets a randomly chosen participant of the group as leader.
*/
private void setRandomLeader() {
this.leader = getRandomMember();
}
/**
* Returns a random participant of all group members.
*
* @return SimLocationActuator
*/
public SimLocationActuator getRandomMember() {
if(members.size() >= 1) {
Random rand = Randoms.getRandom(SocialMovementGroup.class);
int item = rand.nextInt(members.size() - 1);
int i = 0;
for(SimLocationActuator host : members) {
if(i == item) {
return host;
}
i++;
}
}
return null;
}
/**
* Returns true if this group has a specific host as member, false otherwise
*
* @param SimLocationActuator The host to be checked.
* @return boolean
*/
public boolean hasMember(SimLocationActuator host) {
if(members.contains(host)) {
return true;
}
return false;
}
/**
* Returns the position of the group leader.
*
* @return PositionVector The position of the group leader.
*/
public PositionVector getLeaderPosition() {
return leader.getRealPosition();
}
// ===================
// Getters and Setters
// ===================
public int getGroupSize() {
return members.size();
}
public Set<SimLocationActuator> getMembers() {
return members;
}
public void setMembers(Set<SimLocationActuator> participants) {
this.members = new LinkedHashSet<>(participants);
}
public SimLocationActuator getLeader() {
return leader;
}
public PositionVector getDestination() {
return destination;
}
public void setDestination(PositionVector destination) {
this.destination = destination;
}
public PositionVector getMeetingPoint() {
return meetingPoint;
}
public void setMeetingPoint(PositionVector meetingPoint) {
this.meetingPoint = meetingPoint;
}
}
/*
* 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.groups.groupencounter;
import java.util.LinkedHashSet;
import java.util.Random;
import java.util.Set;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.SocialGroupMovementModel;
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.util.PositionVector;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* This class contains methods used by all encounter strategies.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public abstract class AbstractGroupEncounter implements IGroupEncounterBehavior {
//--- COMMON VARIABLES TO BE DECLARED IN CONFIG ---
protected boolean enableGroupEncounters;
protected double meetingDistance;
//-------------------------------------------------
protected final int DECISION_NONE = 0;
protected final int DECISION_MERGE_FULL = 1;
protected final int DECISION_MERGE_PARTIAL = 2;
protected final int DECISION_DISSOLVE = 3;
protected SocialGroupMovementModel movementModel;
protected MovementGroupContainer groupCon;
protected Random rand = Randoms.getRandom(AbstractGroupEncounter.class);
@Override
public void initialize(SocialGroupMovementModel movementModel) {
groupCon = MovementGroupContainer.getInstance();
for(SimLocationActuator host : movementModel.getAllLocationActuators()) {
groupCon.addHasMergedEntry(host, false);
}
}
public Set<SocialMovementGroup[]> getEncounteringGroups() {
Set<SocialMovementGroup[]> encounteringGroups = new LinkedHashSet<>();
Set<SocialMovementGroup> alreadyProcessed = new LinkedHashSet<>();
if(enableGroupEncounters) {
Set<SocialMovementGroup> allGroups = groupCon.getGroups();
for(SocialMovementGroup group1 : allGroups) {
for(SocialMovementGroup group2 : allGroups) {
if(group1 != group2) {
if(!(alreadyProcessed.contains(group1) && alreadyProcessed.contains(group2))) {
if(getDistanceBetweenGroups(group1, group2) <= meetingDistance) {
SimLocationActuator g1Leader = group1.getLeader();
if(!groupCon.getHasMerged().get(g1Leader)) {
SocialMovementGroup[] groups = new SocialMovementGroup[2];
groups[0] = group1;
groups[1] = group2;
encounteringGroups.add(groups);
alreadyProcessed.add(group1);
alreadyProcessed.add(group2);
}
else {
if(waitedLongEnoughAfterMerging(g1Leader, groupCon.getWaitTime())) {
SocialMovementGroup[] groups = new SocialMovementGroup[2];
groups[0] = group1;
groups[1] = group2;
encounteringGroups.add(groups);
alreadyProcessed.add(group1);
alreadyProcessed.add(group2);
}
}
}
}
}
}
}
}
return encounteringGroups;
}
/**
* {@inheritDoc}
*/
public void handleEncounters(Set<SocialMovementGroup[]> encounteringGroups) {
if(encounteringGroups == null || encounteringGroups.isEmpty()) {
return;
}
for(SocialMovementGroup[] groups : encounteringGroups) {
handleGroupEncounter(groups[0], groups[1]);
}
}
/**
* Returns the distance between two groups based on their leaders position.
*
* @param SocialMovementGroup The first group.
* @param SocialMovementGroup The second group.
*
* @return Double Distance between group leaders of both groups.
*
* @author Marcel Verst
*/
public double getDistanceBetweenGroups(SocialMovementGroup group1, SocialMovementGroup group2) {
PositionVector l1Pos = group1.getLeaderPosition();
PositionVector l2Pos = group2.getLeaderPosition();
return l1Pos.distanceTo(l2Pos);
}
/**
* Compares the size of two groups and returns the larger group.
*
* @param SocialMovementGroup The first group.
* @param SocialMovementGroup The second group.
* @return GroupInstance The larger group, or the first group if both are the same size.
*
* @author Marcel Verst
*/
protected SocialMovementGroup getLargerGroup(SocialMovementGroup group1, SocialMovementGroup group2) {
if(group1.getGroupSize() >= group2.getGroupSize()) {
return group1;
}
else {
return group2;
}
}
/**
* Compares the size of two groups and returns the smaller group.
*
* @param SocialMovementGroup The first group.
* @param SocialMovementGroup The second group.
* @return GroupInstance The smaller group, or the second group if both are the same size.
*
* @author Marcel Verst
*/
protected SocialMovementGroup getSmallerGroup(SocialMovementGroup group1, SocialMovementGroup group2) {
if(group1.getGroupSize() < group2.getGroupSize()) {
return group1;
}
else {
return group2;
}
}
/**
* Returns true, if a host has waited long enough after its last merging process.
*
* @param SimLocationActuator The host to be checked.
* @param int The time a host has to wait until it can merge again.
* @return boolean
*
* @author Marcel Verst
*/
protected boolean waitedLongEnoughAfterMerging(SimLocationActuator host, long waitTime) {
return ((Time.getCurrentTime() - groupCon.getMergedAtTime().get(host)) >= waitTime);
}
public void setMeetingDistance(double meetingDistance) {
if (meetingDistance < 0) {
throw new ConfigurationException(
"AbstractGroupEncounter: Variable meetingDistance must be >= 0!");
}
this.meetingDistance = meetingDistance;
}
public void setEnableGroupEncounters(boolean enableGroupEncounters) {
this.enableGroupEncounters = enableGroupEncounters;
}
/**
* Removes both groups on encounter.
*
* @author Marcel Verst
*/
protected void dissolveGroups(SocialMovementGroup group1, SocialMovementGroup group2) {
groupCon.updateMergeVars(group1, group2);
if(groupCon.getGroups().contains(group1) && groupCon.getGroups().contains(group2)) {
groupCon.removeGroup(group1);
groupCon.removeGroup(group2);
}
}
/**
* Merges two groups together into one single group. The smaller group is merged into the larger group.
*
* @param SocialMovementGroup The first group.
* @param SocialMovementGroup The second group.
*
* @author Marcel Verst
*/
protected void mergeGroupsFully(SocialMovementGroup group1, SocialMovementGroup group2) {
groupCon.updateMergeVars(group1, group2);
SocialMovementGroup large = getLargerGroup(group1, group2);
SocialMovementGroup small = getSmallerGroup(group1, group2);
Set<SimLocationActuator> toRemove = new LinkedHashSet<>();
toRemove.addAll(small.getMembers());
for(SimLocationActuator participant : toRemove) {
small.removeHostFromGroup(participant);
groupCon.getLeftGroupAtTime().put(participant, Time.getCurrentTime());
large.addHostToGroup(participant);
}
groupCon.removeGroup(small);
}
/**
* Merges two groups partially. A specified number of hosts leaves the larger group and joins the smaller group.
*
* @param SocialMovementGroup The first group.
* @param SocialMovementGroup The second group.
*
* @author Marcel Verst
*/
protected void mergeGroupsPartially(SocialMovementGroup group1, SocialMovementGroup group2, int numberOfHostsToLeave) {
if(numberOfHostsToLeave <= 0)
return;
SocialMovementGroup large = getLargerGroup(group1, group2);
SocialMovementGroup small = getSmallerGroup(group1, group2);
if((large.getGroupSize() - numberOfHostsToLeave) >= groupCon.getMinGroupSize()) {
groupCon.updateMergeVars(group1, group2);
for(int i = 0; i < numberOfHostsToLeave; i++) {
SimLocationActuator randomParticipant = large.getRandomMember();
groupCon.getLeftGroupAtTime().put(randomParticipant, Time.getCurrentTime() );
large.removeHostFromGroup(randomParticipant);
small.addHostToGroup(randomParticipant);
groupCon.updateGroupEntry(small);
groupCon.updateGroupEntry(large);
}
}
}
}
/*
* 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.groups.groupencounter;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
/**
* This class checks if there is any pair of groups which encounter each other. Randomly decides
* if the groups dissolve or not after the encounter.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public class Dissolve extends AbstractGroupEncounter {
//--- VARIABLES TO BE DECLARED IN CONFIG ---
private double probabilityToDissolve;
//------------------------------------------
/**
* {@inheritDoc}
* Lets both groups dissolve with a certain probability in case they encounter.
*/
@Override
public void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2) {
if(rand.nextDouble() <= probabilityToDissolve) {
dissolveGroups(group1, group2);
}
}
public void setProbabilityToDissolve(double probabilityToDissolve) {
if (probabilityToDissolve < 0 || probabilityToDissolve > 1.0) {
throw new ConfigurationException(
"probabilityToDissolve should be between 0.0 and 1.0!");
}
this.probabilityToDissolve = probabilityToDissolve;
}
}
/*
* 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.groups.groupencounter;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
/**
* This class checks if there is any pair of groups which encounter each other. Randomly decides
* if the groups merge fully or not after the encounter.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public class Fully extends AbstractGroupEncounter {
//--- VARIABLES TO BE DECLARED IN CONFIG ---
private double probabilityToMergeFully;
//------------------------------------------
/**
* {@inheritDoc}
* Lets both groups merge fully with a certain probability in case they encounter.
*/
@Override
public void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2) {
if(rand.nextDouble() <= probabilityToMergeFully) {
mergeGroupsFully(group1, group2);
}
}
public void setProbabilityToMergeFully(double probabilityToMergeFully) {
if (probabilityToMergeFully < 0 || probabilityToMergeFully > 1.0) {
throw new ConfigurationException(
"probabilityToMergeFully should be between 0.0 and 1.0!");
}
this.probabilityToMergeFully = probabilityToMergeFully;
}
}
/*
* 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.groups.groupencounter;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.SocialGroupMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
/**
* This class checks if there is any pair of groups which encounter each other. Randomly decides
* if the groups merge fully, dissolve or do nothing after the encounter.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public class FullyDissolve extends AbstractGroupEncounter {
//--- VARIABLES TO BE DECLARED IN CONFIG ---
private double probabilityToMergeFully;
private double probabilityToDissolve;
//------------------------------------------
@Override
public void initialize(SocialGroupMovementModel movementModel) {
super.initialize(movementModel);
checkConfiguration();
}
/**
* {@inheritDoc}
* Applies dependent on probability values if the groups merge fully, dissolve or do nothing.
*/
@Override
public void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2) {
int decision = decide();
if(decision == DECISION_MERGE_FULL) {
mergeGroupsFully(group1, group2);
}
else if(decision == DECISION_DISSOLVE) {
dissolveGroups(group1, group2);
}
}
/**
* Decider to set the function which a leader should call if its group is in meeting range with another group.
*
* @return int
*/
private int decide() {
double decider = rand.nextDouble();
double maxMergeFully = probabilityToMergeFully;
double maxDissolve = probabilityToMergeFully + probabilityToDissolve;
// mergeFully
if(decider >= 0.0 && decider < maxMergeFully) {
return DECISION_MERGE_FULL;
}
// dissolve
else if(decider >= maxMergeFully && decider < maxDissolve) {
return DECISION_DISSOLVE;
}
else {
return DECISION_NONE;
}
}
public void setProbabilityToMergeFully(double probabilityToMergeFully) {
if (probabilityToMergeFully < 0 || probabilityToMergeFully > 1.0) {
throw new ConfigurationException(
"probabilityToMergeFully should be between 0.0 and 1.0!");
}
this.probabilityToMergeFully = probabilityToMergeFully;
}
public void setProbabilityToDissolve(double probabilityToDissolve) {
if (probabilityToDissolve < 0 || probabilityToDissolve > 1.0) {
throw new ConfigurationException(
"probabilityToDissolve should be between 0.0 and 1.0!");
}
this.probabilityToDissolve = probabilityToDissolve;
}
/**
* Checks for the correct configuration.
*
* @author Marcel Verst
*/
private void checkConfiguration() {
if(probabilityToMergeFully + probabilityToDissolve > 1.0) {
throw new ConfigurationException(
"FullyDissolve Group Encounter: probabilityToMergeFully + probabilityToDissolve must not exceed 1.0!");
}
}
}
/*
* 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.groups.groupencounter;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.SocialGroupMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
/**
* This class checks if there is any pair of groups which encounter each other. Randomly decides
* if the groups merge fully, partially or do nothing after the encounter.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public class FullyPartially extends AbstractGroupEncounter {
//--- VARIABLES TO BE DECLARED IN CONFIG ---
private double probabilityToMergeFully;
private double probabilityToMergePartially;
private int numberOfHostsToLeave;
//------------------------------------------
@Override
public void initialize(SocialGroupMovementModel movementModel) {
super.initialize(movementModel);
checkConfiguration();
}
/**
* {@inheritDoc}
* Applies dependent on probability values if the groups merge fully, merge partially or do nothing.
*/
@Override
public void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2) {
int decision = decide();
if(decision == DECISION_MERGE_FULL) {
mergeGroupsFully(group1, group2);
}
else if(decision == DECISION_MERGE_PARTIAL) {
mergeGroupsPartially(group1, group2, numberOfHostsToLeave);
}
}
/**
* Decider to set the function which a leader should call if its group is in meeting range with another group.
*
* @return int
*/
private int decide() {
double decider = rand.nextDouble();
double maxMergeFully = probabilityToMergeFully;
double maxMergePartially = probabilityToMergeFully + probabilityToMergePartially;
// mergeFully
if(decider >= 0.0 && decider < maxMergeFully) {
return DECISION_MERGE_FULL;
}
// mergePartially
else if(decider >= maxMergeFully && decider < maxMergePartially) {
return DECISION_MERGE_PARTIAL;
}
else
return DECISION_NONE;
}
public void setProbabilityToMergeFully(double probabilityToMergeFully) {
if (probabilityToMergeFully < 0 || probabilityToMergeFully > 1.0) {
throw new ConfigurationException(
"probabilityToMergeFully should be between 0.0 and 1.0!");
}
this.probabilityToMergeFully = probabilityToMergeFully;
}
public void setProbabilityToMergePartially(double probabilityToMergePartially) {
if (probabilityToMergePartially < 0 || probabilityToMergePartially > 1.0) {
throw new ConfigurationException(
"probabilityToMergePartially should be between 0.0 and 1.0!");
}
this.probabilityToMergePartially = probabilityToMergePartially;
}
public void setNumberOfHostsToLeave(int numberOfHostsToLeave) {
if (numberOfHostsToLeave < 0) {
throw new ConfigurationException(
"numberOfHostsToLeave should be greater or equal than 0!");
}
this.numberOfHostsToLeave = numberOfHostsToLeave;
}
/**
* Checks for the correct configuration.
*
* @author Marcel Verst
*/
private void checkConfiguration() {
if(probabilityToMergeFully + probabilityToMergePartially > 1.0) {
throw new ConfigurationException(
"probabilityToMergeFully + probabilityToMergePartially should not exceed 1.0!");
}
}
}
/*
* 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.groups.groupencounter;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.SocialGroupMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
/**
* This class checks if there is any pair of groups which encounter each other. Randomly decides
* if the groups merge fully, merge partially, dissolve or do nothing after the encounter.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public class FullyPartiallyDissolve extends AbstractGroupEncounter {
//--- VARIABLES TO BE DECLARED IN CONFIG ---
private double probabilityToMergeFully;
private double probabilityToMergePartially;
private double probabilityToDissolve;
private int numberOfHostsToLeave;
//------------------------------------------
@Override
public void initialize(SocialGroupMovementModel movementModel) {
super.initialize(movementModel);
checkConfiguration();
}
/**
* {@inheritDoc}
* Applies dependent on probability values if the groups merge fully, merge partially, dissolve or do nothing.
*/
@Override
public void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2) {
int decision = decide();
if(decision == DECISION_MERGE_FULL) {
mergeGroupsFully(group1, group2);
}
else if(decision == DECISION_MERGE_PARTIAL) {
mergeGroupsPartially(group1, group2, numberOfHostsToLeave);
}
else if(decision == DECISION_DISSOLVE) {
dissolveGroups(group1, group2);
}
}
/**
* Decider to set the function which a leader should call if its group is in meeting range with another group.
*
* @return int
*/
private int decide() {
double decider = rand.nextDouble();
double maxMergeFully = probabilityToMergeFully;
double maxMergePartially = probabilityToMergeFully + probabilityToMergePartially;
double maxDissolve = probabilityToMergeFully + probabilityToMergePartially + probabilityToDissolve;
// mergeFully
if(decider >= 0.0 && decider < maxMergeFully) {
return DECISION_MERGE_FULL;
}
// mergePartially
else if(decider >= maxMergeFully && decider < maxMergePartially) {
return DECISION_MERGE_PARTIAL;
}
// dissolve
else if(decider >= maxMergePartially && decider <= maxDissolve) {
return DECISION_DISSOLVE;
}
else
return DECISION_NONE;
}
public void setProbabilityToMergeFully(double probabilityToMergeFully) {
if (probabilityToMergeFully < 0 || probabilityToMergeFully > 1.0) {
throw new ConfigurationException(
"probabilityToMergeFully should be between 0.0 and 1.0!");
}
this.probabilityToMergeFully = probabilityToMergeFully;
}
public void setProbabilityToMergePartially(double probabilityToMergePartially) {
if (probabilityToMergePartially < 0 || probabilityToMergePartially > 1.0) {
throw new ConfigurationException(
"probabilityToMergePartially should be between 0.0 and 1.0!");
}
this.probabilityToMergePartially = probabilityToMergePartially;
}
public void setProbabilityToDissolve(double probabilityToDissolve) {
if (probabilityToDissolve < 0 || probabilityToDissolve > 1.0) {
throw new ConfigurationException(
"probabilityToDissolve should be between 0.0 and 1.0!");
}
this.probabilityToDissolve = probabilityToDissolve;
}
public void setNumberOfHostsToLeave(int numberOfHostsToLeave) {
if (numberOfHostsToLeave < 0) {
throw new ConfigurationException(
"numberOfHostsToLeave should be greater or equal than 0!");
}
this.numberOfHostsToLeave = numberOfHostsToLeave;
}
/**
* Checks for the correct configuration.
*
* @author Marcel Verst
*/
private void checkConfiguration() {
if(probabilityToMergeFully + probabilityToMergePartially + probabilityToDissolve > 1.0) {
throw new ConfigurationException(
"probabilityToMergeFully + probabilityToMergePartially + probabilityToDissolve should not exceed 1.0!");
}
}
}
/*
* 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.groups.groupencounter;
import java.util.Set;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.SocialGroupMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
/**
* Handles group encounters. Check group encounters based on the leaders location of {@link SocialMovementGroup}s.
* Encounter takes part if the position between two leaders falls below a specified threshold.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public interface IGroupEncounterBehavior {
/**
* Initializes class variables.
*
* @author Marcel Verst
*/
void initialize(SocialGroupMovementModel movementModel);
/**
* Checks if any of the current groups come in a close range which is equivalent to a group meeting.
* Calls the handleGroupEncounters(Group, Group) method to define the group behavior.
*
* @author Marcel Verst
* @return
*/
Set<SocialMovementGroup[]> getEncounteringGroups();
/**
* Applies an encountering action to each detected encountering groups.
*
* @param Set<Group[]> The set of encountering groups.
*
* @author Marcel Verst
*/
void handleEncounters(Set<SocialMovementGroup[]> encounteringGroups);
/**
* Defines what to do with both groups in case they encountered.
*
* @param SocialMovementGroup The first group.
* @param SocialMovementGroup The second group.
*
* @author Marcel Verst
*/
void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2);
}
\ No newline at end of file
/*
* 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.groups.groupencounter;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
/**
* This class checks if there is any pair of groups which encounter each other. Randomly decides
* if the groups merge partially or not after the encounter.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public class Partially extends AbstractGroupEncounter {
//--- VARIABLES TO BE DECLARED IN CONFIG ---
private double probabilityToMergePartially;
private int numberOfHostsToLeave;
//------------------------------------------
/**
*
* Lets both groups merge partially with a certain probability in case they encounter.
*/
@Override
public void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2) {
if(rand.nextDouble() <= probabilityToMergePartially) {
mergeGroupsPartially(group1, group2, numberOfHostsToLeave);
}
}
public void setProbabilityToMergePartially(double probabilityToMergePartially) {
if (probabilityToMergePartially < 0 || probabilityToMergePartially > 1.0) {
throw new ConfigurationException(
"probabilityToMergePartially should be between 0.0 and 1.0!");
}
this.probabilityToMergePartially = probabilityToMergePartially;
}
public void setNumberOfHostsToLeave(int numberOfHostsToLeave) {
if (numberOfHostsToLeave < 0) {
throw new ConfigurationException(
"numberOfHostsToLeave should be greater or equal than 0!");
}
this.numberOfHostsToLeave = numberOfHostsToLeave;
}
}
/*
* 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.groups.groupencounter;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.ModularMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.SocialGroupMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
/**
* This class checks if there is any pair of groups which encounter each other. Randomly decides
* if the groups merge partially, dissolve or do nothing after the encounter.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public class PartiallyDissolve extends AbstractGroupEncounter {
//--- VARIABLES TO BE DECLARED IN CONFIG ---
private double probabilityToMergePartially;
private double probabilityToDissolve;
private int numberOfHostsToLeave;
//------------------------------------------
@Override
public void initialize(SocialGroupMovementModel movementModel) {
super.initialize(movementModel);
checkConfiguration();
}
/**
* {@inheritDoc}
* Applies dependent on probability values if the groups merge partially, dissolve or do nothing.
*/
@Override
public void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2) {
int decision = decide();
if(decision == DECISION_MERGE_PARTIAL) {
mergeGroupsPartially(group1, group2, numberOfHostsToLeave);
}
else if(decision == DECISION_DISSOLVE) {
dissolveGroups(group1, group2);
}
}
/**
* Decider to set the function which a leader should call if its group is in meeting range with another group.
*
* @return int
*/
private int decide() {
double decider = rand.nextDouble();
double maxMergePartially = probabilityToMergePartially;
double maxDissolve = probabilityToMergePartially + probabilityToDissolve;
// mergePartially
if(decider >= 0.0 && decider < maxMergePartially) {
return DECISION_MERGE_PARTIAL;
}
// dissolve
else if(decider >= maxMergePartially && decider < maxDissolve) {
return DECISION_DISSOLVE;
}
else
return DECISION_NONE;
}
public void setProbabilityToMergePartially(double probabilityToMergePartially) {
if (probabilityToMergePartially < 0 || probabilityToMergePartially > 1.0) {
throw new ConfigurationException(
"probabilityToMergePartially should be between 0.0 and 1.0!");
}
this.probabilityToMergePartially = probabilityToMergePartially;
}
public void setProbabilityToDissolve(double probabilityToDissolve) {
if (probabilityToDissolve < 0 || probabilityToDissolve > 1.0) {
throw new ConfigurationException(
"probabilityToDissolve should be between 0.0 and 1.0!");
}
this.probabilityToDissolve = probabilityToDissolve;
}
public void setNumberOfHostsToLeave(int numberOfHostsToLeave) {
if (numberOfHostsToLeave < 0) {
throw new ConfigurationException(
"numberOfHostsToLeave should be greater or equal than 0!");
}
this.numberOfHostsToLeave = numberOfHostsToLeave;
}
/**
* Checks for the correct configuration.
*
* @author Marcel Verst
*/
private void checkConfiguration() {
if(probabilityToMergePartially + probabilityToDissolve > 1.0) {
throw new ConfigurationException(
"probabilityToMergePartially + probabilityToDissolve should not exceed 1.0!");
}
}
}
/*
* 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.groups.groupencounter;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
import de.tud.kom.p2psim.impl.util.Tuple;
import de.tudarmstadt.maki.simonstrator.api.Time;
/**
* This class checks if there is any pair of groups which encounter each other. Randomly decides
* if the groups wait for a specified of time during encounter or not.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public class Wait extends AbstractGroupEncounter{
//--- VARIABLES TO BE DECLARED IN CONFIG ---
private double probabilityToWait;
private long timeToWait;
//------------------------------------------
@Override
public void handleGroupEncounter(SocialMovementGroup group1, SocialMovementGroup group2) {
if(rand.nextDouble() <= probabilityToWait) {
wait(group1, group2);
}
}
/**
* Assigns two groups the role to wait for a specified amount of time. After waiting for this time,
* the groups are released from the waiting role and can continue their trip.
*
* @param SocialMovementGroup The first group.
* @param SocialMovementGroup The second group.
*
* @author Marcel Verst
*/
private void wait(SocialMovementGroup group1, SocialMovementGroup group2) {
// Do not apply waiting process if one of both groups is already waiting
if(groupCon.waitingGroups.containsKey(group1) && !groupCon.waitingGroups.containsKey(group2)) {
return;
}
if(!groupCon.waitingGroups.containsKey(group1) && groupCon.waitingGroups.containsKey(group2)) {
return;
}
// If both groups are not waiting, declare them as waiting groups for a duration of timeToWait
if(!groupCon.waitingGroups.containsKey(group1) && !groupCon.waitingGroups.containsKey(group2)) {
groupCon.waitingGroups.put(group1, new Tuple<Long, Long>(timeToWait, Time.getCurrentTime()));
groupCon.waitingGroups.put(group2, new Tuple<Long, Long>(timeToWait, Time.getCurrentTime()));
}
// If both groups are already waiting
if(groupCon.waitingGroups.containsKey(group1) && groupCon.waitingGroups.containsKey(group2)) {
long timerGroup1 = groupCon.waitingGroups.get(group1).getA();
long timerGroup2 = groupCon.waitingGroups.get(group2).getA();
// Remove groups if they have waited long enough
if(timerGroup1 <= 0 && timerGroup2 <= 0) {
groupCon.updateMergeVars(group1, group2);
groupCon.waitingGroups.remove(group1);
groupCon.waitingGroups.remove(group2);
}
// Decrement timer of both groups if they have to wait more
else {
long deltaGroup1 = Time.getCurrentTime() - groupCon.waitingGroups.get(group1).getB();
groupCon.waitingGroups.put(group1, new Tuple<Long, Long>(timerGroup1 - deltaGroup1, Time.getCurrentTime()));
long deltaGroup2 = Time.getCurrentTime() - groupCon.waitingGroups.get(group2).getB();
groupCon.waitingGroups.put(group2, new Tuple<Long, Long>(timerGroup2 - deltaGroup2, Time.getCurrentTime()));
}
}
}
/*
* GETTERS AND SETTERS
*/
public void setProbabilityToWait(double probabilityToWait) {
if (probabilityToWait < 0 || probabilityToWait > 1.0) {
throw new ConfigurationException(
"probabilityToWait should be between 0.0 and 1.0!");
}
this.probabilityToWait = probabilityToWait;
}
public void setTimeToWait(long timeToWait) {
if(timeToWait < 0) {
throw new ConfigurationException(
"timeToWait should be greater or equal than 0!");
}
this.timeToWait = timeToWait;
}
}
/*
* 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.groups.groupforming;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import de.tud.kom.p2psim.api.topology.movement.SimLocationActuator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.SocialGroupMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.BasicAttractionPoint;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionGenerator;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.hostcount.IAttractionPointHostCounter;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.SocialMovementGroup;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.groups.MovementGroupContainer;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.transition.ITransitionStrategy;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.util.Tuple;
import de.tudarmstadt.maki.simonstrator.api.Randoms;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
/**
* Abstract class implementation for implementing GroupFormingStrategies.
*
* @author Marcel Verst
* @version 1.0, 22.11.2018
*/
public abstract class AbstractGroupForming implements IGroupFormingBehavior {
protected Random rand = Randoms.getRandom(AbstractGroupForming.class);
protected SocialGroupMovementModel movementModel;
protected MovementGroupContainer groupCon;
// Holds time information of nodes for the groups (stay duration, last update)
protected Map<INodeID, Tuple<Long,Long>> stayDuration;
// GROUP VARIABLES FROM CONFIGS
protected boolean enableGroups;
protected int minGroupSize;
protected int maxGroupSize;
protected double probabilityToJoin;
protected int maxNumberOfGroups;
protected long waitTime;
protected long setupTime;
protected IAttractionPointHostCounter hostCounter;
/**
* Creates a group with the given set of participants.
*
* @param Set<SimLocationActuator> The participants which want to form a group.
*
* @author Marcel Verst
*/
public void createGroup(Set<SimLocationActuator> candidates) {
SocialMovementGroup group = new SocialMovementGroup(candidates);
// Guarantee that the new destination of a group is not equal to the current AttractionPoint where the group is created
// This would be the case if the destination of the group leader is the current position of the group.
AttractionPoint leaderTarget = group.getLeader().getCurrentTargetAttractionPoint();
AttractionPoint poiDestination = null;
do {
poiDestination = getRandomAttractionPoint();
} while(poiDestination == leaderTarget);
// Add Offset to destination
PositionVector destination = new PositionVector(poiDestination.getLongitudeOrX(), poiDestination.getLatitudeOrY());
double apRadius = poiDestination.getRadius();
PositionVector offset = new PositionVector(rand.nextDouble() * apRadius / 3, rand.nextDouble() * apRadius / 3);
destination.plus(offset);
group.setDestination(destination);
setMP(group);
for(SimLocationActuator member : group.getMembers()) {
member.setTargetAttractionPoint(poiDestination);
groupCon.addHasBeenInGroupEntry(member, true);
if(groupCon.getLeftGroupAtTime().containsKey(member)) {
// System.out.println(groupCon.getLeftGroupAtTime().get(member));
groupCon.removeLeftGroupAtTimeEntry(member);
}
}
groupCon.addGroup(group);
}
/**
* Returns a random {@link AttractionPoint} out of the set of all AttractionPoints
*
* @return AttractionPoint
*
* @author Marcel Verst
*/
protected AttractionPoint getRandomAttractionPoint() {
int item = rand.nextInt(IAttractionGenerator.attractionPoints.size());
return IAttractionGenerator.attractionPoints.get(item);
}
/**
* Removes a group.
*
* @param SocialMovementGroup The group to be removed.
*
* @author Marcel Verst
*/
public void removeGroup(SocialMovementGroup group) {
groupCon.removeGroup(group);
}
/**
* Returns the first AttractionPoint which contains the host with the greatest stayDuration of all hosts located in AttractionPoints.
*
* @return AttractionPoint
*
* @author Marcel Verst, Julian Zobel
*/
protected AttractionPoint getAttractionPointWithOldestHost() {
AttractionPoint result = null;
long maxDuration = 0;
for(AttractionPoint ap : IAttractionGenerator.attractionPoints) {
for(SimLocationActuator host : hostCounter.getHostsOfAttractionPoint(ap)) {
INodeID id = host.getHost().getId();
long duration = stayDuration.get(id).getA();
if(duration > maxDuration) {
result = ap;
maxDuration = duration;
}
}
}
return result;
}
/**
* Returns an Array of SimLocationActuators sorted in ascending order of stayDuration values.
*
* @param Set<SimLocationActuator> The candidates to sort.
* @return SimLocationActuator[]
*
* @author Marcel Verst
*/
public SimLocationActuator[] getHostsSortedByStayDurationAscending(Set<SimLocationActuator> candidates) {
int size = candidates.size();
SimLocationActuator[] youngestHostsSorted = new SimLocationActuator[size];
for(int i = 0; i < size; i++) {
long largestDuration = Integer.MAX_VALUE;
SimLocationActuator youngesHost = null;
for(SimLocationActuator candidate : candidates) {
INodeID id = candidate.getHost().getId();
long duration = stayDuration.get(id).getA();
if(duration <= largestDuration) {
largestDuration = duration;
youngesHost = candidate;
}
}
youngestHostsSorted[i] = youngesHost;
candidates.remove(youngesHost);
}
return youngestHostsSorted;
}
/**
* Returns an Array of SimLocationActuators sorted in descending order of stayDuration values.
*
* @param Set<SimLocationActuator> The candidates to sort.
* @return SimLocationActuator[]
*
* @author Marcel Verst
*/
public SimLocationActuator[] getHostsSortedByStayDurationDescending(Set<SimLocationActuator> candidates) {
int size = candidates.size();
SimLocationActuator[] oldestHostsSorted = new SimLocationActuator[size];
for(int i = 0; i < size; i++) {
long largestDuration = 0;
SimLocationActuator oldestHost = null;
for(SimLocationActuator candidate : candidates) {
if(!groupCon.isGroupMember(candidate)) {
INodeID id = candidate.getHost().getId();
long duration = stayDuration.get(id).getA();
if(duration >= largestDuration) {
largestDuration = duration;
oldestHost = candidate;
}
}
}
if(oldestHost != null) {
oldestHostsSorted[i] = oldestHost;
}
candidates.remove(oldestHost);
}
return oldestHostsSorted;
}
protected AttractionPoint getAttractionPointWithMostHosts() {
AttractionPoint apCandidate = null;
int size = 0;
for(AttractionPoint ap : IAttractionGenerator.attractionPoints) {
int numberOfHostsInAP = hostCounter.getHostCountOfAttractionPoint(ap);
if(numberOfHostsInAP > size) {
apCandidate = ap;
size = numberOfHostsInAP;
}
}
return apCandidate;
}
/**
* Checks for a set of candidates which candidate is able to join a group. Returns a subset of group candidates which
* are able to form a group with other candidates.
*
* @param Set<SimLocationActuator> Set of candidates.
* @return Set<SimLocationActuator> Set of group candidates.
*
* @author Marcel Verst
*/
public Set<SimLocationActuator> getGroupCandidates(Set<SimLocationActuator> candidates){
Set<SimLocationActuator> groupCandidates = new LinkedHashSet<>();
for(SimLocationActuator candidate : candidates) {
// Candidate can only be a group candidate if he is not yet in a group
if(!groupCon.isGroupMember(candidate)){
// Further check if the candidate even wants to join (based on probability)
if(wantsToJoin()) {
/*
* Candidate is not in a group yet and wants to be in a group:
* Check if the candidate has been in a group before.
*/
// If not, add the candidate to the set of group candidates.
if(!beenInGroup(candidate)) {
groupCandidates.add(candidate);
}
// Host has already been in a group. Check if the host has waited long enough to join another group.
else {
if(waitedLongEnough(candidate, Time.getCurrentTime() / 1000000)) {
groupCandidates.add(candidate);
}
}
}
else {
/*
* The host does not want to join. This decision is counted as an action which has the impact,
* that the host can not perform any other action until he waited for a specified amount of time.
* This procedure ensures that the host is not asked again every second if he wants to join a group.
*/
groupCon.addHasBeenInGroupEntry(candidate, true);
groupCon.addLeftGroupAtTimeEntry(candidate, Time.getCurrentTime() / 1000000);
}
}
}
return groupCandidates;
}
/**
* Checks if a host wants to join a group or not based on a given probability.
* Returns true if willing to join, false else.
*
* @return boolean
*
* @author Marcel Verst
*/
protected boolean wantsToJoin() {
return (rand.nextDouble() <= probabilityToJoin);
}
/**
* Checks if a host has waited long enough before he is allowed to join groups again.
* Returns true, if the host has waited long enough, false else.
*
* @param SimLocationActuator The host to be checked.
* @param int The current time.
* @return boolean
*
* @author Marcel Verst
*/
protected boolean waitedLongEnough(SimLocationActuator host, long time) {
return (getWaitingTime(host, time) >= waitTime);
}
/**
* Returns the time a host has waited since he left a group the last time.
*
* @param SimLocacationActuator The host to be checked.
* @param Long The current time.
* @return Long
*
* @author Marcel Verst
*/
private long getWaitingTime(SimLocationActuator host, long currentTime) {
return currentTime - groupCon.getLeftGroupAtTime().get(host);
}
/**
* Returns true, if a host has been in a group before at least once. False else.
*
* @param SimLocacationActuator The host to be checked.
* @return Boolean
*
* @author Marcel Verst
*/
protected boolean beenInGroup(SimLocationActuator host) {
if(!groupCon.getHasBeenInAGroup().containsKey(host)) {
groupCon.addHasBeenInGroupEntry(host, false);
}
return groupCon.getHasBeenInAGroup().get(host);
}
/*
* =====================================================================================================
* === MEETING POINT FUNCTIONS
* =====================================================================================================
*/
/**
* Sets the meeting point of a group after the group has been created. Before walking towards the destination,
* the group members first have to meet at the meeting point.
*
* @param SocialMovementGroup The group to set the meeting point.
*
* @author Marcel Verst, Julian Zobel
*/
public void setMP(SocialMovementGroup group) {
PositionVector leaderPos = group.getLeader().getRealPosition();
BasicAttractionPoint meetingPoint = new BasicAttractionPoint("Group Movement Meeting Point of Leader #"+group.getLeader().getHost().getId(), leaderPos);
group.setMeetingPoint(meetingPoint);
// Update target for all group members to meeting point
for(SimLocationActuator participant : group.getMembers()) {
ITransitionStrategy transition = movementModel.getTransition();
transition.updateTargetAttractionPoint(participant, meetingPoint);
}
}
}
/*
* 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.groups.groupforming;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import de.tud.kom.p2psim.api.scenario.ConfigurationException;
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.SocialGroupMovementModel;
import de.tud.kom.p2psim.impl.topology.movement.modularosm.attraction.IAttractionGenerator;
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.transition.ITransitionStrategy;
import de.tud.kom.p2psim.impl.topology.util.PositionVector;
import de.tud.kom.p2psim.impl.util.Either;
import de.tud.kom.p2psim.impl.util.Tuple;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Oracle;
import de.tudarmstadt.maki.simonstrator.api.Time;
import de.tudarmstadt.maki.simonstrator.api.common.graph.INodeID;
import de.tudarmstadt.maki.simonstrator.api.component.ComponentNotAvailableException;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.AttractionPoint;
import de.tudarmstadt.maki.simonstrator.api.component.sensor.location.Location;
/**
* This class is responsible for creating or deleting groups. Therefore the amount of hosts in each POI
* is checked and from this set of hosts candidates are chosen which then form a group.
* Deletion of groups happens only in the case when they reached their group leaders destination.
*
* @author Marcel Verst
* @version 1.0, 09.11.2018
*
*
* Updated the group forming to use the simulation time units instead of integer +1 counters.
*
* @author Julian Zobel
*
*/
public class DefaultGroupForming extends AbstractGroupForming {
private Map<SimLocationActuator, AttractionPoint> lastAPs;
private int nextGroupSize;
public void initialize(SocialGroupMovementModel movementModel) {
this.movementModel = movementModel;
nextGroupSize = nextGroupSize();
lastAPs = new LinkedHashMap<>();
groupCon = MovementGroupContainer.getInstance();
groupCon.setWaitTime(waitTime);
groupCon.setMinGroupSize(minGroupSize);
groupCon.setMaxGroupSize(maxGroupSize);
// Initialize instances of other classes
this.hostCounter = movementModel.getAttractionPointHostCounter();
stayDuration = new LinkedHashMap<INodeID, Tuple<Long,Long>>();
for(SimLocationActuator host : movementModel.getAllLocationActuators()) {
groupCon.addHasBeenInGroupEntry(host, false);
lastAPs.put(host, host.getCurrentTargetAttractionPoint());
stayDuration.put(host.getHost().getId(), new Tuple<Long, Long>(0L, Time.getCurrentTime()));
}
}
/*
* =====================================================================================================
* === GROUP HANDLING
* =====================================================================================================
*/
/**
* {@inheritDoc}
*/
public void manageGroups() {
long currentTime = Time.getCurrentTime();
if(enableGroups && (currentTime >= setupTime) && probabilityToJoin > 0.0) {
runGroupBuildingProcess();
runGroupDeletionProcess();
}
}
/*
* =====================================================================================================
* === GROUP BUILDING PROCESS
* =====================================================================================================
*/
/**
* {@inheritDoc}
*/
public void runGroupBuildingProcess() {
updateStayDuration();
int groupsToCreate = maxNumberOfGroups - groupCon.getGroups().size();
for(int i = 0; i < groupsToCreate; i++) {
// Get attractionPoint with highest amount of hosts
hostCounter.updateHostCount();
AttractionPoint apCandidate = getAttractionPointWithOldestHost();
if(apCandidate == null) {
break;
}
int numberOfHostsInAttractionPoint = hostCounter.getHostCountOfAttractionPoint(apCandidate);
// Adapt nextGroupSize to AP conditions
while(numberOfHostsInAttractionPoint < nextGroupSize && nextGroupSize >= 2) {
nextGroupSize--;
}
if(numberOfHostsInAttractionPoint >= nextGroupSize) {
Set<SimLocationActuator> hostsOfPoi = hostCounter.getHostsOfAttractionPoint(apCandidate);
SimLocationActuator[] hostsSorted = getHostsSortedByStayDurationDescending(hostsOfPoi);
Set<SimLocationActuator> groupCandidates = new LinkedHashSet<>();
if(hostsSorted.length > 0) {
for(int tmp = 0; tmp <= nextGroupSize; tmp++) {
for(int index = 0; index < hostsSorted.length; index++) {
SimLocationActuator hostToAdd = hostsSorted[index];
if(hostToAdd != null) {
if(!groupCandidates.contains(hostToAdd)) {
if(!movementModel.getSingleHosts().contains(hostToAdd)) {
if(wantsToJoin()) {
if(!beenInGroup(hostToAdd)) {
groupCandidates.add(hostToAdd);
break;
}
// Host has already been in a group. Check if the host has waited long enough to join another group.
else {
if(waitedLongEnough(hostToAdd, Time.getCurrentTime())) {
groupCandidates.add(hostToAdd);
break;
}
}
}
else {
/*
* The host does not want to join. This decision is counted as an action which has the impact,
* that the host can not perform any other action until he waited for a specified amount of time.
* This procedure ensures that the host is not asked again every second if he wants to join a group.
*/
groupCon.addHasBeenInGroupEntry(hostToAdd, true);
groupCon.addLeftGroupAtTimeEntry(hostToAdd, Time.getCurrentTime());
}
}
}
}
}
}
}
if(groupCandidates.isEmpty() || groupCandidates == null) {
break;
}
while(groupCandidates.size() < nextGroupSize && nextGroupSize >= 2) {
nextGroupSize--;
}
if(groupCandidates.size() >= nextGroupSize) {
for(SimLocationActuator candidate : groupCandidates) {
INodeID id = candidate.getHost().getId();
stayDuration.put(id, new Tuple<Long, Long>(0L, Time.getCurrentTime()));
}
createGroup(groupCandidates);
nextGroupSize = nextGroupSize();
}
}
}
}
/*
* =====================================================================================================
* === GROUP DELETION PROCESS
* =====================================================================================================
*/
public void runGroupDeletionProcess() {
LocalMovementStrategy movementStrategy = movementModel.getMovementStrategy();
ITransitionStrategy transition = movementModel.getTransition();
Set<SocialMovementGroup> groupsToRemove = new LinkedHashSet<>();
Set<SocialMovementGroup> groups = groupCon.getGroups();
for(SocialMovementGroup group : groups) {
SimLocationActuator leader = group.getLeader();
PositionVector target = movementModel.getCurrentTargets().get(leader);
Either<PositionVector, Boolean> either = movementStrategy.nextPosition(leader, target);
if (either.hasLeft()) {
// Do nothing
} else {
transition.reachedAttractionPoint(leader, leader.getCurrentTargetAttractionPoint());
groupsToRemove.add(group);
}
}
for(SocialMovementGroup group : groupsToRemove) {
removeGroup(group);
}
}
/*
* =====================================================================================================
* === HELPER FUNCTIONS
* =====================================================================================================
*/
/**
* Updates the stayDuration of each Host
*/
public void updateStayDuration() {
for(Host host : Oracle.getAllHosts()) {
try {
SimLocationActuator component = host.getComponent(SimLocationActuator.class);
INodeID id = component.getHost().getId();
// Check if host is in an AP area
boolean isInAp = false;
for(AttractionPoint ap : IAttractionGenerator.attractionPoints) {
Location hostLocation = component.getLastLocation();
if(ap.distanceTo(hostLocation) <= ap.getRadius()) {
isInAp = true;
}
}
// In AP, increase stayDuration
if(isInAp) {
Tuple<Long, Long> timeInfo = stayDuration.get(id);
long delta = Time.getCurrentTime() - timeInfo.getB();
// update information (increase overall stay duration and set current time as update time)
stayDuration.put(id, new Tuple<Long, Long>(timeInfo.getA() + delta, Time.getCurrentTime()));
}
// Not in AP, reset stayDuration
else {
stayDuration.put(id, new Tuple<Long, Long>(0L, Time.getCurrentTime()));
}
} catch (ComponentNotAvailableException e) {
e.printStackTrace();
}
}
}
/*
private Set<SimLocationActuator> getRandomSubSet(Set<SimLocationActuator> candidates){
Set<SimLocationActuator> candidatesSubSet = new LinkedHashSet<>();
for(int i = 0; i < nextGroupSize; i++) {
SimLocationActuator randomCandidate = getRandomCandidate(candidates);
candidatesSubSet.add(randomCandidate);
}
return candidatesSubSet;
}
*/
/*
private SimLocationActuator getRandomCandidate(Set<SimLocationActuator> candidates) {
int size = candidates.size();
int item = rand.nextInt(size-1);
int i = 0;
SimLocationActuator actuator = null;
for(SimLocationActuator host : candidates) {
if(i == item) {
actuator = host;
}
i++;
}
candidates.remove(actuator);
return actuator;
}
*/
/**
* Returns the next randomly generated number of Hosts required to form a group.
*
* @return Integer
*
* @author Marcel Verst
*/
private int nextGroupSize() {
int nextGroupSize = rand.nextInt(maxGroupSize+1);
if(nextGroupSize < minGroupSize) {
nextGroupSize = minGroupSize;
}
return nextGroupSize;
}
/*
* =====================================================================================================
* === GETTERS AND SETTERS
* =====================================================================================================
*/
public void setEnableGroups(boolean enableGroups) {
this.enableGroups = enableGroups;
}
public void setMinGroupSize(int minGroupSize) {
if (minGroupSize < 0) {
throw new ConfigurationException(
"minGroupSize should be greater or equal than 3!");
}
this.minGroupSize = minGroupSize;
}
public void setMaxGroupSize(int maxGroupSize) {
if (maxGroupSize < 0) {
throw new ConfigurationException(
"maxGroupSize should be greater or equal than 3!");
}
this.maxGroupSize = maxGroupSize;
}
public void setMaxNumberOfGroups(int maxNumberOfGroups) {
if (maxNumberOfGroups < 0) {
throw new ConfigurationException(
"maxNumberOfGroups should be greater or equal than 0!");
}
this.maxNumberOfGroups = maxNumberOfGroups;
}
public void setProbabilityToJoin(double probabilityToJoin) {
if (probabilityToJoin < 0 || probabilityToJoin > 1.0) {
throw new ConfigurationException(
"probabilityToJoin should be between 0.0 and 1.0!");
}
this.probabilityToJoin = probabilityToJoin;
}
public void setWaitTime(long waitTime) {
if (waitTime < 0) {
throw new ConfigurationException(
"waitTime should be greater or equal than 0!");
}
this.waitTime = waitTime;
}
public void setSetupTime(long setupTime) {
if (setupTime < 0) {
throw new ConfigurationException(
"setupTime should be greater or equal than 0!");
}
this.setupTime = setupTime;
}
public double getProbabilityToJoin() {
return probabilityToJoin;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment