/** * A component of a library for * GENESIS * Copyright (C) 2008 * Andy Turner, * University of Leeds. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ package uk.ac.leeds.ccg.andyt.projects.genesis.process; import java.io.File; import java.util.HashSet; import java.util.Iterator; import java.util.Random; import java.util.Vector; import uk.ac.leeds.ccg.andyt.grids.core.Grid2DSquareCellDouble; import uk.ac.leeds.ccg.andyt.grids.exchange.ImageExporter; import uk.ac.leeds.ccg.andyt.grids.process.Grid2DSquareCellProcessor; import uk.ac.leeds.ccg.andyt.projects.genesis.society.demography.Demographics; import uk.ac.leeds.ccg.andyt.projects.genesis.society.demography.Fertility; import uk.ac.leeds.ccg.andyt.projects.genesis.society.demography.Mapping; import uk.ac.leeds.ccg.andyt.projects.genesis.society.demography.Mortality; import uk.ac.leeds.ccg.andyt.projects.genesis.society.demography.Movement; import uk.ac.leeds.ccg.andyt.projects.genesis.society.environment.Environment; //import uk.ac.leeds.ccg.andyt.projects.genesis.society.organisations.Family; import uk.ac.leeds.ccg.andyt.projects.genesis.society.environment.Location; import uk.ac.leeds.ccg.andyt.projects.genesis.society.organisations.Household; import uk.ac.leeds.ccg.andyt.projects.genesis.society.persons.Female; import uk.ac.leeds.ccg.andyt.projects.genesis.society.persons.Male; import uk.ac.leeds.ccg.andyt.projects.genesis.society.persons.Person; import uk.ac.leeds.ccg.andyt.projects.genesis.society.environment.Time; /** * A class to generate a society. */ public class GenerateSociety_2 extends Grid2DSquareCellProcessor { private int _RandomSeed; private Environment _Environment; /** * _Population[0] is a Female HashSet * _Population[1] is a Male HashSet */ //private Object[] _Population; /** * A collection of all Persons, alive or dead, male or female. */ private HashSet _Population; /** * A collection of all alive Females. */ private HashSet _Population_Alive_Female; /** * A collection of all alive Females that are pregnant. */ private HashSet _Population_Alive_Female_Pregnant; /** * A collection of all alive Males. */ private HashSet _Population_Alive_Male; public ImageExporter _ImageExporter; public String _Type; public GenerateSociety_2() { } public static void main(String args[]) { GenerateSociety_2 _GenerateSociety_2 = new GenerateSociety_2(); _GenerateSociety_2.run(); } /** * Example run with the smallest timestep being 1 second producing: * Age/gender plots at each year * A composite map of locations each day * * Each person has a workplace and some workhours. They travel to their * workplace and depending on how early/late they are, they set off at * different time the next day. Hopefully after a few days most people * should set of at about the right time so as not to be late. * * To begin with, each Person works from 9am to 5pm every day. * * There are 10 Work Locations and these assigned at Random. * * information about how related society is * need to model who fathers which children * people now have fertility and mortality rates conditioned by their resource level. * people move about the landscape getting resource * people need a memory of where they have gone and what resource is available there * people have social networks forming now they move about in space coming into contact with people from other households */ public void run() { _RandomSeed = 0; Time _Time = new Time(20, 0); _Grid2DSquareCells = new HashSet(); boolean _HandleOutOfMemoryError = false; long _NRows = 501; long _NCols = 501; Grid2DSquareCellDouble _World_Grid2DSquareCellDouble = (Grid2DSquareCellDouble) _Grid2DSquareCellDoubleFactory.create(_NRows, _NCols); long row; long col; for (row = 0; row < _NRows; row++) { for (col = 0; col < _NCols; col++) { _World_Grid2DSquareCellDouble.setCell(row, col, 0.0d, _HandleOutOfMemoryError); } } _Environment = new Environment( new Random(_RandomSeed), _Time, _Grid2DSquareCellDoubleFactory, _World_Grid2DSquareCellDouble, _HandleOutOfMemoryError); _Environment._Init_Resource_Grid2DSquareCellDouble(); _Time = new Time(0, 0); int numberOfWorkplaces = 100; Vector _Location_Works = new Vector(numberOfWorkplaces); int delta_row; int delta_col; int variation = 400; for (int i = 0; i < numberOfWorkplaces; i++) { delta_row = _Environment._Random.nextInt(variation); delta_col = _Environment._Random.nextInt(variation); //_Location_Works.add(_Environment.getRandomLocation()); _Location_Works.add(new Location( _NRows / 2 - (variation / 2) + delta_row, _NCols / 2 - (variation / 2) + delta_col)); } int _NumberOfHouseholds = 5000; int _Max_NumberOfFemalesPerHousehold = 5; int _Max_NumberOfMalesPerHousehold = 5; _Initialise_Population( _Environment, _Time, _NumberOfHouseholds, _Max_NumberOfFemalesPerHousehold, _Max_NumberOfMalesPerHousehold, _Location_Works); _ImageExporter = new ImageExporter(); _Type = "PNG"; Demographics _Demographics = new Demographics(); int _Years = 1;//300; _Simulate(_Demographics, _Years); } /** * Initialises Persons in a simple society. * There are 10 households each consisting of 10 Males and 10 * Females as yet unrelated. * Each household is randomly located within the environment. * Each Person has a randomly located workplace within the environment. */ public void _Initialise_Population( Environment _Environment, Time _Time, int _NumberOfHouseholds, int _Max_NumberOfFemalesPerHousehold, int _Max_NumberOfMalesPerHousehold, Vector _Location_Works) { _Population = new HashSet(); _Population_Alive_Male = new HashSet(); _Population_Alive_Female = new HashSet(); _Population_Alive_Female_Pregnant = new HashSet(); int _NumberOfFemalesPerHousehold; int _NumberOfMalesPerHousehold; int i; int _Household_int; Object _ID; Male _Male; Female _Female; //Person _Person; Time _Min_Time_Birth = new Time(0, 0, 0); Time _Max_Time_Birth = new Time(15, 0, 0); Time _Time_Birth; //Calendar _DateOfBirth_Calendar; for (_Household_int = 0; _Household_int < _NumberOfHouseholds; _Household_int++) { // N.B. Possibility of empty households. Household _Household = new Household(_Environment.getRandomLocation()); // Generate Females _NumberOfFemalesPerHousehold = _Environment._Random.nextInt(_Max_NumberOfFemalesPerHousehold); for (i = 0; i < _NumberOfFemalesPerHousehold; i++) { //_Place_Location = _Environment.getRandomLocation(); _ID = new Object(); _Time_Birth = Time.get_RandomTime( _Min_Time_Birth, _Max_Time_Birth, _Environment._Random); _Female = new Female( _Environment, _ID, _Time_Birth, _Household); _Female._Location_Work = (Location) _Location_Works.elementAt(_Environment._Random.nextInt(_Location_Works.size())); _Female._Time_Work = new Time[2]; _Female._Time_Work[0] = new Time(0, 0, 60 * 60 * 9); _Female._Time_Work[1] = new Time(0, 0, 60 * 60 * 17); _Female._Time_SetOffToWork = _Female._Time_Work[0]; _Population_Alive_Female.add(_Female); } // Generate Males _NumberOfMalesPerHousehold = _Environment._Random.nextInt(_Max_NumberOfMalesPerHousehold); for (i = 0; i < _NumberOfMalesPerHousehold; i++) { //_Place_Location = _Environment.getRandomLocation(); _ID = new Object(); _Time_Birth = Time.get_RandomTime( _Min_Time_Birth, _Max_Time_Birth, _Environment._Random); _Male = new Male( _Environment, _ID, _Time_Birth, _Household); //_Male._Location_Work = _Environment.getRandomLocation(); _Male._Location_Work = (Location) _Location_Works.elementAt(_Environment._Random.nextInt(_Location_Works.size())); _Male._Time_Work = new Time[2]; _Male._Time_Work[0] = new Time(0, 0, 60 * 60 * 9); _Male._Time_Work[1] = new Time(0, 0, 60 * 60 * 17); _Male._Time_SetOffToWork = _Male._Time_Work[0]; _Population_Alive_Male.add(_Male); } } _Population.addAll(_Population_Alive_Male); _Population.addAll(_Population_Alive_Female); } /** * Dynamically simulates a population over time. * @param _Demographics * @param _Years The number of years over which the simulation occurs */ public void _Simulate( Demographics _Demographics, int _Years) { Mortality _Mortality = new Mortality(_Environment); int _TotalBirths = 0; int _TotalBirthsInYear = 0; int _TotalDeaths = 0; int _TotalDeathsInYear = 0; int _TotalPregnancies = 0; int _TotalPregnanciesInYear = 0; int _TotalMiscarriages = 0; int _TotalMiscarriagesInYear = 0; Grid2DSquareCellDouble _Population_Location_Composite_Map; Grid2DSquareCellDouble _Population_Movement_Composite_Map; File _File; Fertility _Fertility = new Fertility(); boolean movement; int _Hours; int _HoursInSeconds; int _Minutes; int _MinutesInSeconds; int _Seconds; //int _StartSimulationSecondOfDay = (60 * 60 * 9); for (int _Year = 0; _Year < _Years; _Year++) { _TotalBirthsInYear = 0; _TotalDeathsInYear = 0; _TotalPregnanciesInYear = 0; _TotalMiscarriagesInYear = 0; //for (int _Day = 0; _Day < Time._Normal_Days_In_Year; _Day++) { for (int _Day = 0; _Day < 2; _Day++) { _Population_Location_Composite_Map = (Grid2DSquareCellDouble) _Environment._Grid2DSquareCellDoubleFactory.create(_Environment._World_Grid2DSquareCellDouble); _Population_Movement_Composite_Map = (Grid2DSquareCellDouble) _Environment._Grid2DSquareCellDoubleFactory.create(_Environment._World_Grid2DSquareCellDouble); //_Environment._Time._SecondOfDay = _StartSimulationSecondOfDay; //for (int _Second = _StartSimulationSecondOfDay; _Second < Time._Normal_Seconds_In_Day; _Second++) { for (int _Second = 0; _Second < Time._Normal_Seconds_In_Day; _Second++) { // if (_Second > (60 * 60 * 9) + (60 * 4)) { // int Debug = 0; // } movement = _SimulateMovement(); //if (_Day == 0) { _Hours = _Second / (60 * 60); _HoursInSeconds = _Hours * 60 * 60; _Minutes = (_Second - _HoursInSeconds) / 60; _MinutesInSeconds = _Minutes * 60; _Seconds = _Second - _MinutesInSeconds - _HoursInSeconds; if (movement) { Mapping._AddTo_Population_Movement_Composite_Map( _Population_Movement_Composite_Map, _Population_Alive_Female, _Population_Alive_Male, 1.1d, _Environment._HandleOutOfMemoryError); // Mapping._AddTo_Population_Location_Composite_Map( // _Population_Movement_Composite_Map, // _Population, // 1.1d, // _Environment._HandleOutOfMemoryError); if (_Second % 5 == 0) { _File = new File("C:/temp/_Population_Movement_Composite_Map_" + _Year + "_" + _Day + "_" + _Hours + "_" + _Minutes + "_" + _Seconds + "." + _Type); //_Rescale(_Population_Movement_Composite_Map, "log", 1.0d, 10.0d,_Environment._HandleOutOfMemoryError); Mapping._OutputMap( _Population_Movement_Composite_Map, _File, _Type, _ImageExporter, _Environment); } } //} // // Output Map // Mapping._AddTo_Population_Location_Composite_Map( // _Population_Location_Composite_Map, // _Population, // 1.0d, // _Environment._HandleOutOfMemoryError); // if (_Second % 60 == 0) { // _File = new File("C:/temp/_Population_Location_Composite_Map_" + _Year + "_" + _Day + "_" + _Hours + "_" + _Minutes + "_" + _Seconds + "." + _Type); // Mapping._OutputMap( // _Population_Location_Composite_Map, // _File, _Type, _ImageExporter, _Environment); // } System.out.println("Second " + _Second + " Out Of " + Time._Normal_Seconds_In_Day); _Environment._Time._Increment_Second(); } // _File = new File("C:/temp/_Density_Map_Population" + _Year + "_" + _Day + "." + _Type); // Mapping._OutputMap( // _Population_Location_Composite_Map, // _File, _Type, _ImageExporter, _Environment); // Output Demographics // Deaths // Does anyone die today? _TotalDeathsInYear += _SimulateDeath( _Mortality); // Births // Is anyone born today? _TotalBirthsInYear += _SimulateBirth(); // Pregnancy // Does anyone get pregnant today? _TotalPregnanciesInYear += _SimulatePregnancy(_Fertility); // Miscarriage // Does anyone miscarry today? _TotalMiscarriagesInYear += _SimulateMiscarriage(); _Environment._Time._Increment_Day(); System.out.println( "_Year " + _Year + "_Day " + _Day); } _TotalDeaths += _TotalDeathsInYear; _TotalBirths += _TotalBirthsInYear; _TotalPregnancies += _TotalPregnanciesInYear; System.out.println( "_Year " + _Year + ", _TotalDeathsInYear " + _TotalDeathsInYear + ", _TotalBirthsInYear " + _TotalBirthsInYear + ", _TotalPregnanciesInYear " + _TotalPregnanciesInYear + ", _TotalMiscarriagesInYear " + _TotalMiscarriagesInYear); _Demographics._AgeGenderPlot( _Population_Alive_Female, _Population_Alive_Male, _Environment._Time); } System.out.println( ", _TotalDeaths " + _TotalDeaths + ", _TotalBirths " + _TotalBirths + ", _TotalPregnancies " + _TotalPregnancies + ", _TotalMiscarriages " + _TotalMiscarriages); //return result; } /** */ public int _SimulateDeath( Mortality _Mortality) { int _TotalDeaths = 0; //double _FixedDailyDeathRate = 0.001; //0.5; double _DailyDeathRate; Iterator _Iterator; Female _Female; Male _Male; double comparison; HashSet newDeadFemales = new HashSet(); _Iterator = _Population_Alive_Female.iterator(); while (_Iterator.hasNext()) { _Female = (Female) _Iterator.next(); _DailyDeathRate = _Mortality.get_AnnualMortalityLikelihood(_Female) / 365.0d; comparison = _Environment._Random.nextDouble(); //if (comparison<_FixedDailyDeathRate){ if (comparison < _DailyDeathRate) { _Female.set_Time_Death(_Environment._Time); newDeadFemales.add(_Female); _TotalDeaths++; } } _Population_Alive_Female.removeAll(newDeadFemales); _Population_Alive_Female_Pregnant.removeAll(newDeadFemales); HashSet newDeadMales = new HashSet(); _Iterator = _Population_Alive_Male.iterator(); while (_Iterator.hasNext()) { _Male = (Male) _Iterator.next(); _DailyDeathRate = _Mortality.get_AnnualMortalityLikelihood(_Male) / 365.0d; comparison = _Environment._Random.nextDouble(); //if (comparison<_FixedDailyDeathRate){ if (comparison < _DailyDeathRate) { _Male.set_Time_Death(_Environment._Time); newDeadFemales.add(_Male); _TotalDeaths++; } } _Population_Alive_Male.removeAll(newDeadMales); return _TotalDeaths++; } /** * @return Total number of births */ public int _SimulateBirth() { int _TotalBirths = 0; Iterator _Iterator; Female _Female; HashSet newbornFemales = new HashSet(); _Iterator = _Population_Alive_Female.iterator(); while (_Iterator.hasNext()) { _Female = (Female) _Iterator.next(); if (_Female._IsPregnant()) { if (_Female._Time_DueToGiveBirth.compareTo(_Environment._Time) == 0) { Person _Person = _Female._Gives_Birth(); if (_Person.get_Gender() == 0) { newbornFemales.add(_Person); } else { _Population_Alive_Male.add(_Person); } _TotalBirths++; //System.out.println("Birth"); //} else { // System.out.println("Birth due in " + _Female._Time_DueToGiveBirth._Difference(_Environment._Time)); } } } _Population_Alive_Female.addAll(newbornFemales); return _TotalBirths; } /** * Returns HashSet of all males at _Location * @param _Location */ public HashSet getMales(Object _Location) { Iterator _Iterator = _Population_Alive_Male.iterator(); Male _Male; HashSet _MalesAtLocation = new HashSet(); while (_Iterator.hasNext()) { _Male = (Male) _Iterator.next(); if (_Male._Location == _Location) { _MalesAtLocation.add(_Male); } } return _MalesAtLocation; } /** */ public int _SimulatePregnancy( Fertility _Fertility) { int _TotalPregnancies = 0; Iterator _Iterator; Female _Female; int _Age; double fertility; double comparison; _Iterator = _Population_Alive_Female.iterator(); while (_Iterator.hasNext()) { _Female = (Female) _Iterator.next(); _Age = _Female.get_AgeInYears_int(); if (!_Female._IsPregnant()) { // Is there a male around to tango? HashSet _Males = getMales(_Female._Location); if (_Males.size() > 0) { // Select one to be the father. // At the moment we just get the first given by the HashSet... // This is probably not best practive, but it's good enough for now Iterator _Males_Iterator = _Males.iterator(); Male _Father = (Male) _Males_Iterator.next(); fertility = _Fertility.get_Fertility_Female(_Age); comparison = _Environment._Random.nextDouble(); if (comparison < fertility) { _Female.set_Pregnant(); //_Female.set_UnbornsFather(_Father); _Population_Alive_Female_Pregnant.add(_Female); _TotalPregnancies++; //System.out.println("Pregnancy"); } } } } return _TotalPregnancies; } /** * * @param _PregnantFemales */ public int _SimulateMiscarriage() { int _TotalMiscarriages = 0; // Fixed chance of miscarriage double _MiscarriageProbablity = 0.0005; double comparison; Iterator _Iterator; Female _Female; _Iterator = _Population_Alive_Female_Pregnant.iterator(); HashSet _MiscarriedFemales = new HashSet(); while (_Iterator.hasNext()) { _Female = (Female) _Iterator.next(); comparison = _Environment._Random.nextDouble(); if (comparison < _MiscarriageProbablity) { _Female._Time_DueToGiveBirth = null; _MiscarriedFemales.add(_Female); _TotalMiscarriages++; //System.out.println("Miscarriage"); } } _Population_Alive_Female_Pregnant.removeAll(_MiscarriedFemales); return _TotalMiscarriages; } /** * Agents only move from home to work and then back again. * Each agent can move to any position in a 1 cell radius of their current location. * @return true if some Person moves */ public boolean _SimulateMovement() { boolean result = false; Iterator _Iterator; Person _Person; _Iterator = _Population_Alive_Female.iterator(); while (_Iterator.hasNext()) { _Person = (Person) _Iterator.next(); if (_Person._Location_Heading == null) { if (_Person._Time_Work[1]._SecondOfDay == _Environment._Time._SecondOfDay) { // Everyone goes home after work! _Person._Location_Heading = _Person._Household._Location; } else { if (_Person._Time_SetOffToWork._SecondOfDay == _Environment._Time._SecondOfDay) { _Person._Location_Heading = _Person._Location_Work; } } } else { if (_Person._Location_Heading.equals(_Person._Location_Work)) { if (!_Person._Location.equals(_Person._Location_Work)) { result = true; _Person._Location = Movement.getNewLocation_1( _Person._Location, _Person._Location_Work, _Environment); } if (_Person._Location.equals(_Person._Location_Work)) { // Person arrives at work int _Seconds_Late = _Environment._Time._SecondOfDay - _Person._Time_Work[0]._SecondOfDay; _Person._Location_Heading = null; _Person._Time_SetOffToWork._SecondOfDay -= _Seconds_Late; } } else { if (_Person._Location_Heading.equals(_Person._Household._Location)) { if (!_Person._Location.equals(_Person._Household._Location)) { result = true; _Person._Location = Movement.getNewLocation_1( _Person._Location, _Person._Household._Location, _Environment); } if (_Person._Location.equals(_Person._Household._Location)) { // Person arrives at home _Person._Location_Heading = null; } } } } } _Iterator = _Population_Alive_Male.iterator(); while (_Iterator.hasNext()) { _Person = (Person) _Iterator.next(); if (_Person._Location_Heading == null) { if (_Person._Time_Work[1]._SecondOfDay == _Environment._Time._SecondOfDay) { // Everyone goes home after work! _Person._Location_Heading = _Person._Household._Location; } else { if (_Person._Time_SetOffToWork._SecondOfDay == _Environment._Time._SecondOfDay) { _Person._Location_Heading = _Person._Location_Work; } } } else { if (_Person._Location_Heading.equals(_Person._Location_Work)) { if (!_Person._Location.equals(_Person._Location_Work)) { result = true; _Person._Location = Movement.getNewLocation_1( _Person._Location, _Person._Location_Work, _Environment); } if (_Person._Location.equals(_Person._Location_Work)) { // Person arrives at work int _Seconds_Late = _Environment._Time._SecondOfDay - _Person._Time_Work[0]._SecondOfDay; _Person._Location_Heading = null; _Person._Time_SetOffToWork._SecondOfDay -= _Seconds_Late; } } else { if (_Person._Location_Heading.equals(_Person._Household._Location)) { if (!_Person._Location.equals(_Person._Household._Location)) { result = true; _Person._Location = Movement.getNewLocation_1( _Person._Location, _Person._Household._Location, _Environment); } if (_Person._Location.equals(_Person._Household._Location)) { // Person arrives at home _Person._Location_Heading = null; } } } } } return result; } }