7. Advanced simulation: Population fitting and subcatchment aggregation¶
The examples up to this point have focused on demonstrating the different features an object types within pySIMDEUM using a small collection of houses at most. However, in practice, pySIMDEUM is likely to be used to simulate large number of houses at once and built a representation of water usage, and/or discharge of wastewater into the sewer network.
We will cover two scenarios here:
- A manual way, simulating multiple houses using demographic stats from your config files.
- Simulate multiple houses using
build_multi_hh()method in the api if the occupancy type of a household is already known. - A more advanced method in which we use census population counts and boundaries to fit occupancy type to specific house locations, and then simulate based on these occupancy types. A further step of using subcatchment boundaries to aggregate household wastewater profiles is also included.
1) Manual method: config file demographic stats¶
In other examples, you will notice that we have used the built_house() method to generate a house, we can use a similar structure of code to achieve this for multiple houses.
import pysimdeum
from pysimdeum.core.house import Property
from pysimdeum.core.statistics import Statistics
houses = []
number_of_houses = 3
for _i in range(number_of_houses):
stats = Statistics()
prop = Property(statistics=stats)
house = prop.built_house()
house.populate_house()
house.furnish_house()
for user in house.users:
user.compute_presence(statistics=stats)
house.simulate()
houses.append(house)
houses
[House: id = a8c91095-f783-40b9-abed-8137f2bf35b1 type = family user = 5 appliances = ['WcNewSave', 'Bathtub', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'OutsideTap', 'NormalShower', 'WashingMachine'], House: id = a8c91095-f783-40b9-abed-8137f2bf35b1 type = two_person user = 2 appliances = ['WcNormal', 'Bathtub', 'BathroomTap', 'KitchenTap', 'FancyShower', 'WashingMachine'], House: id = a8c91095-f783-40b9-abed-8137f2bf35b1 type = two_person user = 2 appliances = ['WcNormal', 'BathroomTap', 'KitchenTap', 'OutsideTap', 'NormalShower', 'WashingMachine']]
You can access each House object from the houses list as normal and view plot or write files.
houses[0].consumption.sum(["user","enduse","patterns"]).sel(flowtypes="totalflow").plot()
[<matplotlib.lines.Line2D at 0x166118550>]
2) build_multi_hh() method¶
This method assumes you have a list of houses with unique ids and occupancy type pre-assigned. In our case we will just generate a demo dictionary of what this input might look like so the expected input format is clear.
household_dict = {
"hh_1": "one_person",
"hh_2": "two_person",
"hh_3": "family"
}
household_dict
{'hh_1': 'one_person', 'hh_2': 'two_person', 'hh_3': 'family'}
You can provide the regular inputs on simulation duration, inclusion of discharge and use of spillover feature. Notice the house ids and occupancy type being carried through the simulation into the House objects.
houses = pysimdeum.build_multi_hh(
household_data=household_dict,
duration='1 day',
country='UK',
simulate_discharge=False,
spillover=False
)
houses
{'hh_1': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNewSave', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'OutsideTap', 'FancyShower', 'WashingMachine'],
'hh_2': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = two_person
user = 2
appliances = ['WcNewSave', 'BathroomTap', 'KitchenTap', 'NormalShower', 'WashingMachine'],
'hh_3': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = family
user = 3
appliances = ['WcNormal', 'Bathtub', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'OutsideTap', 'NormalShower', 'WashingMachine']}
3) Population method: population fitting and subcatchment aggregation¶
This final method provides a way of feeding in granular census population counts for boundaries within your study area. In the UK, this might look like providing output area boundaries and their population counts as well as house locations. An extra file representing subcatchments is included to help aggregate household wastewater profiles together.
This method is supported by the DataPrep class and spatial_config.toml which together help prepare the various input files needed for this method into a standardised format that works with the Population method.
Data files needed and their expected columns are:
- Census boundaries file (e.g.
.geojson)- census boundary ids
- geometry
- Census population count (with ids matching boundaries file)
- census boundary ids
- population count
- House location points (unique ids)
- ids
- building type (assuming file includes mix of resi and non-resi)
- Subcatchment boundaries (e.g.
.geojson)- ids
- geometry
The DataPrep class and spatial_config.toml essentially help map column ids from your raw dataset to the expected inputs for the Population method. We can read in the config file to just understand the different sections. The first section dataset is the file path to each of your respective files.
import os
import toml
from pysimdeum.data import DATA_DIR
from pysimdeum.core.population import DataPrep, Population
import folium
spatial_config = toml.load(os.path.join(DATA_DIR, "UK", 'spatial_config.toml'))
spatial_config['datasets']
{'subcatchments': 'data/subcatchments.geojson',
'boundaries': 'data/oa.geojson',
'boundaries_pop': 'data/oa_population.csv',
'houses': 'data/houses.geojson'}
The user will need to map their file specific columns to the expected column names. Essentially, the key (left) is the expected name (do not change that), and the corresponding value (right) is the file specific name. In the example below, my subcatchments file has a column called subcatchme that is being mapped to subcatchment_id.
spatial_config['columns']
{'subcatchments': {'geometry': 'geometry', 'subcatchment_id': 'subcatchme'},
'boundaries': {'geometry': 'geometry', 'boundary_id': 'OA21CD'},
'boundaries_pop': {'boundary_id_code': 'OA 2021 Code', 'population': 'Total'},
'houses': {'geometry': 'geometry',
'house_id': 'TOID',
'function': 'BaseFuncti'}}
DataPrep prepares the input data into a generalised format based on the mapping instructions from spatial_config.toml
data_prep = DataPrep(country='UK')
Initialising a Population class with the DataPrep instance as an input, combined with the usual arguments when simulating houses will set off a series of actions that assign occupancy types to household locations that fit against census population counts for the inputted boundaries. An additional argument, sample is used to run the process for 10 randomly sampled houses contained within the study area.
pop = Population(datasets = data_prep.datasets, sample=True, country='UK', simulate_discharge=True, spillover=False)
Now contained with pop (Population instance) is house_instances which is a dictionary of house ids and their House instance containing the usual information of a house including the simulation objects.
pop.houses_instances
{'hh252': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNormal', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'NormalShower', 'WashingMachine'],
'hh251': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = family
user = 5
appliances = ['WcNewSave', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'FancyShower', 'WashingMachine'],
'hh205': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = family
user = 4
appliances = ['WcNormalSave', 'BathroomTap', 'KitchenTap', 'FancyShower', 'WashingMachine'],
'hh174': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNormal', 'BathroomTap', 'KitchenTap', 'FancyShower', 'WashingMachine'],
'hh179': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = two_person
user = 2
appliances = ['WcNew', 'BathroomTap', 'KitchenTap', 'OutsideTap', 'FancyShower', 'WashingMachine'],
'hh6': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNormal', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'FancyShower', 'WashingMachine'],
'hh77': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = two_person
user = 2
appliances = ['WcNewSave', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'OutsideTap', 'NormalShower', 'WashingMachine'],
'hh99': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNormal', 'BathroomTap', 'KitchenTap', 'OutsideTap', 'NormalShower', 'WashingMachine'],
'hh186': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNew', 'BathroomTap', 'KitchenTap', 'OutsideTap', 'FancyShower', 'WashingMachine'],
'hh257': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNew', 'Bathtub', 'BathroomTap', 'KitchenTap', 'OutsideTap', 'NormalShower', 'WashingMachine']}
You can also access a dictionary of the subcatchments and the houses contained within that area. This is used to then aggregate household wastewater profiles to subcatchment level.
pop.subcatchment_houses
{'SO40511701.1': ['hh188'],
'SO40511750': ['hh154', 'hh246'],
'SO40511801': ['hh165', 'hh174', 'hh244'],
'SO40511801.1': ['hh163'],
'SO40512602': ['hh168', 'hh191', 'hh205'],
'SO40512701': ['hh179'],
'SO40512704': ['hh148', 'hh214'],
'SO40512801': ['hh185', 'hh186', 'hh211', 'hh257'],
'SO40513702': ['hh138'],
'SO40513802': ['hh151', 'hh234'],
'SO40514301': ['hh71', 'hh77'],
'SO40514403': ['hh4', 'hh22'],
'SO40514503': ['hh23', 'hh25', 'hh76'],
'SO40514704': ['hh248', 'hh251'],
'SO40514705': ['hh146', 'hh203', 'hh228', 'hh255', 'hh260'],
'SO40514801': ['hh183', 'hh196', 'hh245', 'hh259'],
'SO40515201': ['hh16', 'hh34'],
'SO40515502': ['hh6',
'hh27',
'hh30',
'hh48',
'hh65',
'hh99',
'hh106',
'hh127'],
'SO40515601!': ['hh141', 'hh142', 'hh206', 'hh215', 'hh252'],
'SO40515603.1': ['hh128'],
'SO40516401': ['hh2',
'hh31',
'hh32',
'hh39',
'hh43',
'hh44',
'hh53',
'hh59',
'hh85',
'hh91',
'hh93',
'hh112',
'hh113',
'hh123'],
'SO40517304': ['hh49', 'hh98', 'hh101', 'hh111'],
'XXXX000004': ['hh9', 'hh60', 'hh61', 'hh115']}
pop.subcatchment_profiles
{'SO40511801': <xarray.DataArray (time: 86401, patterns: 1)> Size: 691kB
array([[0.],
[0.],
[0.],
...,
[0.],
[0.],
[0.]])
Coordinates:
* time (time) datetime64[ns] 691kB 2026-03-12 ... 2026-03-13
* patterns (patterns) int64 8B 0
flowtypes <U9 36B 'totalflow',
'SO40512602': <xarray.DataArray (time: 86401, patterns: 1)> Size: 691kB
array([[0.],
[0.],
[0.],
...,
[0.],
[0.],
[0.]])
Coordinates:
* time (time) datetime64[ns] 691kB 2026-03-12 ... 2026-03-13
* patterns (patterns) int64 8B 0
flowtypes <U9 36B 'totalflow',
'SO40512701': <xarray.DataArray (time: 86401, patterns: 1)> Size: 691kB
array([[0.],
[0.],
[0.],
...,
[0.],
[0.],
[0.]])
Coordinates:
* time (time) datetime64[ns] 691kB 2026-03-12 ... 2026-03-13
* patterns (patterns) int64 8B 0
flowtypes <U9 36B 'totalflow',
'SO40512801': <xarray.DataArray (time: 86401, patterns: 1)> Size: 691kB
array([[0.],
[0.],
[0.],
...,
[0.],
[0.],
[0.]])
Coordinates:
* time (time) datetime64[ns] 691kB 2026-03-12 ... 2026-03-13
* patterns (patterns) int64 8B 0
flowtypes <U9 36B 'totalflow',
'SO40514301': <xarray.DataArray (time: 86401, patterns: 1)> Size: 691kB
array([[0.],
[0.],
[0.],
...,
[0.],
[0.],
[0.]])
Coordinates:
* time (time) datetime64[ns] 691kB 2026-03-12 ... 2026-03-13
* patterns (patterns) int64 8B 0
flowtypes <U9 36B 'totalflow',
'SO40514704': <xarray.DataArray (time: 86401, patterns: 1)> Size: 691kB
array([[0.],
[0.],
[0.],
...,
[0.],
[0.],
[0.]])
Coordinates:
* time (time) datetime64[ns] 691kB 2026-03-12 ... 2026-03-13
* patterns (patterns) int64 8B 0
flowtypes <U9 36B 'totalflow',
'SO40515502': <xarray.DataArray (time: 86401, patterns: 1)> Size: 691kB
array([[0.],
[0.],
[0.],
...,
[0.],
[0.],
[0.]])
Coordinates:
* time (time) datetime64[ns] 691kB 2026-03-12 ... 2026-03-13
* patterns (patterns) int64 8B 0
flowtypes <U9 36B 'totalflow',
'SO40515601!': <xarray.DataArray (time: 86401, patterns: 1)> Size: 691kB
array([[0.],
[0.],
[0.],
...,
[0.],
[0.],
[0.]])
Coordinates:
* time (time) datetime64[ns] 691kB 2026-03-12 ... 2026-03-13
* patterns (patterns) int64 8B 0
flowtypes <U9 36B 'totalflow'}
pop.subcatchment_profiles[next(iter(pop.subcatchment_profiles))].plot()
[<matplotlib.lines.Line2D at 0x16a58a610>]
pop.houses_instances
{'hh252': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNormal', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'NormalShower', 'WashingMachine'],
'hh251': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = family
user = 5
appliances = ['WcNewSave', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'FancyShower', 'WashingMachine'],
'hh205': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = family
user = 4
appliances = ['WcNormalSave', 'BathroomTap', 'KitchenTap', 'FancyShower', 'WashingMachine'],
'hh174': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNormal', 'BathroomTap', 'KitchenTap', 'FancyShower', 'WashingMachine'],
'hh179': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = two_person
user = 2
appliances = ['WcNew', 'BathroomTap', 'KitchenTap', 'OutsideTap', 'FancyShower', 'WashingMachine'],
'hh6': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNormal', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'FancyShower', 'WashingMachine'],
'hh77': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = two_person
user = 2
appliances = ['WcNewSave', 'BathroomTap', 'Dishwasher', 'KitchenTap', 'OutsideTap', 'NormalShower', 'WashingMachine'],
'hh99': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNormal', 'BathroomTap', 'KitchenTap', 'OutsideTap', 'NormalShower', 'WashingMachine'],
'hh186': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNew', 'BathroomTap', 'KitchenTap', 'OutsideTap', 'FancyShower', 'WashingMachine'],
'hh257': House:
id = a8c91095-f783-40b9-abed-8137f2bf35b1
type = one_person
user = 1
appliances = ['WcNew', 'Bathtub', 'BathroomTap', 'KitchenTap', 'OutsideTap', 'NormalShower', 'WashingMachine']}
pop.houses_instances[next(iter(pop.houses_instances))].consumption.sum(['enduse', 'user']).sel(flowtypes='totalflow').mean(['patterns']).plot()
[<matplotlib.lines.Line2D at 0x173423510>]
pop.houses_instances[next(iter(pop.houses_instances))].discharge.discharge.sum(['enduse', 'user', 'dischargetypes']).mean(['patterns']).plot()
[<matplotlib.lines.Line2D at 0x173493510>]
All the objects are still accessible. Here we can view the subcatchments and the houses contained within them, categorised by the occupancy type.
m = pop.subcatchments.explore(name='houses')
pop.houses.explore(m=m, name='houses', column='occupancy_type')
folium.LayerControl().add_to(m)
m
The Population class is designed to work with Infoworks ICM. The subcatchment structure and groupings work with how wastewater profiles are handled within Infoworks. As a result, a method is included to take aggregated subcatchment wastewater profiles and export them into a specific .csv format expected for wastewater profiles within Infoworks.
As part of the population object, automatic aggregation of wastewater profiles to subcatchment levels are included and held within Population.subcatchment_ww_profiles. They are accessible as below.
pop.subcatchment_ww_profiles
{'SO40511801': {'daily_flow': {datetime.date(2026, 3, 12): 155.4717899636809},
'hourly_average': {datetime.date(2026, 3, 12): 6.4779912484867035},
'ww_profile': time flow n p cod bod5 \
0 2026-03-12 00:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
1 2026-03-12 01:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
2 2026-03-12 02:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
3 2026-03-12 03:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
4 2026-03-12 04:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
5 2026-03-12 05:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
6 2026-03-12 06:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
7 2026-03-12 07:00:00 26.471602 0.231971 0.068411 1.664716 1.012815
8 2026-03-12 08:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
9 2026-03-12 09:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
10 2026-03-12 10:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
11 2026-03-12 11:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
12 2026-03-12 12:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
13 2026-03-12 13:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
14 2026-03-12 14:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
15 2026-03-12 15:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
16 2026-03-12 16:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
17 2026-03-12 17:00:00 13.996595 0.200009 0.122547 2.918388 1.603583
18 2026-03-12 18:00:00 63.588954 0.063809 0.070893 1.833808 1.069897
19 2026-03-12 19:00:00 30.536556 0.156158 0.490700 4.803266 1.820198
20 2026-03-12 20:00:00 19.341753 0.174901 0.757558 5.037899 2.662572
21 2026-03-12 21:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
22 2026-03-12 22:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
23 2026-03-12 23:00:00 1.536330 0.242944 0.247348 6.585729 4.543288
ss amm
0 0.000000 0.000000
1 0.000000 0.000000
2 0.000000 0.000000
3 0.000000 0.000000
4 0.000000 0.000000
5 0.000000 0.000000
6 0.000000 0.000000
7 0.719544 0.094396
8 0.000000 0.000000
9 0.000000 0.000000
10 0.000000 0.000000
11 0.000000 0.000000
12 0.000000 0.000000
13 0.000000 0.000000
14 0.000000 0.000000
15 0.000000 0.000000
16 0.000000 0.000000
17 1.508951 0.060392
18 1.326954 0.007961
19 1.063365 0.067116
20 1.470530 0.099937
21 0.000000 0.000000
22 0.000000 0.000000
23 2.706736 0.023941 },
'SO40512602': {'daily_flow': {datetime.date(2026, 3, 12): 267.1731724950427},
'hourly_average': {datetime.date(2026, 3, 12): 11.13221552062678},
'ww_profile': time flow n p cod \
0 2026-03-12 00:00:00 0.000000 0.000000 0.000000 0.000000
1 2026-03-12 01:00:00 14.400000 0.387725 0.049758 2.826914
2 2026-03-12 02:00:00 0.000000 0.000000 0.000000 0.000000
3 2026-03-12 03:00:00 0.000000 0.000000 0.000000 0.000000
4 2026-03-12 04:00:00 0.000000 0.000000 0.000000 0.000000
5 2026-03-12 05:00:00 0.000000 0.000000 0.000000 0.000000
6 2026-03-12 06:00:00 28.235336 0.376545 0.067627 2.584905
7 2026-03-12 07:00:00 50.479803 0.278243 0.049175 1.149973
8 2026-03-12 08:00:00 6.894210 0.108087 0.082831 2.974553
9 2026-03-12 09:00:00 0.675539 0.031296 0.088578 1.248120
10 2026-03-12 10:00:00 0.075998 0.031296 0.088578 1.248120
11 2026-03-12 11:00:00 0.000000 0.000000 0.000000 0.000000
12 2026-03-12 12:00:00 0.000000 0.000000 0.000000 0.000000
13 2026-03-12 13:00:00 15.474431 0.529938 0.091093 2.250261
14 2026-03-12 14:00:00 0.860750 0.399811 0.456682 12.137732
15 2026-03-12 15:00:00 9.600000 0.421211 0.032852 0.276769
16 2026-03-12 16:00:00 0.015342 28.590094 16.840708 111.533480
17 2026-03-12 17:00:00 6.026289 0.752944 0.132616 5.528720
18 2026-03-12 18:00:00 24.982320 0.100128 0.041743 1.123061
19 2026-03-12 19:00:00 5.702172 0.422330 0.103543 2.129118
20 2026-03-12 20:00:00 10.627837 0.160677 0.057781 0.383542
21 2026-03-12 21:00:00 5.095056 0.411737 0.118760 0.745782
22 2026-03-12 22:00:00 83.228090 0.077010 0.014072 0.359514
23 2026-03-12 23:00:00 4.800000 0.280285 0.011034 0.433581
bod5 ss amm
0 0.000000 0.000000 0.000000
1 0.720466 0.103422 0.179822
2 0.000000 0.000000 0.000000
3 0.000000 0.000000 0.000000
4 0.000000 0.000000 0.000000
5 0.000000 0.000000 0.000000
6 1.454256 0.316047 0.176547
7 0.628286 0.217085 0.111084
8 1.403091 1.212282 0.007946
9 0.345222 0.280066 0.001157
10 0.345222 0.280066 0.001157
11 0.000000 0.000000 0.000000
12 0.000000 0.000000 0.000000
13 1.416541 0.604041 0.148211
14 9.113663 4.582520 0.021124
15 0.608290 0.000000 0.237386
16 259.685714 248.908324 2.023171
17 2.042645 1.036798 0.194226
18 0.632428 0.513451 0.039795
19 1.725746 0.724185 0.136027
20 0.421458 0.071466 0.077765
21 0.456625 0.033434 0.262223
22 0.260814 0.263247 0.037144
23 0.571610 0.000000 0.171574 },
'SO40512701': {'daily_flow': {datetime.date(2026, 3, 12): 186.62263141010268},
'hourly_average': {datetime.date(2026, 3, 12): 7.7759429754209455},
'ww_profile': time flow n p cod bod5 \
0 2026-03-12 00:00:00 39.120000 0.049782 0.007316 0.520772 0.216010
1 2026-03-12 01:00:00 15.817767 0.318309 0.028848 0.349249 0.256520
2 2026-03-12 02:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
3 2026-03-12 03:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
4 2026-03-12 04:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
5 2026-03-12 05:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
6 2026-03-12 06:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
7 2026-03-12 07:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
8 2026-03-12 08:00:00 3.248536 0.162548 0.099321 2.182596 1.988335
9 2026-03-12 09:00:00 14.400000 0.124217 0.034505 0.391149 0.470922
10 2026-03-12 10:00:00 14.400000 0.419651 0.020011 2.801744 1.459554
11 2026-03-12 11:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
12 2026-03-12 12:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
13 2026-03-12 13:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
14 2026-03-12 14:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
15 2026-03-12 15:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
16 2026-03-12 16:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
17 2026-03-12 17:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
18 2026-03-12 18:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
19 2026-03-12 19:00:00 70.645405 0.074008 0.010745 0.337332 0.169751
20 2026-03-12 20:00:00 3.651761 0.081535 0.078593 2.470101 0.836562
21 2026-03-12 21:00:00 16.580643 0.297522 0.058528 0.822048 0.708877
22 2026-03-12 22:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
23 2026-03-12 23:00:00 8.758519 0.121386 0.065609 0.696508 0.459935
ss amm
0 0.263317 0.027964
1 0.008992 0.102696
2 0.000000 0.000000
3 0.000000 0.000000
4 0.000000 0.000000
5 0.000000 0.000000
6 0.000000 0.000000
7 0.000000 0.000000
8 1.213828 0.008491
9 0.000000 0.094616
10 0.200062 0.173721
11 0.000000 0.000000
12 0.000000 0.000000
13 0.000000 0.000000
14 0.000000 0.000000
15 0.000000 0.000000
16 0.000000 0.000000
17 0.000000 0.000000
18 0.000000 0.000000
19 0.125628 0.035252
20 1.123256 0.004564
21 0.321970 0.098010
22 0.000000 0.000000
23 0.094790 0.101015 },
'SO40512801': {'daily_flow': {datetime.date(2026, 3, 12): 171.6369448864725},
'hourly_average': {datetime.date(2026, 3, 12): 7.1515393702696874},
'ww_profile': time flow n p cod bod5 \
0 2026-03-12 00:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
1 2026-03-12 01:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
2 2026-03-12 02:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
3 2026-03-12 03:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
4 2026-03-12 04:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
5 2026-03-12 05:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
6 2026-03-12 06:00:00 9.199008 0.094126 0.072404 1.368027 0.726015
7 2026-03-12 07:00:00 20.395687 0.261483 0.093909 2.664712 1.661777
8 2026-03-12 08:00:00 20.385648 0.291362 0.070275 1.450791 1.093182
9 2026-03-12 09:00:00 0.152236 6.634371 3.996598 119.769846 56.237264
10 2026-03-12 10:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
11 2026-03-12 11:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
12 2026-03-12 12:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
13 2026-03-12 13:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
14 2026-03-12 14:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
15 2026-03-12 15:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
16 2026-03-12 16:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
17 2026-03-12 17:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
18 2026-03-12 18:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
19 2026-03-12 19:00:00 60.801472 0.147559 0.019782 0.848670 0.453362
20 2026-03-12 20:00:00 21.600000 0.360486 0.047563 1.445595 0.747996
21 2026-03-12 21:00:00 0.026002 1.316704 3.618171 51.792236 29.984709
22 2026-03-12 22:00:00 15.045249 0.392581 0.081667 3.399840 1.075444
23 2026-03-12 23:00:00 24.031643 0.295550 0.048932 1.198345 0.916123
ss amm
0 0.000000 0.000000
1 0.000000 0.000000
2 0.000000 0.000000
3 0.000000 0.000000
4 0.000000 0.000000
5 0.000000 0.000000
6 0.859472 0.007924
7 1.945413 0.123646
8 1.070262 0.101291
9 59.090473 0.337303
10 0.000000 0.000000
11 0.000000 0.000000
12 0.000000 0.000000
13 0.000000 0.000000
14 0.000000 0.000000
15 0.000000 0.000000
16 0.000000 0.000000
17 0.000000 0.000000
18 0.000000 0.000000
19 0.338143 0.047088
20 0.102292 0.142100
21 10.307220 0.073588
22 0.548771 0.169318
23 0.196787 0.114968 },
'SO40514301': {'daily_flow': {datetime.date(2026, 3, 12): 158.5908016953076},
'hourly_average': {datetime.date(2026, 3, 12): 6.607950070637816},
'ww_profile': time flow n p cod bod5 \
0 2026-03-12 00:00:00 13.835607 0.572689 0.079963 2.690980 1.684493
1 2026-03-12 01:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
2 2026-03-12 02:00:00 7.200000 0.341632 0.023180 0.392527 0.152061
3 2026-03-12 03:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
4 2026-03-12 04:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
5 2026-03-12 05:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
6 2026-03-12 06:00:00 4.719068 0.304171 0.053544 0.706924 0.500547
7 2026-03-12 07:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
8 2026-03-12 08:00:00 24.844449 0.309465 0.073984 0.986183 0.775116
9 2026-03-12 09:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
10 2026-03-12 10:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
11 2026-03-12 11:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
12 2026-03-12 12:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
13 2026-03-12 13:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
14 2026-03-12 14:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
15 2026-03-12 15:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
16 2026-03-12 16:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
17 2026-03-12 17:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
18 2026-03-12 18:00:00 31.870869 0.387126 0.108444 3.485081 2.017716
19 2026-03-12 19:00:00 8.751750 0.450736 0.813197 10.914582 5.170675
20 2026-03-12 20:00:00 7.200000 0.295339 0.037142 0.282828 0.127008
21 2026-03-12 21:00:00 4.397088 0.601988 0.107552 1.302217 0.453483
22 2026-03-12 22:00:00 3.691971 0.994087 0.140766 8.583937 3.633048
23 2026-03-12 23:00:00 52.080000 0.008903 0.001555 0.341624 0.175244
ss amm
0 0.255662 0.273969
1 0.000000 0.000000
2 0.000000 0.176383
3 0.000000 0.000000
4 0.000000 0.000000
5 0.000000 0.000000
6 0.084049 0.226932
7 0.000000 0.000000
8 0.342551 0.155722
9 0.000000 0.000000
10 0.000000 0.000000
11 0.000000 0.000000
12 0.000000 0.000000
13 0.000000 0.000000
14 0.000000 0.000000
15 0.000000 0.000000
16 0.000000 0.000000
17 0.000000 0.000000
18 1.026707 0.152286
19 3.794232 0.296725
20 0.000000 0.055866
21 0.142294 0.107172
22 0.961822 0.200360
23 0.404537 0.001227 },
'SO40514704': {'daily_flow': {datetime.date(2026, 3, 12): 196.21438389580598},
'hourly_average': {datetime.date(2026, 3, 12): 8.175599328991916},
'ww_profile': time flow n p cod bod5 \
0 2026-03-12 00:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
1 2026-03-12 01:00:00 7.899867 0.553469 0.081747 0.887290 0.728707
2 2026-03-12 02:00:00 50.172452 0.008680 0.008269 0.269526 0.174314
3 2026-03-12 03:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
4 2026-03-12 04:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
5 2026-03-12 05:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
6 2026-03-12 06:00:00 7.227342 0.449022 0.073843 0.875855 0.777423
7 2026-03-12 07:00:00 7.683800 0.423770 0.135695 2.175924 1.146671
8 2026-03-12 08:00:00 7.550056 0.016394 0.031057 0.564540 0.285129
9 2026-03-12 09:00:00 61.677211 0.056827 0.023318 0.520418 0.327672
10 2026-03-12 10:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
11 2026-03-12 11:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
12 2026-03-12 12:00:00 3.600000 0.652287 0.050884 0.346160 0.679834
13 2026-03-12 13:00:00 4.983686 0.395163 0.106727 2.415638 1.223543
14 2026-03-12 14:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
15 2026-03-12 15:00:00 0.423065 0.166981 0.721688 3.993650 3.412218
16 2026-03-12 16:00:00 3.515023 0.190058 0.096475 3.717186 2.553952
17 2026-03-12 17:00:00 2.275471 0.356831 0.472371 7.751955 4.323032
18 2026-03-12 18:00:00 10.800000 0.619321 0.082485 2.530907 1.214583
19 2026-03-12 19:00:00 0.115080 0.295801 0.805660 11.467233 8.085312
20 2026-03-12 20:00:00 2.702229 0.039621 0.126115 1.458977 0.632728
21 2026-03-12 21:00:00 5.054176 0.348812 0.111444 1.387918 1.233051
22 2026-03-12 22:00:00 7.200000 0.565137 0.067804 0.476548 0.747033
23 2026-03-12 23:00:00 13.334926 0.236619 0.040156 0.346514 0.243214
ss amm
0 0.000000 0.000000
1 0.068153 0.226295
2 0.346313 0.001011
3 0.000000 0.000000
4 0.000000 0.000000
5 0.000000 0.000000
6 0.045728 0.277901
7 0.980904 0.103646
8 0.398408 0.001269
9 0.353251 0.040575
10 0.000000 0.000000
11 0.000000 0.000000
12 0.000000 0.379755
13 1.297626 0.228376
14 0.000000 0.000000
15 1.939474 0.009295
16 2.312298 0.014822
17 5.508751 0.028193
18 0.454140 0.213772
19 5.160278 0.004713
20 0.183330 0.001359
21 0.218442 0.093965
22 0.000000 0.211491
23 0.062727 0.086321 },
'SO40515502': {'daily_flow': {datetime.date(2026, 3, 12): 279.7071242225466},
'hourly_average': {datetime.date(2026, 3, 12): 11.654463509272775},
'ww_profile': time flow n p cod bod5 \
0 2026-03-12 00:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
1 2026-03-12 01:00:00 9.600000 0.206313 0.023584 0.204795 0.214710
2 2026-03-12 02:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
3 2026-03-12 03:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
4 2026-03-12 04:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
5 2026-03-12 05:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
6 2026-03-12 06:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
7 2026-03-12 07:00:00 145.188999 0.002933 0.001063 0.141201 0.055109
8 2026-03-12 08:00:00 11.284000 0.002584 0.000385 0.128970 0.048019
9 2026-03-12 09:00:00 3.287520 0.027504 0.074660 1.133970 0.644312
10 2026-03-12 10:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
11 2026-03-12 11:00:00 14.479853 0.276911 0.073966 1.491657 0.906541
12 2026-03-12 12:00:00 8.741907 0.063210 0.087265 2.585914 0.952273
13 2026-03-12 13:00:00 10.379983 0.224063 0.065497 0.868128 0.778142
14 2026-03-12 14:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
15 2026-03-12 15:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
16 2026-03-12 16:00:00 61.338830 0.068084 0.025711 0.879407 0.457227
17 2026-03-12 17:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
18 2026-03-12 18:00:00 12.979922 0.267363 0.075194 1.754084 1.203042
19 2026-03-12 19:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
20 2026-03-12 20:00:00 0.308155 0.157586 0.409513 3.097194 3.419004
21 2026-03-12 21:00:00 0.452630 0.122528 0.382540 1.711209 2.609037
22 2026-03-12 22:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
23 2026-03-12 23:00:00 1.665325 0.047362 0.123592 2.034100 1.207917
ss amm
0 0.000000 0.000000
1 0.000000 0.052517
2 0.000000 0.000000
3 0.000000 0.000000
4 0.000000 0.000000
5 0.000000 0.000000
6 0.000000 0.000000
7 0.079107 0.000284
8 0.076342 0.000269
9 0.212836 0.001414
10 0.000000 0.000000
11 0.727078 0.040020
12 0.877165 0.006849
13 0.474926 0.125577
14 0.000000 0.000000
15 0.000000 0.000000
16 0.592628 0.013903
17 0.000000 0.000000
18 0.919313 0.086815
19 0.000000 0.000000
20 1.053300 0.005309
21 1.017765 0.003741
22 0.000000 0.000000
23 0.380297 0.001709 },
'SO40515601!': {'daily_flow': {datetime.date(2026, 3, 12): 112.64034555174489},
'hourly_average': {datetime.date(2026, 3, 12): 4.693347731322704},
'ww_profile': time flow n p cod bod5 \
0 2026-03-12 00:00:00 58.260000 0.070018 0.007261 0.292739 0.302615
1 2026-03-12 01:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
2 2026-03-12 02:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
3 2026-03-12 03:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
4 2026-03-12 04:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
5 2026-03-12 05:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
6 2026-03-12 06:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
7 2026-03-12 07:00:00 0.136612 3.094002 2.230665 51.704340 43.878567
8 2026-03-12 08:00:00 12.070575 0.204095 0.066290 0.994300 0.674535
9 2026-03-12 09:00:00 0.442269 0.937250 0.326155 20.612503 7.754131
10 2026-03-12 10:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
11 2026-03-12 11:00:00 19.247860 0.224426 0.051949 0.681696 0.571306
12 2026-03-12 12:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
13 2026-03-12 13:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
14 2026-03-12 14:00:00 9.600000 0.276142 0.032677 4.414122 1.092307
15 2026-03-12 15:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
16 2026-03-12 16:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
17 2026-03-12 17:00:00 9.979212 0.282050 0.046434 0.830670 0.675733
18 2026-03-12 18:00:00 0.382738 0.062230 0.315437 3.815516 2.501560
19 2026-03-12 19:00:00 0.347206 0.966381 0.528033 26.823434 12.525806
20 2026-03-12 20:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
21 2026-03-12 21:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
22 2026-03-12 22:00:00 0.000000 0.000000 0.000000 0.000000 0.000000
23 2026-03-12 23:00:00 2.173873 0.022130 0.042873 0.689010 0.470102
ss amm
0 0.254550 0.035044
1 0.000000 0.000000
2 0.000000 0.000000
3 0.000000 0.000000
4 0.000000 0.000000
5 0.000000 0.000000
6 0.000000 0.000000
7 35.807116 0.290400
8 0.521744 0.060304
9 11.656394 0.085853
10 0.000000 0.000000
11 0.147103 0.073858
12 0.000000 0.000000
13 0.000000 0.000000
14 0.329710 0.151869
15 0.000000 0.000000
16 0.000000 0.000000
17 0.492160 0.090426
18 0.791844 0.007973
19 16.148967 0.063268
20 0.000000 0.000000
21 0.000000 0.000000
22 0.000000 0.000000
23 0.147511 0.001174 }}
Each subcatchment_ww_profiles dictionary contains a nested dictionary with daily_flow, hourly_average and the actual wastewater profile ww_profile.
pop.subcatchment_ww_profiles[next(iter(pop.subcatchment_ww_profiles))].keys()
dict_keys(['daily_flow', 'hourly_average', 'ww_profile'])
pop.subcatchment_ww_profiles[next(iter(pop.subcatchment_ww_profiles))]['daily_flow']
{datetime.date(2026, 3, 12): 155.4717899636809}
pop.subcatchment_ww_profiles[next(iter(pop.subcatchment_ww_profiles))]['hourly_average']
{datetime.date(2026, 3, 12): 6.4779912484867035}
pop.subcatchment_ww_profiles[next(iter(pop.subcatchment_ww_profiles))]['ww_profile']
| time | flow | n | p | cod | bod5 | ss | amm | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2026-03-12 00:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 1 | 2026-03-12 01:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 2 | 2026-03-12 02:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 3 | 2026-03-12 03:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 4 | 2026-03-12 04:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 5 | 2026-03-12 05:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 6 | 2026-03-12 06:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 7 | 2026-03-12 07:00:00 | 26.471602 | 0.231971 | 0.068411 | 1.664716 | 1.012815 | 0.719544 | 0.094396 |
| 8 | 2026-03-12 08:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 9 | 2026-03-12 09:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 10 | 2026-03-12 10:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 11 | 2026-03-12 11:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 12 | 2026-03-12 12:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 13 | 2026-03-12 13:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 14 | 2026-03-12 14:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 15 | 2026-03-12 15:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 16 | 2026-03-12 16:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 17 | 2026-03-12 17:00:00 | 13.996595 | 0.200009 | 0.122547 | 2.918388 | 1.603583 | 1.508951 | 0.060392 |
| 18 | 2026-03-12 18:00:00 | 63.588954 | 0.063809 | 0.070893 | 1.833808 | 1.069897 | 1.326954 | 0.007961 |
| 19 | 2026-03-12 19:00:00 | 30.536556 | 0.156158 | 0.490700 | 4.803266 | 1.820198 | 1.063365 | 0.067116 |
| 20 | 2026-03-12 20:00:00 | 19.341753 | 0.174901 | 0.757558 | 5.037899 | 2.662572 | 1.470530 | 0.099937 |
| 21 | 2026-03-12 21:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 22 | 2026-03-12 22:00:00 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
| 23 | 2026-03-12 23:00:00 | 1.536330 | 0.242944 | 0.247348 | 6.585729 | 4.543288 | 2.706736 | 0.023941 |
For now, writing to Infoworks ICM csv formatting does not support nutrient concentration and just provides the wastewater flow.
from pysimdeum.tools.write import generate_infoworks_csv
generate_infoworks_csv(pop.subcatchment_ww_profiles, './data/infoworks')