Hi everyone i've produced an agent based model. The agents can move randomly and use the A* algorithm to move to places to places. There are two main collections 1) arrival Queue (arraylist) and the 2) main agents (arraylist). All the agents are initially placed into the arrival queue, agents are placed into the simulation at certain time intervals e.g. 100 agents per 400 simulation steps).
The issue im getting is every time I increase the population of agents from 3000+ the simulation begins to lag. Also im using the Java 2D libraries for visualizing the 2D array of agents. Bellow ive added a screenshot of the the visualVM of my application is shows the methods which are being called the most (CPU time).
Model code:
package Model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import Model.Grid;
import Agent.*;
public class Model extends AbstractModel implements Runnable{
private Grid grid;
private Constants modelConstants;
private RandomGenerator randGenerator;
private GridMapLayout Maplayout;
private RoomController roomController;
private AgentFactory agentFacory;
private Statistics stats;
private ArrayList<AbstractAgent> agents;
private Queue<Patient> patientArrivalQueue;
private List<Patient> dischargedPatients;
private Queue<Doctor> doctorsQueue;
private Queue<Nurse> nursesQueue;
private int patientPopulation;
private int doctorPopulation;
private int receptionNurses;
private int aNeNurses;
private int ward1Nurses;
private int ward2Nurses;
private int ward3Nurses;
private boolean running;
private int currentSimCycle;
private int simArrivalCounter;
public CTimer timer = new CTimer();
public Model() {
super();
this.grid = new Grid(150, 150); //if no given size grid uses default size
this.modelConstants = new Constants();
this.randGenerator = new RandomGenerator(modelConstants.getSEED());
this.Maplayout = new GridMapLayout(this);
this.roomController = new RoomController(this);
this.agentFacory = new AgentFactory(this);
this.stats = new Statistics(this);
this.currentSimCycle = 0;
this.simArrivalCounter = 0;
this.agents = new ArrayList<AbstractAgent>();
this.patientArrivalQueue = new LinkedList<Patient>();
this.dischargedPatients = new LinkedList<Patient>();
this.doctorsQueue = new LinkedList<Doctor>();
this.nursesQueue = new LinkedList<Nurse>();
loadModelConstants();
loadMapLayout();
roomController.readyRoomCollections();
createAllAgents();
loadDoctorsInRooms();
loadNursesInRooms();
loadNextPatientArrival();
// randomlyPopulateGrid();
stats.updateStatistics();
stats.setDataValid(false);
// Room entrance = roomController.getAllRooms().get("Entrance");
// Room reception = roomController.getAllRooms().get("Reception");
// Room aNe = roomController.getAllRooms().get("A&E");
// Room ward1 = roomController.getAllRooms().get("Ward 1");
// Room ward2 = roomController.getAllRooms().get("Ward 2");
// Room ward3 = roomController.getAllRooms().get("Ward 3");
// Room canteen = roomController.getAllRooms().get("Canteen");
// Room toilet = roomController.getAllRooms().get("Toilet");
//
// System.out.println(toilet);
// System.out.println(entrance.getDoorLocations().size());
// System.out.println("Reception: " + reception.getRoomLocations().size());
// System.out.println("A&E: " + aNe.getRoomLocations().size());
// System.out.println("Ward 1: " + ward1.getRoomLocations().size());
// System.out.println("Ward 2: " + ward2.getRoomLocations().size());
// System.out.println("Ward 3: " + ward3.getRoomLocations().size());
// System.out.println("Canteen: " + canteen.getRoomLocations().size());
// System.out.println("Toilet: " + toilet.getRoomLocations().size());
}
public void loadModelConstants() {
this.patientPopulation = modelConstants.getPatientPopulation();
this.doctorPopulation = modelConstants.getDoctorPopulation();
this.receptionNurses = modelConstants.getReceptionNursePopulation();
this.aNeNurses = modelConstants.getaNeNursePopulation();
this.ward1Nurses = modelConstants.getWard1NursePopulation();
this.ward2Nurses = modelConstants.getWard2NursePopulation();
this.ward3Nurses = modelConstants.getWard3NursePopulation();
// System.out.println(this.patientPopulation);
// System.out.println(this.doctorPopuation);
// System.out.println(this.nursePopulation);
System.out.println("Loaded Model Constants");
}
public void loadMapLayout() {
Maplayout.loadMapImage();
Maplayout.loadRGBfileAndRooms();
Maplayout.readPixels();
Maplayout.addMapLayout();
// layout.printCells();
System.out.println("Loaded Map Layout");
}
public void createAllAgents() {
ArrayList<Patient> tempPatient = new ArrayList<Patient>();
ArrayList<Doctor> tempDoctor = new ArrayList<Doctor>();
ArrayList<Nurse> tempNurse = new ArrayList<Nurse>();
int totalNurses = + (modelConstants.getReceptionNursePopulation()
+ modelConstants.getaNeNursePopulation()
+ modelConstants.getWard1NursePopulation()
+ modelConstants.getWard2NursePopulation()
+ modelConstants.getWard3NursePopulation()
);
int noOfAgentLeftToCreate = modelConstants.getPatientPopulation() + modelConstants.getDoctorPopulation()
+ totalNurses;
while(tempPatient.size() != this.patientPopulation) {
Patient newPatient = (Patient) this.agentFacory.createAgent("PATIENT", noOfAgentLeftToCreate);
tempPatient.add(newPatient);
noOfAgentLeftToCreate--;
}
while(tempDoctor.size() != this.doctorPopulation) {
Doctor newDoctor = (Doctor)this.agentFacory.createAgent("DOCTOR", noOfAgentLeftToCreate);
tempDoctor.add(newDoctor);
noOfAgentLeftToCreate--;
}
while(tempNurse.size() != totalNurses) {
Nurse newNurse = (Nurse)this.agentFacory.createAgent("NURSE", noOfAgentLeftToCreate);
tempNurse.add(newNurse);
noOfAgentLeftToCreate--;
}
this.patientArrivalQueue.addAll(tempPatient); //Add total patients to arrive queue
this.doctorsQueue.addAll(tempDoctor); //Add all doctors to the doctors agent collection
this.nursesQueue.addAll(tempNurse); //Add all nurses to the nurse agent collection
System.out.println("All agents created");
}
public void loadDoctorsInRooms() {
for(Map.Entry<String, Room> pair : roomController.getDoctorRooms().entrySet()) {
String key = pair.getKey();
Room value = pair.getValue();
if(value.isRoomEmpty()) {
Doctor newDoctor = doctorsQueue.remove();
Location randFreeRoomLoc = value.getRandomFreeRoomLocation();
grid.moveAgentToNewLocation(newDoctor, newDoctor.getLocation(), randFreeRoomLoc);
newDoctor.setLocation(randFreeRoomLoc);
newDoctor.setAllocatedRoom(value);
newDoctor.getAgentController().setCurrentRoom(value);
newDoctor.getAgentController().setTargetRoom(value);
//Tell the room that this agent is now a occupant of the room
value.getCurrentOccupantsMap().put(newDoctor.getAgentID(), newDoctor);
agents.add(newDoctor);
}
}
Room aNeRoom = roomController.getAllRooms().get("A&E");
if(aNeRoom.isRoomEmpty()) {
Doctor aNeDoc = doctorsQueue.remove();
Location randFreeRoomLoc = aNeRoom.getRandomFreeRoomLocation();
grid.moveAgentToNewLocation(aNeDoc, aNeDoc.getLocation(), randFreeRoomLoc);
aNeDoc.setLocation(randFreeRoomLoc);
aNeDoc.setAllocatedRoom(aNeRoom);
aNeDoc.getAgentController().setCurrentRoom(aNeRoom);
aNeDoc.getAgentController().setTargetRoom(aNeRoom);
//Tell the room that this agent is now a occupant of the room
aNeRoom.getCurrentOccupantsMap().put(aNeDoc.getAgentID(), aNeDoc);
agents.add(aNeDoc);
}
System.out.println("All Doctors are placed");
}
public void loadNursesInRooms() {
HashMap<String, Room> nurseRooms = new HashMap<String, Room>();
nurseRooms.putAll( roomController.getAllRooms());
nurseRooms.remove("Toilet");
nurseRooms.remove("Canteen");
nurseRooms.remove("Staff");
nurseRooms.remove("Corridor");
nurseRooms.remove("ISOL Entrance");
nurseRooms.remove("Entrance");
nurseRooms.remove("Exit");
for(Map.Entry<String, Room> drPair : roomController.getDoctorRooms().entrySet()) {
String drKey = drPair.getKey();
Room drValue = drPair.getValue();
for(Map.Entry<String, Room> isolPair : roomController.getIsolRooms().entrySet()) {
String isolKey = isolPair.getKey();
Room isolValue = isolPair.getValue();
if(nurseRooms.containsKey(drKey)) {
nurseRooms.remove(drKey);
}
if(nurseRooms.containsKey(isolKey)) {
nurseRooms.remove(isolKey);
}
}
}
for(Map.Entry<String, Room> pair : nurseRooms.entrySet()) {
String key = pair.getKey();
Room value = pair.getValue();
int noOfNurseToCreate = 0;
if(key.contentEquals("Reception")) {
noOfNurseToCreate = modelConstants.getReceptionNursePopulation();
}
else if(key.contentEquals("A&E")) {
noOfNurseToCreate = modelConstants.getaNeNursePopulation();
}
else if(key.contentEquals("Ward 1")) {
noOfNurseToCreate = modelConstants.getWard1NursePopulation();
}
else if(key.contentEquals("Ward 2")) {
noOfNurseToCreate = modelConstants.getWard2NursePopulation();
}
else if(key.contentEquals("Ward 3")) {
noOfNurseToCreate = modelConstants.getWard3NursePopulation();
}
for(int i=0; i != noOfNurseToCreate; i++) {
Nurse newNurse = nursesQueue.remove();
Location roomLocation = value.getRandomFreeRoomLocation();
grid.moveAgentToNewLocation(newNurse, newNurse.getLocation(), roomLocation);
newNurse.setLocation(roomLocation);
newNurse.setAllocatedRoom(value);
newNurse.getAgentController().setCurrentRoom(value);
newNurse.getAgentController().setTargetRoom(value);
//Tell the room controller that this agent is now an occupant of the room
value.getCurrentOccupantsMap().put(newNurse.getAgentID(), newNurse);
agents.add(newNurse);
}
}
System.out.println("All Nurses are placed");
}
public void loadNextPatientArrival() {
if(this.simArrivalCounter == 0) {
int removeThemPatients = 0;
//If there are more patients in the arrival queue then the specified simPatientarrival rate then
//remove the specified amount of patients per simPatient arrival rate
if(patientArrivalQueue.size() >= modelConstants.getPatientArrivalRate()) {
removeThemPatients = modelConstants.getPatientArrivalRate();
}
//Number of patient to place on the grid is less then the patient arrival rate, just place the rest into the entrance
else {
removeThemPatients = patientArrivalQueue.size();
}
Room reception = roomController.getAllRooms().get("Reception");
Room aNe = roomController.getAllRooms().get("A&E");
for(int i=removeThemPatients; i !=0; i--) {
Patient nextPatient = patientArrivalQueue.remove();
// if(nextPatient.getPatientType().contains("Normal") & nextPatient.getLocation() != null) {
if(grid.checkEmptyAt(nextPatient.getLocation())) {
grid.placeAgent(nextPatient, nextPatient.getLocation());
agents.add(nextPatient);
}
else {
patientArrivalQueue.add(nextPatient);
}
// }
}
//IMPORTANT need to reset the simArrivalCounter back to the specified count
this.simArrivalCounter = this.modelConstants.getSimArrivalCounter();
// System.out.println("More patients have arrived");
}
}
public void removeDischargedPatients() {
//Just iterate through the exit room door locations and remove
//the the discharged patients waiting there into the patient discharge list
Room exit = roomController.getAllRooms().get("Exit");
for(Location loc : exit.getDoorLocations()) {
if(!grid.checkEmptyAt(loc)) {
Patient dischargedPatient = (Patient) grid.getAgentAtLocation(loc);
grid.clearLocationAt(loc);
agents.remove(dischargedPatient);
dischargedPatients.add(dischargedPatient);
}
}
}
public void randomlyPopulateGrid() {
Room reception = roomController.getAllRooms().get("Reception");
while(!this.patientArrivalQueue.isEmpty()) {
Location freeLoc = reception.getRandomFreeRoomLocation();
Patient nextPatient = this.patientArrivalQueue.remove();
grid.moveAgentToNewLocation(nextPatient, nextPatient.getLocation(), freeLoc);
nextPatient.setLocation(freeLoc);
nextPatient.getAgentController().setCurrentRoom(reception);
nextPatient.getAgentController().setTargetRoom(reception);
agents.add(nextPatient);
}
System.out.println("Populate Grid");
}
public void simulateCycles(int maxCycles) {
for(int i=0; i != maxCycles; i++) {
loadNextPatientArrival();
removeDischargedPatients();
updateAgents();
stats.updateStatistics();
stats.setDataValid(false);
this.currentSimCycle++;
this.simArrivalCounter--;
}
notifyViews();
}
public void updateAgents() {
// Iterator<AbstractAgent> it = agents.iterator();
// while(it.hasNext()) {
// AbstractAgent nextAgent = it.next();
// nextAgent.act();
// }
for(AbstractAgent agent : agents) {
agent.act();
}
}
@Override
public void startSimulation() {
new Thread(this).start();
System.out.println("Running Simulation");
}
@Override
public void stopSimulation() {
running = false;
System.out.println("Simulation has stoped");
}
@Override
public void resetSimulation() {
System.out.println("Model Constant set to default");
}
public void run() {
running = true;
// int loop = 0;
while(running) {
// System.out.println("loop: "+ loop);
// loop++;
simulateCycles(1);
try {
Thread.sleep(5);
}
catch (Exception e) {
}
}
}
public Grid getGrid() {
return grid;
}
public List<AbstractAgent> getAgentsCollection() {
return agents;
}
public GridMapLayout getGridMayLayout() {
return Maplayout;
}
public RoomController getRoomController() {
return roomController;
}
public Constants getModelConstants() {
return modelConstants;
}
public RandomGenerator getRandGenerator() {
return randGenerator;
}
public int getCurrentSimCycle() {
return currentSimCycle;
}
public Statistics getStats() {
return stats;
}
}