Skip to content

create_world_2

Create World

Example script to show the creation of a world for simulation.

Creates a World object and writes the details to a file (my_world.hdf5).

This example script creates a World object, which contains information such as the geography, population distribution, places of leisure, places of work, and how the disease interacts. This World object is then used by run_simulation.md in order to simulate the spread of the infection.

Creation of the world takes several steps:

Step 1: Disease configuration.

This step configures the disease. It uses the DiseaseConfig class, which manages disease-specific configurations and initalises managers for rates, interactions, symptoms, etc.

Step 2: Create the Geography.

This step creates a Geography object, which contains all the geographical objects that encode where things are --- people, workplaces, schools, and leisure activities.

Step 3: Create the World object.

This is usually the slowest step. It creates people according to demography, assigning them workplaces an leisure activities, and then assigns them a household in the Geography to live in. See world.py for details.

Step 4: Leisure Time.

Initialises leisure activities (Pubs, Cinemas, Groceries, Gymns) if available and not yet done.

Step 5: Travel.

Sets up the ability for people to travel.

Step 6: Writing the world.

Writes the world to an hdf5 file.

geography_choice_step(choice=2)

Selects which areas (the smallest geographic unit for the code) to load into the world.

Several examples are given here, decided by the variable "choice".

Select the geography to simulate

1: Small Aberdeen Test 2: Small Durham Test 3: Small Cross-Region (Carlisle + Southern Dumfries) 4: Small Northern Ireland test 5: 100 MSOAs from all regions (E, S, W, N) 6: ALL MSOAs from super_area_centroids.csv except S02003412 and S02003443 7: Only MSOAs that start with N from super_area_centroids.csv

Parameters:

Name Type Description Default
choice int

int (Default value = 2)

2

Returns:

Name Type Description
list list

msoas_to_load (list): A list of strings corresponding to the keynames of each area to load into the world.

Source code in example_scripts/create_world_2.py
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
def geography_choice_step(choice: int = 2) -> list:
    """Selects which areas (the smallest geographic unit for the code) to load into the world.

    Several examples are given here, decided by the variable "choice".

    Select the geography to simulate:
        1: Small Aberdeen Test
        2: Small Durham Test
        3: Small Cross-Region (Carlisle + Southern Dumfries)
        4: Small Northern Ireland test
        5: 100 MSOAs from all regions (E, S, W, N)
        6: ALL MSOAs from super_area_centroids.csv except S02003412 and S02003443
        7: Only MSOAs that start with N from super_area_centroids.csv

    Args:
        choice (int, optional): int (Default value = 2)

    Returns:
        list: msoas_to_load (list): A list of strings corresponding to the keynames of each area to load into the world.
    """
    match choice:
        case 1: 
            SAs_to_load = ['S02002529','S02002527','S02002541','S02002532','S02002531','S02002520','S02002528','S02002522','S02002521','S02002519','S02002530','S02002539','S02002536','S02002537','S02002538','S02002535','S02002534','S02002576','S02002571','S02002575','S02002533','S02002577','S02002516','S02002515','S02002526','S02002525','S02002523']
        case 2:
            SAs_to_load = ['E02004314', 'E02004315', 'E02004313', 'E02004309', 'E02007058', 'E02007099'] #Durham, Darlington, Newcastle
        case 3:
            SAs_to_load = ['E02003999','E02004002','E02003987','E02003990','E02003989','E02003992','E02003996', 'S02002832','S02002840','S02002841','S02002846','S02002828']
        case 4:
            SAs_to_load = ['N21000433', 'N21000423', 'N21000427', 'N21000399', 'N21000403', 'N21000274','N21000192','N21000178','N21000335','N21000224']
        case 5:
            # Load 100 MSOAs from all regions (E, S, W, N) from file
            SAs_to_load = []
            with open(os.path.join(os.path.dirname(__file__), '../selected_100_msoas_file1.txt'), 'r') as f:
                for line in f:
                    line = line.strip()
                    if line and line.endswith(','):
                        SA_code = line[1:-2]  # Remove quotes and comma
                        SAs_to_load.append(SA_code)
        case 6:
            # Load ALL MSOAs from super_area_centroids.csv except S02003412 and S02003443
            SAs_to_load = []
            excluded_SAs = {'S02003412', 'S02003443'}

            centroids_file = os.path.join(os.path.dirname(__file__), '../data/input/geography/super_area_centroids.csv')
            with open(centroids_file, 'r') as f:
                csv_reader = csv.reader(f)
                next(csv_reader)  # Skip header row
                for row in csv_reader:
                    if row:  # Skip empty rows
                        SA_code = row[0]
                        if SA_code not in excluded_SAs:
                            SAs_to_load.append(SA_code)
        case 7:
            SAs_to_load = ['E02006345'] 
        case _:
            raise ValueError("The variable 'choice' does not correspond to any case.\n As a result, the script does not know what MSOA to load")

    return SAs_to_load

geography_loading(SAs_to_load)

Loads the geography of the world. This includes the list of areas and super_areas, other important places, and where those places are.

Parameters:

Name Type Description Default
SAs_to_load list

a list of all the super-areas that are to be used for the world.

required

Returns:

Name Type Description
Geography Geography

an object that generates the geography-area hierarchy. For example, it contains the lists of areas, super_areas, and regions. It also contains the locations of important places such as hospitals, schools, and grocery outlets. See geography.py.

Source code in example_scripts/create_world_2.py
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
def geography_loading(SAs_to_load: list) -> "Geography":
    """Loads the geography of the world. This includes the list of areas and super_areas, other important places, and where those places are.

    Args:
        SAs_to_load (list): a list of all the super-areas that are to be used for the world.

    Returns:
        Geography: an object that generates the geography-area hierarchy. For example, it contains the lists of areas, super_areas, and regions. It also contains the locations of important places such as hospitals, schools, and grocery outlets. See [geography.py](../geography/geography.md).
    """

    try:

        hierarchy_filename = (
            paths.data_path / "input/geography/area_super_area_region.csv"
        )
        area_coord_filename = (
            paths.data_path / "input/geography/area_coordinates_sorted.csv"
        )
        superarea_coord_filename = (
            paths.data_path / "input/geography/super_area_coordinates_sorted.csv"
        )
        area_socioeconomic_index_filename = (
            paths.data_path / "input/geography/socioeconomic_index.csv"
        )

        # Attempts to load the basic geography --- i.e. the list of areas and super_areas. 
        logger.info("Loading geography and boundaries from files...")
        geography = Geography.from_file(hierarchy_filename,
                                        area_coord_filename,
                                        superarea_coord_filename,
                                        area_socioeconomic_index_filename,
                                        filter_key = {"super_area": SAs_to_load})
        logger.info(f"Successfully loaded geography with {len(geography.areas)} areas and {len(geography.super_areas)} super areas")


        # Trying to load hospitals
        try:
            geography.hospitals = Hospitals.for_geography(geography)
            logger.info(f"Added {len(geography.hospitals) if geography.hospitals else 0} hospitals")
        except Exception as e:
            logger.warning(f"Failed to add hospitals: {e}")
            geography.hospitals = None


        # Trying to load companies
        try:
            geography.companies = Companies.for_geography(geography, sct_companies_file=paths.data_path / "input/companies/SCT_companies.csv")
            logger.info(f"Added {len(geography.companies) if geography.companies else 0} companies")
        except Exception as e:
            logger.warning(f"Failed to add companies: {e}")
            geography.companies = None

        # Trying to load schools
        try:
            geography.schools = Schools.for_geography(geography)
            logger.info(f"Added {len(geography.schools) if geography.schools else 0} schools")
        except Exception as e:
            logger.warning(f"Failed to add schools: {e}")
            geography.schools = None


        # Trying to load universities
        try:
            geography.universities = Universities.for_geography(geography)
            logger.info(f"Added {len(geography.universities) if geography.universities else 0} universities")
        except Exception as e:
            logger.warning(f"Failed to add universities: {e}")
            geography.universities = None

        # Trying to load care homes
        try:
            logger.info("Starting care homes loading with detailed debugging...")
            geography.care_homes = CareHomes.for_geography(geography)
            logger.info(f"Added {len(geography.care_homes) if geography.care_homes else 0} care homes")
        except Exception as e:
            logger.error(f"Failed to add care homes: {e}")
            geography.care_homes = None


        # Trying to load student dorms
        try:
            geography.student_dorms = StudentDorms.for_geography(geography)
            logger.info(f"Added {len(geography.student_dorms) if geography.student_dorms else 0} student dorms")
        except Exception as e:
            logger.warning(f"Failed to add student dorms: {e}")
            geography.student_dorms = None

        # Trying to load boarding_schools
        try:
            geography.boarding_schools = BoardingSchools.for_geography(geography)
            logger.info(f"Added {len(geography.boarding_schools) if geography.boarding_schools else 0} boarding schools")
        except Exception as e:
            logger.warning(f"Failed to add boarding schools: {e}")
            geography.boarding_schools = None

    except Exception as e:
        logger.error(f"Failed to create geography: {e}")
        raise

    return geography

main()

Source code in example_scripts/create_world_2.py
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
def main():
    """ """
    t1 = time.time()
    logger.info("Starting world creation process...")


    # Setting up the disease configuration
    disease_config = set_up_disease_config(disease_name = "ev-d68-v")

    # Sets up a profiler
    profiler = cProfile.Profile()
    profiler.enable()

    logger.info("Setting up geographic locations and boundaries")
    SAs_to_load = geography_choice_step(choice = 2)

    # Creates the geographic information of the world. e.g. where areas are, pubs, etc.
    geography = geography_loading(SAs_to_load)

    # Slow step --- trying to generate the world from the geography and demographic information. 
    try:
        world = generate_world_from_geography(geography,
                                              include_households=True)
        logger.info("World successfully generated from geography.")
    except Exception as e:
        logger.error(f"Error generating world from geography: {e}")
        raise


    # Initialise leisure stuff if it doesn't exist already
    try:
        # Initialise leisure venues if they don't exist
        world.pubs = Pubs.for_geography(geography)
        world.cinemas = Cinemas.for_geography(geography)
        world.groceries = Groceries.for_geography(geography)
        world.gyms = Gyms.for_geography(geography)

        # Generate and distribute leisure activities
        leisure = generate_leisure_for_config(world)
        leisure.distribute_social_venues_to_areas(
            areas=world.areas, super_areas=world.super_areas
        )  # this assigns possible social venues to people.
        logger.info("Leisure activities successfully added to world.")
    except Exception as e:
        logger.warning(f"Warning: Error adding leisure activities: {e}")
        logger.warning("Continuing without complete leisure facilities.")



    # Try to initalise the ability for people to move around the world, and travel from one area to another area. 
    try:
        travel = Travel()
        travel.initialise_commute(world)
        logger.info("Travel and commuting successfully initialised.")
    except Exception as e:
        logger.warning(f"Warning: Error initialising travel and commuting: {e}")
        logger.warning("Continuing without complete travel functionality.")


    t2 = time.time()
    runtime = t2 - t1
    logger.info(f"World creation completed in {runtime:.2f} seconds")


    # Saving the file

    try:
        t1 = time.time()
        logger.info("Saving world to HDF5 file...")
        world.to_hdf5("my_world.hdf5")
        logger.info("World successfully saved to tests.hdf5")
        logger.info("World creation process completed successfully")
        logger.info("Done :)")
        runtime = time.time() - t1
        logger.info(f"World hdf5 file written in {runtime:.2f} seconds")
    except Exception as e:
        logger.error(f"Error saving world to HDF5: {e}")
        logger.warning("World creation completed but saving failed.")


    # Saving the profiling data
    try:
        profiler.disable()
        stats = pstats.Stats(profiler).sort_stats('cumulative')
        profile_filename = 'simulation_profile.stats'
        stats.dump_stats(profile_filename)
        logger.info(f"Performance profiling data saved to {profile_filename}")
    except Exception as e:
        logger.error(f"Failed to save profiling data: {e}")


    logger.info("Script execution completed")

set_up_disease_config(disease_name='ev-d68-v')

Creates an object which loads and parses disease-specific managers for things like interactions, symptoms, vaccinations, and policies. It essentially manages the agent-level effects and transmission of the disease.

Parameters:

Name Type Description Default
disease_name str

str (Default value = "ev-d68-v")

'ev-d68-v'

Returns:

Name Type Description
DiseaseConfig DiseaseConfig

disease_config DiseaseConfig: an object that manages the configuration of a specific disease.

Source code in example_scripts/create_world_2.py
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
def set_up_disease_config(disease_name: str = "ev-d68-v") -> DiseaseConfig:
    """Creates an object which loads and parses disease-specific managers for things like interactions, symptoms, vaccinations, and policies. It essentially manages the agent-level effects and transmission of the disease.

    Args:
        disease_name (str, optional): str (Default value = "ev-d68-v")

    Returns:
        DiseaseConfig: disease_config DiseaseConfig: an object that manages the configuration of a specific disease.
    """

    # Start the timing
    t1 = time.time()

    # default config path
    logger.info("Setting up disease configuration")
    config_path = os.path.join(os.path.dirname(__file__), "../june/configs/config_simulation.yaml")
    logger.info(f"Using config from: {config_path}")

    try:
        disease_config = DiseaseConfig(disease_name, config_path)
        GlobalContext.set_disease_config(disease_config)
        logger.info(f"Successfully loaded disease configuration for {disease_name}")
    except Exception as e:
        logger.error(f"Failed to load disease configuration: {e}")
        raise

    return disease_config