Skip to content

Households stock heat migration - #1800

Merged
kndehaan merged 7 commits into
masterfrom
households-stock-heat-migration
Aug 20, 2026
Merged

Households stock heat migration#1800
kndehaan merged 7 commits into
masterfrom
households-stock-heat-migration

Conversation

@aaccensi

@aaccensi aaccensi commented Aug 13, 2026

Copy link
Copy Markdown
Member

Context

The sliders/inputs for both the Buildings and the Households stock and heat demand are changing, so both need a migration to go along. This PR now carries both, so they can land together in a single merge to master.

The buildings migration was reviewed and approved in #1796; that PR is being closed in favour of this one rather than merged separately.

Implemented changes

  • db/migrate/20260804120000_simplified_buildings_heat_inputs.rb — the buildings migration
  • db/migrate/20260813120000_simplified_households_heat_inputs.rb — the households migration
  • db/migrate/20260813120000_simplified_households_heat_inputs/dataset_values.json — the start-year heat demand of every housing type and construction period, per dataset. The households insulation sliders are averaged by the demand each housing type carries, and that demand is solved by the graph rather than stored in ETSource, so it cannot be recalculated in the migration. Generated with the refinery_dump task in ETSource.
  • db/schema.rb — the schema version (and Rails 8 alphabetical order)
  • db/cache_schema.rb — Rails 8 alphabetical order only

Related

Checklist

  • I have tested these changes
  • I have updated documentation as needed
  • I have tagged the relevant people for review

@aaccensi
aaccensi requested a review from kndehaan August 13, 2026 14:01
@aaccensi

aaccensi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

@kndehaan, I realized that there is one of those cases where things can happen with the data even if it does not make much sense. See the "important note" block in the PR description.

Copy link
Copy Markdown
Member

How is this handled in the migration? I assume that the new value is capped to the maximum value of the new slider, right?

@aaccensi

aaccensi commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

Currently is unhandled. The new slider currently is just populated with the sum of the previous ones, but the frontend cannot display that properly. A decision on this needs to be made and then I will adapt the code accordingly.

kndehaan commented Aug 13, 2026

Copy link
Copy Markdown
Member

Can you cap it to the max slider value? We do not want to allow set user values to be outside the min and max bounds.

Copy link
Copy Markdown
Member Author

Sure, we can do that. For scenario owners it means their scenario may lose the homes above the new limit, which is 1/4th of what was possible before for the entire housing stock.

On our side, in the migration code, besides capping the total we need to scale down the four housing-type numbers along with it, so the shares per housing type still add up to 100%.

@aaccensi
aaccensi force-pushed the households-stock-heat-migration branch 2 times, most recently from 54171ec to 78ad1a0 Compare August 13, 2026 15:37
@kndehaan

Copy link
Copy Markdown
Member

For scenario owners it means their scenario may lose the homes above the new limit, which is 1/4th of what was possible before for the entire housing stock.

I checked the featured scenarios: it's never the case that total nr of new residences exceeds the total nr of existing residences in the start year. So this approach seems fine.

@kndehaan

kndehaan commented Aug 18, 2026

Copy link
Copy Markdown
Member

It came to me that for converting the household_insulation_level* inputs, a different approach should be taken for the future ones and the existing construction periods.

For the future residences, the current approach of weighing the input with number of units, floor area and kWh/m2 is correct since that corresponds with how we determine heat demand for new residences in the future year.

For the existing residences (all existing construction periods), we determine the demand in the future year based on scaling of the demand in the start year. Calculation example:

heat demand start year = 1000 MJ
typical heat demand start year = 60 kWh/m2
typical heat demand future year = 50 kWh/m2
heat demand future year = 50/60 * 1000 MJ = 833 MJ

Doing a similar calculation for the migration requires a data dump of the demand of the relevant nodes in the start year, see below. The data dump needs to contain these values for all datasets. Notifying @louispt1 as well reg the data dump requirement.

Relevant nodes:

households_useful_demand_for_space_heating_apartments_before_1945
households_useful_demand_for_space_heating_detached_houses_before_1945
households_useful_demand_for_space_heating_semi_detached_houses_before_1945
households_useful_demand_for_space_heating_terraced_houses_before_1945
households_useful_demand_for_space_heating_apartments_1945_1964
households_useful_demand_for_space_heating_detached_houses_1945_1964
households_useful_demand_for_space_heating_semi_detached_houses_1945_1964
households_useful_demand_for_space_heating_terraced_houses_1945_1964
households_useful_demand_for_space_heating_apartments_1965_1984
households_useful_demand_for_space_heating_detached_houses_1965_1984
households_useful_demand_for_space_heating_semi_detached_houses_1965_1984
households_useful_demand_for_space_heating_terraced_houses_1965_1984
households_useful_demand_for_space_heating_apartments_1985_2004
households_useful_demand_for_space_heating_detached_houses_1985_2004
households_useful_demand_for_space_heating_semi_detached_houses_1985_2004
households_useful_demand_for_space_heating_terraced_houses_1985_2004
households_useful_demand_for_space_heating_apartments_2005_present
households_useful_demand_for_space_heating_detached_houses_2005_present
households_useful_demand_for_space_heating_semi_detached_houses_2005_present
households_useful_demand_for_space_heating_terraced_houses_2005_present

@kndehaan
kndehaan requested a review from louispt1 August 18, 2026 07:19
@aaccensi

Copy link
Copy Markdown
Member Author

Ok @kndehaan, so for the migration of the insulation the future residences work as before but the existing residences now weigh in based in their start-year heat demand rather then the floor area. Could you check if this gives you the expected results? Once you give the thumbs up, we would only be needing a code check by @louispt1.

Comment thread db/migrate/20260813120000_simplified_households_heat_inputs.rb
@kndehaan

Copy link
Copy Markdown
Member

@louispt1 note that it's not needed to review 20260804120000_simplified_buildings_heat_inputs.rb, which has already been reviewed in a separate PR by Nora.

@kndehaan kndehaan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migration approved in terms of working principles.


# A construction period of the housing stock. The old inputs exist for every housing type, the new
# ones cover all types of the period at once.
Period = Struct.new(:name, :demolished_key, :insulation_key) do

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is demolished_key passed in here instead of derived like all the other keys? It seems to follow the same pattern and if you set it up the same way you don't need to pass demolished_key: nil in NEW_PERIOD

Is there a case where you pass a non-derived key?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the new period never asks for I we can do it.

total = [built, present_residences(scenario, PRESENT_RESIDENCES_ATTRIBUTE)].min
residences.transform_values! { |of_type| of_type * total / built } if total < built

scenario.user_values[NEW_RESIDENCES_KEY] = total.round(RESIDENCES_DECIMALS).to_f

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm concerned that for scaled datasets with round we could end up above the maximum (present_number_of_residences can be fractional)? This effects two places - also the demolished total (scenario.user_values[period.demolished_key] = demolished.round(RESIDENCES_DECIMALS).to_f).

Clamping to the max after rounding could be a solution, although you also end up with fractions there which would be rejected by the step value. Alternatively you can floor and then you're within bounds, in which case you might end up 1 residence short of the maximum.

What do you think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! The most important thing here is to not go beyond the min/max values of the input.

I think floor is the best option here since this is both in line with the max value and step value. @aaccensi what do you think?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets do something about it, even though this would only happen when demolishing everything or building beyond the cap (Kyra confirmed already the latest was not in our data). Simplest is flooring which is also the closest to what would happen in the frontend to a scaled value defined with 0 decimal places.

aaccensi and others added 7 commits August 20, 2026 16:37
- Insulation is written as a positive reduction rather than a negative change.
- The behaviour input is no longer set, so a demand increase above the default is dropped rather than carried over, which also removes the demand weighting the shared behaviour input needed (big simplification).
- Values are rounded to the step value of their own input.
Every other migration in db/migrate deletes the keys of inputs that etsource has removed as soon as it processes a scenario; only the unknown-area guard stops it. This one returned before the delete when the area had no typical demand, leaving the scenario holding a key for an input that no longer exists.
The model scales the start-year demand of the residences left standing today rather than recalculating it from the floor area, so the insulation weighting now reads that demand from a dump generated with the refinery_dump task. New residences weigh in just as before, this is in line with the model.
@kndehaan
kndehaan force-pushed the households-stock-heat-migration branch from 74ae9a4 to 622876f Compare August 20, 2026 14:37
@kndehaan
kndehaan merged commit 895f2b5 into master Aug 20, 2026
1 check passed
@kndehaan
kndehaan deleted the households-stock-heat-migration branch August 20, 2026 14:43
@aaccensi
aaccensi restored the households-stock-heat-migration branch August 20, 2026 16:06
aaccensi added a commit that referenced this pull request Aug 20, 2026
…igration"

This reverts commit 895f2b5, reversing
changes made to 10c1859.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants