package uk.ac.leeds.sog.moses.agent; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.StringTokenizer; import org.apache.log4j.Logger; /** * @author BELINDA * This class models the process of the household formation. * In order to form households, first step is to group people by area as household members live in the same Output Area. Then we * put different types of agents into the categories according to their attributes,eg: whether they are HRP, married, children, * adults or elderly etc. Then we can start to assign them into households according to the HRP's requirement of the household members, eg: * whether the HRP needs a spouse and number of children and elderlys within the household etc. * Each assignment complies to the household structure, otherwise an error message will be printed out in model log explaining the reason * why one HRP is not assigned household members. */ public class AreaModel { // declare the variables //total data fields for each record in the raw data protected static final int NUMBER_OF_DATA_FIELDS = 18; //String to hold the location info private String i_location; //a list to hold all the raw data of all people(before parsing) protected List i_peopleData; //create a list to hold all people protected List i_persons; //create lists to hold different agents (HRPs, child dependents, elderly dependents, adult dependents and spouse) protected List i_hrp; protected List i_childDependent; protected List i_elderlyDependent; protected List i_spouse; protected List i_adultDependent; //create a list to hold the people that fall between our categories if there are any protected List i_unknownTypePerson; //create lists to hold the assigned/unassigned HRPs protected List i_assignedHRP; protected List i_unassignedHRP; //total people protected int i_totalNumPersons; //list for the formed households/vacant households protected List i_households; protected List i_vacantHouseholds; //Strings for log descriptions protected String i_descriptionBeforeBuildingModel; protected String i_descriptionAfterBuildingModel; // logger to print out logs protected static Logger s_logger = Logger.getLogger(AreaModel.class); protected static String s_lineSeparator = System.getProperty("line.separator"); /** * Default constructor */ public AreaModel(){} /** * This method initialise the AreaModel */ public AreaModel(String a_location) { i_location = a_location; i_peopleData = new ArrayList(); i_persons = new ArrayList(); i_hrp = new ArrayList(); i_childDependent = new ArrayList(); i_elderlyDependent = new ArrayList(); i_spouse = new ArrayList(); i_adultDependent = new ArrayList(); i_unknownTypePerson = new ArrayList(); i_assignedHRP = new ArrayList(); i_unassignedHRP = new ArrayList(); i_totalNumPersons = 0; i_households = new ArrayList(); i_vacantHouseholds = new ArrayList(); } //Method to get the raw data list public List getPeopleData() { return i_peopleData; } //method to get a number of the total population public int getTotalNumPersons() { return i_totalNumPersons; } //method to get the person list public List getPersons() { return i_persons; } //method to get the HRP list public List getHRP() { return i_hrp; } //method to get the child list public List getChild() { return i_childDependent; } //method to get the elderly list public List getElderly() { return i_elderlyDependent; } //method to get the adult list public List getAdult() { return i_adultDependent; } // method to get the spouse list public List getSpouse() { return i_spouse; } // method to get the assigned HRP list public List getAssignedHRP() { return i_assignedHRP; } // method to get the adult list public List getUnassignedHRP() { return i_unassignedHRP; } // method to get the adult list public List getUnknownTypePerson() { return i_unknownTypePerson; } //This method simulates the steps during the household lifecycle: one year per step. public void step() { //If the list of households is empty, there is no occupied house in the //area and simulation for this area stops if(i_households.size() == 0) { if(s_logger.isDebugEnabled()) { s_logger.debug("No occupied house in the area " + i_location); s_logger.debug("Simulation stops in the area " + i_location); } return; } List temp = new ArrayList(); //add the vacant households in the temp list unless household is not vacant for(int i=0; i= 65 ) { // create an elderly dependent person = new ElderlyDependent(pid); } else { // create an adult dependent person = new AdultDependent(pid); } // set other attributes of the person person.setIndSARRecID(indSARRecID); person.setId(id); person.setAge(age); person.setSocialClass(socialClass); person.setGender(gender); person.setMaritalStatus(maritalStatus); person.setIntIllness(longTermIllness); person.setHealth(health); person.setLocation(location); person.setWLocation(wardLocation); person.setOLocation(oLocation); person.setHrpStatus(hrpStatus); if(houseID != -1) { person.setHouseID(houseID); } person.setHouseholdSize(householdSize); person.setCarer(carrer); person.setFormalCare(formalCare); person.setChildDependentFlag(hasChildDependent); person.setNumElderly(numOfElderly); person.setFitness(fitness); // add person into list according to their types if(person instanceof HRP) { i_hrp.add(person); } else if(person instanceof Child) { i_childDependent.add(person); } else if(person instanceof ElderlyDependent) { i_elderlyDependent.add(person); } else if(person instanceof Spouse) { i_spouse.add(person); } else if(person instanceof AdultDependent) { i_adultDependent.add(person); } else { i_unknownTypePerson.add(person); } //put all people in the toal population list i_persons.add(person); //add to the number of total population i_totalNumPersons++; } catch(NumberFormatException e){ s_logger.error("data format error: " + e.toString()); s_logger.error("data format error: " + data); } } else { s_logger.error("data error(number of fields): " + st.countTokens()); s_logger.error("data error(number of fields): " + data); } // end of if } // end of for //Print out the information of the population in the model before creating households StringBuffer buffer = new StringBuffer(); buffer.append(s_lineSeparator); buffer.append("***** before creating households *****"); buffer.append(s_lineSeparator); buffer.append("Number of persons: " + i_totalNumPersons); buffer.append(s_lineSeparator); buffer.append("Number of HRPs: " + i_hrp.size()); buffer.append(s_lineSeparator); buffer.append("Number of elderly dependents: " + i_elderlyDependent.size()); buffer.append(s_lineSeparator); buffer.append("Number of child dependents: " + i_childDependent.size()); buffer.append(s_lineSeparator); buffer.append("Number of spouses: " + i_spouse.size()); buffer.append(s_lineSeparator); buffer.append("Number of adult dependent: " + i_adultDependent.size()); buffer.append(s_lineSeparator); buffer.append("***** before creating households *****"); buffer.append(s_lineSeparator); i_descriptionBeforeBuildingModel = buffer.toString(); if(s_logger.isDebugEnabled()) { s_logger.debug(buffer.toString()); } // sort by age sortByAge(); } //This method build up the households and print out the information of //the population and households after creating households public void buildModel() { //call the method to build households buildHouseholds(); //print out messages in the log to provide information after creating households StringBuffer buffer = new StringBuffer(); buffer.append("***** after creating households *****"); buffer.append(s_lineSeparator); buffer.append("Number of HRPs left: " + i_unassignedHRP.size()); buffer.append(s_lineSeparator); buffer.append("Number of HRPs assigned into household: " + i_assignedHRP.size()); buffer.append(s_lineSeparator); buffer.append("Number of elderly dependents left: " + i_elderlyDependent.size()); buffer.append(s_lineSeparator); buffer.append("Number of child dependents left: " + i_childDependent.size()); buffer.append(s_lineSeparator); buffer.append("Number of spouses left: " + i_spouse.size()); buffer.append(s_lineSeparator); buffer.append("Number of adult dependent left: " + i_adultDependent.size()); buffer.append(s_lineSeparator); buffer.append("Number of unassigned HRPs: " + i_unassignedHRP.size()); buffer.append(s_lineSeparator); buffer.append("PIDs of unassigned HRPs: "); for(int i=0; i 1) { if(hrp.getMaritalStatus() == 0) { // process single HRP boolean result = processSingleHRPHousehold(hrp, household); if(result == true) { i_assignedHRP.add(hrp); s_logger.debug("create household for single HRP(PID): " + hrp.getPid()); } else { i_unassignedHRP.add(hrp); } } else if(hrp.getMaritalStatus() == 1) { // process married HRP boolean result = processMarriedHRPHousehold(hrp, household); if(result == true) { i_assignedHRP.add(hrp); s_logger.debug("create household for married HRP(PID): " + hrp.getPid()); } else { i_unassignedHRP.add(hrp); } } else { s_logger.error("Marrital status is not correct: " + hrp.getMaritalStatus()); i_unassignedHRP.add(hrp); continue; } } } //See if we stil can build a household when HRP is married, but cannot find spouse //for HRP(no spouse or spouse age is not suitable)and we still have child/adult/elderly //dependents left - In reality, couples not living together for various reasons. s_logger.debug("try to build more households."); s_logger.debug("number of unassigned HRPs: " + i_unassignedHRP.size()); List tempHRP = new ArrayList(); for(int i=0; i= 65) { hrp.setNumElderlyDependent(hrp.getNumElderly() - 1); } else { hrp.setNumElderlyDependent(hrp.getNumElderly()); } if(i_elderlyDependent.size() < hrp.getNumElderlyDependent()) { s_logger.debug("not have enough elderly dependents for HRP(PID): " + hrp.getPid()); continue; } if(hrp.getChildDependentFlag() == 1) { if(i_childDependent.size() == 0) { s_logger.debug("not have child dependent for HRP(PID): " + hrp.getPid()); continue; } int numChildAdult = hrp.getHouseholdSize() - 1 - hrp.getNumElderlyDependent(); if((i_childDependent.size() + i_adultDependent.size()) < numChildAdult) { s_logger.debug("not have enough child/adult dependent for HRP(PID): " + hrp.getPid()); continue; } // assign elderly dependents for(int j=0; j 0) { // assign child dependents if(i_childDependent.size() > 0) { Child child = (Child) i_childDependent.get(0); child.setHouseID(household.getId()); household.addChildDependent(child); i_childDependent.remove(0); numChildAdult--; } if(numChildAdult == 0) { // assignment finished break; } // addsign adult dependents if(i_adultDependent.size() > 0) { AdultDependent adult = (AdultDependent) i_adultDependent.get(0); adult.setHouseID(household.getId()); household.addAdultDependent(adult); i_adultDependent.remove(0); numChildAdult--; } } s_logger.debug("create a household for HRP(PID): " + hrp.getPid()); tempHRP.add(hrp); household.setHouseholdStatus(0); i_households.add(household); } else { // HRP does not have child dependent int numAdult = hrp.getHouseholdSize() - 1 - hrp.getNumElderlyDependent(); if(i_adultDependent.size() < numAdult) { s_logger.debug("not have enough adult dependent for HRP(PID): " + hrp.getPid()); continue; } // assign elderly dependents for(int j=0; j= 65) { // If HRP is over 65, number of elderly dependents should minus 1 a_hrp.setNumElderlyDependent((a_hrp.getNumElderly() -1)); } else { a_hrp.setNumElderlyDependent(a_hrp.getNumElderly()); } //If the number of elderly dependents needed is greater than what is left //in eldery dependents list, the household can not be formed and error messages will be printed. if(a_hrp.getNumElderlyDependent() > i_elderlyDependent.size()) { s_logger.error("---------------------------------------------------------------------------------------------------------------------------------"); s_logger.error("number of elderly dependents needed: " + a_hrp.getNumElderlyDependent()); s_logger.error("not enough elderly dependents for HRP: " + a_hrp.getPid()); s_logger.error("number of elderly dependents left: " + i_elderlyDependent.size()); s_logger.error("---------------------------------------------------------------------------------------------------------------------------------"); return false; } //If there are children in the household, find out if we have enough children to assign if(a_hrp.getChildDependentFlag() == 1) { int totalNumChildAdult = a_household.getSize() - 1 - a_hrp.getNumElderlyDependent(); if(totalNumChildAdult > (i_childDependent.size() + i_adultDependent.size())) { s_logger.debug("not enough child and adult dependents for HRP(PID): " + a_hrp.getPid()); return false; } //As we do not have exact numbers of children and adults in each household, we'll //try to assign at least one child if the household requires children and then make //up the rest of the household by a combination of children and/or adults, whichever //type of dependent is left in list int NumChild = 0; List tempChild = new ArrayList(); int NumAdult = 0; List tempAdult = new ArrayList(); while((NumChild + NumAdult) < totalNumChildAdult) { //assign a child if(i_childDependent.size() > 0) { tempChild.add(i_childDependent.get(NumChild)); NumChild++; } if((NumChild + NumAdult) == totalNumChildAdult) { break; } for(int j=0; j= a_hrp.getAge()) { s_logger.debug("eror: Children must be 16 years younger than HRP."); return false; } }*/ // assign child for(int i=0; i i_adultDependent.size()) { s_logger.debug("not enough adult dependents for HRP(PID): " + a_hrp.getPid()); return false; } for(int i=0; i= 65 && a_hrp.getNumElderly() == 1 && a_hrp.getHouseholdSize() == 2) { // need a spouse younger than 65 Spouse spouse = null; for(int i=0; i= 65 && a_hrp.getNumElderly() == 2 && a_hrp.getHouseholdSize() == 2) { // need a spouse is or older than 65 Spouse spouse = null; for(int i=0; i= 65) { break; } } if(spouse != null && spouse.getAge() >= 65) { spouse.setHouseID(a_household.getId()); a_household.setSpouse(spouse); i_spouse.remove(spouse); a_household.setHouseholdStatus(0); i_households.add(a_household); return true; } // try to assign an elderly dependent instead of an elderly spouse: seperated if(i_elderlyDependent.size() != 0) { ElderlyDependent elderly = (ElderlyDependent) i_elderlyDependent.get(0); elderly.setHouseID(a_household.getId()); a_household.addElderlyDependent(elderly); i_elderlyDependent.remove(0); a_household.setHouseholdStatus(0); i_households.add(a_household); return true; } else { s_logger.debug("error: no elderly dependent left for HRP(PID): " + a_hrp.getPid()); return false; } } else if(a_hrp.getAge() < 65 && a_hrp.getNumElderly() == 0 && a_hrp.getHouseholdSize() == 2) { // need a spouse younger than 65 Spouse spouse = null; for(int i=0; i= 65) { break; } } if(spouse != null && spouse.getAge() >= 65) { spouse.setHouseID(a_household.getId()); a_household.setSpouse(spouse); i_spouse.remove(spouse); a_household.setHouseholdStatus(0); i_households.add(a_household); return true; } // try to assign an elderly dependent because no elderly spouse is left if(i_elderlyDependent.size() != 0) { ElderlyDependent elderly = (ElderlyDependent) i_elderlyDependent.get(0); elderly.setHouseID(a_household.getId()); a_household.addElderlyDependent(elderly); i_elderlyDependent.remove(0); a_household.setHouseholdStatus(0); i_households.add(a_household); return true; } else { s_logger.debug("error: no elderly dependent left for HRP(PID): " + a_hrp.getPid()); return false; } } // cases where household size > 2 // look for a spouse from the spouse candidate list int gender = a_hrp.getGender(); Spouse spouse = null; for(int i=0; i= 65 && spouse.getAge() >= 65) { // both HRP and spouse are over 65 // find out the number of elderly dependents required a_hrp.setNumElderlyDependent(a_hrp.getNumElderly() - 2); if(a_hrp.getNumElderlyDependent() < 0) { s_logger.error("No younger spouse. Unable to create household for HRP: " + a_hrp.getPid()); return false; } return assignDependents(a_hrp, a_household, spouse); } else if(a_hrp.getAge() >= 65 && spouse.getAge() < 65) { // HRP over 65 and spouse younger than 65 // find out the number of elderly dependents required a_hrp.setNumElderlyDependent(a_hrp.getNumElderly() - 1); if(a_hrp.getNumElderlyDependent() < 0) { s_logger.error("Data error: negative number of elderly dependents. Unable to create household for HRP: " + a_hrp.getPid()); return false; } return assignDependents(a_hrp, a_household, spouse); } else if(a_hrp.getAge() < 65 && spouse.getAge() >= 65) { // HRP younger than 65 and spouse over 65 // find out the number of elderly dependents required a_hrp.setNumElderlyDependent(a_hrp.getNumElderly() - 1); if(a_hrp.getNumElderlyDependent() < 0) { s_logger.error("No younger spouse. Unable to create household for HRP: " + a_hrp.getPid()); return false; } return assignDependents(a_hrp, a_household, spouse); } else { // both HRP and spouse are younger than 65 // find out the number of elderly dependents required a_hrp.setNumElderlyDependent(a_hrp.getNumElderly()); if(a_hrp.getNumElderlyDependent() < 0) { s_logger.error("Data error: negative number of elderly dependents. Unable to create household for HRP: " + a_hrp.getPid()); return false; } return assignDependents(a_hrp, a_household, spouse); } // end of assignment with spouse } else { // no spouse if(a_hrp.getAge() >= 65) { // find out the number of elderly dependents required a_hrp.setNumElderlyDependent(a_hrp.getNumElderly() - 1); if(a_hrp.getNumElderlyDependent() < 0) { s_logger.error("Data error: negative number of elderly dependents. Unable to create household for HRP: " + a_hrp.getPid()); return false; } return assignDependents(a_hrp, a_household, null); } else { // HRP younger than 65 // find out the number of elderly dependents required a_hrp.setNumElderlyDependent(a_hrp.getNumElderly()); if(a_hrp.getNumElderlyDependent() < 0) { s_logger.error("Data error: negative number of elderly dependents. Unable to create household for HRP: " + a_hrp.getPid()); return false; } return assignDependents(a_hrp, a_household, null); } } } //This method assign different types of dependents into the household as required protected boolean assignDependents(HRP a_hrp, Household a_household, Spouse spouse) { if(a_hrp.getChildDependentFlag() == 0) { // no children within households // decide the number of adult dependents required if(spouse != null) { // with spouse a_hrp.setNumAdultDependent(a_household.getSize() - 2 - a_hrp.getNumElderlyDependent()); } else { // no spouse a_hrp.setNumAdultDependent(a_household.getSize() - 1 - a_hrp.getNumElderlyDependent()); } if(a_hrp.getNumAdultDependent() < 0) { s_logger.error("data error: negative number of adult dependents. Unable to create household for HRP: " + a_hrp.getPid()); return false; } // check if we have enough elderly dependents/adult dependents if(a_hrp.getNumElderlyDependent() > i_elderlyDependent.size()) { s_logger.error("---------------------------------------------------------------------------------------------------------------------------------"); s_logger.error("number of elderly dependents needed: " + a_hrp.getNumElderlyDependent()); s_logger.error("not enough elderly dependents for HRP: " + a_hrp.getPid()); s_logger.error("number of elderly dependents left: " + i_elderlyDependent.size()); s_logger.error("---------------------------------------------------------------------------------------------------------------------------------"); return false; } else if(a_hrp.getNumAdultDependent() > i_adultDependent.size()) { s_logger.error("---------------------------------------------------------------------------------------------------------------------------------"); s_logger.error("not enough adult dependents for HRP: " + a_hrp.getPid()); s_logger.error("number of adult dependents needed: " + a_hrp.getNumAdultDependent()); s_logger.error("number of adult dependents left: " + i_adultDependent.size()); s_logger.error("---------------------------------------------------------------------------------------------------------------------------------"); return false; } // If we have enough candidates of different types, start to assign people into households // assign spouse to this HRP if HRP has a spouse if(spouse != null) { spouse.setHouseID(a_household.getId()); a_household.setSpouse(spouse); i_spouse.remove(spouse); } // assign elderly dependent into household for(int i=0; i (i_childDependent.size() + i_adultDependent.size())) { s_logger.debug("not enough child and adult dependents for HRP(PID): " + a_hrp.getPid()); return false; } // check if we have enough elderly dependents/adult dependents if(a_hrp.getNumElderlyDependent() > i_elderlyDependent.size()) { s_logger.error("---------------------------------------------------------------------------------------------------------------------------------"); s_logger.error("number of elderly dependents needed: " + a_hrp.getNumElderlyDependent()); s_logger.error("not enough elderly dependents for HRP: " + a_hrp.getPid()); s_logger.error("number of elderly dependents left: " + i_elderlyDependent.size()); s_logger.error("---------------------------------------------------------------------------------------------------------------------------------"); return false; } int NumChild = 0; List tempChild = new ArrayList(); int NumAdult = 0; List tempAdult = new ArrayList(); while((NumChild + NumAdult) < totalNumChildAdult) { //assign a child if(i_childDependent.size() > 0) { tempChild.add(i_childDependent.get(NumChild)); NumChild++; } //stop if we have enough children if((NumChild + NumAdult) == totalNumChildAdult) { break; } //assign an adult for(int j=0; j= a_hrp.getAge()) { s_logger.debug("eror: Children must be 16 years younger than HRP."); return false; } }*/ // assign spouse to this HRP if HRP has a spouse if(spouse != null) { spouse.setHouseID(a_household.getId()); a_household.setSpouse(spouse); i_spouse.remove(spouse); } // assign elderly dependent into household for(int i=0; i