How to hack a SAP 10 calculation

This article provides instructions for "hacking" a Standard Assessment Procedure version 10 (SAP 10) calculation for the energy performance of new and existing dwellings.

What is "hacking" a SAP calculation?

Here, hacking a SAP calculation means running a SAP calculation and replacing some of the default values or intermediate calculation values with our own values.

Why do this?

One of limitations often said about the SAP calculation process is the fact that it uses default values that cannot be changed by the user. In many ways this is a good thing, as SAP is primarily meant for building regulation compliance and so is designed to use standard assumptions and default values.

However there are occasions when using our own values in SAP would be useful. Possible use cases are:

  • The Heat Transfer Coefficient of an existing building has been measured, and we would like to use this value in the SAP calculation to better estimate the space heating energy demand.
  • The internal air temperatures of an existing building have been measured, and we would like to use these values to better estimate the space heating energy demand.
  • A heat pump has been installed, and we would like to use our own gas and electricity prices (rather than the default unit costs) to understand the potential cost savings.

How to do this?

This example uses the SAP 10 API service available at netzeroapis.com.

A Python script is written to send an input file to the API and to report the results of the SAP calculation. As the input file is sent, further instructions are also sent to "overwrite" some of the intermediate calculated values.

The input file used in this example is a SAP10 XML input file for a detached house.

The code used in this example is available as a Jupyter Notebook on GitHub.

Hacking the Heat Transfer Coefficient

The Python code below runs an initial SAP calculation and prints out the monthly Heat Transfer Coefficient (HTC) values (as calculated by SAP), the SAP rating and the SAP band.

# initial run 
import requests
import json
with open('detached_house.xml', 'rb') as input_file:
    response = requests.post(
        url = 'https://netzeroapis.com/calc/sap10',
        files = {'file': input_file},
        headers = {'Authorization': None}
        )
if response.status_code != 200: raise Exception(reposonse.text)
result = response.json()
if result['sap_calculation_success'] == False: 
  raise Exception(result['sap_calculation_error_traceback'])
output_dict = result['sap_calculation_output_dict']
print(
  'Monthly HTC values (value_39_m, W/K): ',
  [round(output_dict[f'value_39_{m}'], 1) for m in range(1,13)]
  )
print('SAP rating (value 258): ', output_dict['value_258'])
print('SAP band: ', output_dict['sap_band'])
Monthly HTC values (value_39_m, W/K):  [239.6, 239.6, 239.5, 239.2, 239.1, 238.9, 
  238.9, 238.8, 239.0, 239.1, 239.2, 239.4]
SAP rating (value 258):  73
SAP band:  C

Here we can see that the monthly HTC values vary between 238.8 W/K and 239.6 W/K. The overal SAP rating (the SAP score) is 73 and the house is in SAP Band "C".

And now here is the new code which "hacks" this calculation. Here an extra JSON file with an overwrite object provides new values for the monthly HTCs - in this case the HTC is set to a constant 100 W/K for all months.

# run with overwriting of HTC values
with open('detached_house.xml', 'rb') as input_file:
    response = requests.post(
        url = 'https://netzeroapis.com/calc/sap10',
        files = {
            'file': input_file,
            'extra': json.dumps({
                'overwrite': 
                    {
                        'value_39_1': 100,
                        'value_39_2': 100,
                        'value_39_3': 100,
                        'value_39_4': 100,
                        'value_39_5': 100,
                        'value_39_6': 100,
                        'value_39_7': 100,
                        'value_39_8': 100,
                        'value_39_9': 100,
                        'value_39_10': 100,
                        'value_39_11': 100,
                        'value_39_12': 100,
                    }
                }),
            },
        headers = {'Authorization': None},
        )
if response.status_code != 200: raise Exception(response.text)
result = response.json()
if result['sap_calculation_success'] == False: 
  raise Exception(result['sap_calculation_error_traceback'])
output_dict = result['sap_calculation_output_dict']
print('Monthly HTC values (value_39_m, W/K): ', [round(output_dict[f'value_39_{m}'], 1) for m in range(1,13)])
print('SAP rating (value 258): ', output_dict['value_258'])
print('SAP band: ', output_dict['sap_band'])
Monthly HTC values (value_39_m, W/K):  [100, 100, 100, 100, 100, 100,
  100, 100, 100, 100, 100, 100]
SAP rating (value 258):  82
SAP band:  B

We can now see that the SAP calculation has used the new HTC values, and changing the HTC to 100 W/K results in the SAP rating increasing to 82 and the house now being in SAP band "B".

Technical note: how is this implemented in the API?

I built this functionality into the SAP 10 API from the very start as I was thought that this would be a useful feature to include.

When the API does the SAP calculations, this is set up as a Python generator. As a value is calculated ("value_1", "value_2" etc.), it is placed in the output_dict variable and then control is yielded back to the main calling function.

When the extra overwrite data is provided to the API, the main calling function looks to see when any of the overwrite variables have just been calculated - and if so it replaces them with the user provided value instead.

The SAP calculation is also set up so that when a variable is required for a calculation at a later point in the process, it is read back from the output_dict (not from any local variable) and so any changes to output_dict will be incorporated into the later calculations.

Summary

  • This post demonstrates how to "hack" a SAP calculation by replacing default values and intermediate calculated values with user supplied values instead.
  • This functionality is implemented in the SAP 10 API hosted at netzeroapis.com.
  • By providing an additional input JSON file named extra, the new user-supplied values can be provided for the API to use.
  • The input file and code used for this are available on GitHub.