RdSAP10 Tutorials

Running a RdSAP10 calculation

An RdSAP10 calculation can be run using:

import sap10calcs
result = sap10calcs.rdsap(
    input_file = 'my_rdsap10_file.xml',
    auth_token = None
)

This uses the sap10calcs.rdsap() function:

  • input_file is an RdSAP10 XML file provided by the user and stored on the local computer.

  • auth_token is an authorization token for the remote API service provided by the user (see here for details).

  • result is a Python dictionary which contains the final RdSAP calculated values (such as energy consumption and the SAP rating), the intermediate calculations and any error messages.

In practice, I would use this in a wider function that also saves the complete output of the sap10calcs.rdsap() function, saves the final SAP10 XML file (ready for use in sap10calcs.calculate()) and prints out any error message. This might look like:

import sap10calcs
import json
from io import StringIO

def run_rdsap(
    fp_in,  # filepath to the input RdSAP10 XML file.
    fp_out_json,  # filepath for the output from the sap10calcs.rdsap function.
    fp_out_xml,  # filepath for the final SAP10 XML file.
    auth_token = None
    ):
    ""
    # run RdSAP engine
    result = sap10calcs.rdsap(
        input_file = fp_in,
        auth_token = auth_token
    )

    # save full output - useful for fixing errors...
    with open(fp_out_json, 'w') as f: json.dump(result, f, indent = 4)

    # print error message if present
    if not result['rdsap_calculation_error_traceback'] is None:
        print('\n', result['rdsap_calculation_error_traceback'])
    else:
        # save SAP10 XML file
        tree, sap_report = sap10calcs.parse_xml(StringIO(result['sap_xml']))
        tree.write(fp_out_xml, encoding="utf-8", xml_declaration=True, pretty_print=True)

    return result

run_rdsap('my_rdsap10_file.xml', 'rdsap_result.json', 'my_sap10_file.xml')

The SAP10 XML file is returned as a string in the result dictionary. So this is converted into a file-like object using StringIO before being read using the sap10calcs.parse_xml() function.

The tree variable is a standard lxml ElementTree. The write method from the lxml package is used to save the XML to a local file.

Editing an existing RdSAP XML input file

This code uses the sap10calcs.parse_rsdap_xml() function to read an RdSAP XML file. It then updates the country code and the number of doors, and saves the XML file with a new name.

import sap10calcs
tree, rdsap_report = sap10calcs.parse_rdsap_xml('my_rdsap10_file.xml')
rdsap_report.report_header.country_code.value = 'Wales'
rdsap_report.sap_data.sap_property_details.door_count.value = 2
tree.write('my_rdsap10_file_edited.xml', encoding="utf-8", xml_declaration=True, pretty_print=True)

Creating a RdSAP XML input file from scratch

This code uses the sap10calcs.create_rdsap_report_xml() function to create an empty RdSAP_Report object, and then uses the object properties and methods to create a complete RdSAP input XML file.

import sap10calcs

# create new rdsap_report element
tree, rdsap_report = sap10calcs.create_rdsap_report_xml()

# report_header
report_header = rdsap_report.add_report_header()
report_header.add_country_code().value = 'England'

# sap_data
sap_data = rdsap_report.add_sap_data()

# sap_property_details
sap_property_details = sap_data.add_sap_property_details()
sap_property_details.add_property_type().value = 'House'
sap_property_details.add_built_form().value = 'Detached'
sap_property_details.add_extensions_count().value = 0
sap_property_details.add_habitable_room_count().value = 1
sap_property_details.add_heated_room_count().value = 1
sap_property_details.add_low_energy_fixed_lighting_bulbs_count().value = 0
sap_property_details.add_incandescent_fixed_lighting_bulbs_count().value = 0
sap_property_details.add_measurement_type().value = 'Internal'
sap_property_details.add_solar_water_heating().value = 'No'
sap_property_details.add_pressure_test().value = 'yes - measured at 50 Pa'
sap_property_details.add_air_permeability().value = 0
sap_property_details.add_mechanical_ventilation().value = 'natural'
sap_property_details.add_conservatory_type().value = 'no conservatory'
sap_property_details.add_door_count().value = 0
sap_property_details.add_percent_draughtproofed().value = 0

# sap_heating
sap_heating = sap_property_details.add_sap_heating()
sap_heating.add_water_heating_fuel().code = '26'
sap_heating.add_water_heating_code().value = 901  # From main heating system
sap_heating.add_immersion_heating_type().value = 'not applicable'
sap_heating.add_cylinder_size().value = 'No Cylinder'
sap_heating.add_has_fixed_air_conditioning().value = False

# main_heating_details
main_heating_details = sap_heating.add_main_heating_details()

# main_heating_1
main_heating_1 = main_heating_details.add_main_heating()
main_heating_1.add_main_heating_number().value = 1
main_heating_1.add_main_heating_category().value = 'boiler with radiators or underfloor heating'
main_heating_1.add_main_fuel_type().code = '26'
main_heating_1.add_main_heating_control().value = 2106  # "Programmer, room thermostat and TRVs"
main_heating_1.add_main_heating_data_source().value = 'SAP Table'
main_heating_1.add_sap_main_heating_code().value = 104
    # "Gas boilers (including mains gas, LPG and biogas) 1998 or later: Condensing combi with automatic ignition"
main_heating_1.add_boiler_ignition_type().value = 'auto-ignition'
main_heating_1.add_boiler_flue_type().value = 'open'
main_heating_1.add_fan_flue_present().value = 'Yes'
main_heating_1.add_heat_emitter_type().value = 'radiators'
main_heating_1.add_main_heating_fraction().value = 1
main_heating_1.add_has_fghrs().value = 'No'
main_heating_1.add_emitter_temperature().value = 'unknown'
main_heating_1.add_central_heating_pump_age().value = 'unknown'

# sap_energy_source
sap_energy_source = sap_property_details.add_sap_energy_source()
sap_energy_source.add_meter_type().value = 'Single'
sap_energy_source.add_mains_gas().value = 'mains gas available in the property'
sap_energy_source.add_electricity_smart_meter_present().value = False
sap_energy_source.add_gas_smart_meter_present().value = False
sap_energy_source.add_is_dwelling_export_capable().value = False
sap_energy_source.add_wind_turbines_count().value = 0
sap_energy_source.add_wind_turbines_terrain_type().value = 'not recorded'
sap_energy_source.add_pv_connection().value = 'not applicable (FGHRS or no PV)'

# photovoltaic_supply
photovoltaic_supply = sap_energy_source.add_photovoltaic_supply()
photovoltaic_supply.add_none_or_no_details().add_percent_roof_area().value = 0

# sap_building_parts
sap_building_parts = sap_property_details.add_sap_building_parts()

# sap_building_part_1
sap_building_part_1 = sap_building_parts.add_sap_building_part()
sap_building_part_1.add_building_part_number().value = 1
sap_building_part_1.add_construction_age_band().value = \
    'England and Wales: 1991-1995; Scotland: 1992-1998; Northern Ireland: 1992-1999'
#sap_building_part_1.add_floor_insulation_thickness().value = '50mm'
sap_building_part_1.add_floor_u_value().value = 1.0
sap_building_part_1.add_floor_heat_loss().value = 'Ground floor'
sap_building_part_1.add_roof_construction().value = 'Pitched (slates or tiles), access to loft'
sap_building_part_1.add_roof_u_value().value = 1.0
sap_building_part_1.add_roof_insulation_location().value = 'Joists'
sap_building_part_1.add_wall_construction().value = 'cavity'
sap_building_part_1.add_wall_dry_lined().value = 'No'
sap_building_part_1.add_wall_u_value().value = 1.0
sap_building_part_1.add_wall_insulation_type().value = 'filled cavity'
sap_building_part_1.add_wall_thickness_measured().value = 'No'
sap_building_part_1.add_party_wall_construction().value = \
    'not applicable (detached property or no party wall in this building part)'

# sap_floor_dimensions_1
sap_floor_dimensions_1 = sap_building_part_1.add_sap_floor_dimensions()

# sap_floor_dimension_1_1
sap_floor_dimension_1_1 = sap_floor_dimensions_1.add_sap_floor_dimension()
sap_floor_dimension_1_1.add_heat_loss_perimeter().value = 40
sap_floor_dimension_1_1.add_room_height().value = 3
sap_floor_dimension_1_1.add_total_floor_area().value = 100
sap_floor_dimension_1_1.add_floor().value = 'lowest occupied'
sap_floor_dimension_1_1.add_floor_construction().value = 'suspended timber'
sap_floor_dimension_1_1.add_floor_insulation().value = 'as built'
sap_floor_dimension_1_1.add_party_wall_length().value = 0

# sap_windows
sap_windows = sap_property_details.add_sap_windows()

# sap_window_1
sap_window_1 = sap_windows.add_sap_window()
sap_window_1.add_window_location().value = 'Main Property'
sap_window_1.add_window_height().value = 1
sap_window_1.add_window_width().value = 1
sap_window_1.add_draught_proofed().value = False
sap_window_1.add_glazing_type().value = 'single glazing'
sap_window_1.add_window_type().value = 'window'
sap_window_1.add_orientation().value = 'South'
window_transmission_details_1 = sap_window_1.add_window_transmission_details()
window_transmission_details_1.add_data_source().value = 'manufacturer data'
window_transmission_details_1.add_u_value().value = 1
window_transmission_details_1.add_solar_transmittance().value = 0.8
sap_window_1.add_frame_factor().value = 0.9
sap_window_1.add_pvc_frame().value = True
sap_window_1.add_window_wall_type().value = 'External wall type 1'
sap_window_1.add_permanent_shutters_present().value = 'No'
sap_window_1.add_permanent_shutters_insulated().value = 'No'

tree.write('my_rdsap10_file.xml', encoding="utf-8", xml_declaration=True, pretty_print=True)

This creates the following XML file (shown below using the display() function):

<RdSAP-Report xmlns="https://epbr.digital.communities.gov.uk/xsd/rdsap">
  <Schema-Version-Original>RdSAP-Schema-21.0.0</Schema-Version-Original>
  <SAP-Version>10.2 ['SAP version 10.2, dated April 2023']</SAP-Version>
  <Report-Header>
    <Country-Code>ENG ['England']</Country-Code>
  </Report-Header>
  <SAP-Data>
    <SAP-Property-Details>
      <Property-Type>0 ['House']</Property-Type>
      <Built-Form>1 ['Detached']</Built-Form>
      <Extensions-Count>0</Extensions-Count>
      <Habitable-Room-Count>1</Habitable-Room-Count>
      <Heated-Room-Count>1</Heated-Room-Count>
      <Low-Energy-Fixed-Lighting-Bulbs-Count>0</Low-Energy-Fixed-Lighting-Bulbs-Count>
      <Incandescent-Fixed-Lighting-Bulbs-Count>0</Incandescent-Fixed-Lighting-Bulbs-Count>
      <Measurement-Type>1 ['Internal']</Measurement-Type>
      <Solar-Water-Heating>N ['No']</Solar-Water-Heating>
      <Pressure-Test>6 ['yes - measured at 50 Pa']</Pressure-Test>
      <Air-Permeability>0</Air-Permeability>
      <Mechanical-Ventilation>0 ['natural']</Mechanical-Ventilation>
      <Conservatory-Type>1 ['no conservatory']</Conservatory-Type>
      <Door-Count>0</Door-Count>
      <Percent-Draughtproofed>0</Percent-Draughtproofed>
      <SAP-Heating>
        <Water-Heating-Fuel>26 ['mains gas (not community)']</Water-Heating-Fuel>
        <Water-Heating-Code>901</Water-Heating-Code>
        <Immersion-Heating-Type>NA ['not applicable']</Immersion-Heating-Type>
        <Cylinder-Size>1 ['No Cylinder']</Cylinder-Size>
        <Has-Fixed-Air-Conditioning>0 ['False']</Has-Fixed-Air-Conditioning>
        <Main-Heating-Details>
          <Main-Heating>
            <Main-Heating-Number>1</Main-Heating-Number>
            <Main-Heating-Category>2 ['boiler with radiators or underfloor heating']</Main-Heating-Category>
            <Main-Fuel-Type>26 ['mains gas (not community)']</Main-Fuel-Type>
            <Main-Heating-Control>2106</Main-Heating-Control>
            <Main-Heating-Data-Source>2 ['SAP Table']</Main-Heating-Data-Source>
            <SAP-Main-Heating-Code>104</SAP-Main-Heating-Code>
            <Boiler-Ignition-Type>1 ['auto-ignition']</Boiler-Ignition-Type>
            <Boiler-Flue-Type>1 ['open']</Boiler-Flue-Type>
            <Fan-Flue-Present>Y ['Yes']</Fan-Flue-Present>
            <Heat-Emitter-Type>1 ['radiators']</Heat-Emitter-Type>
            <Main-Heating-Fraction>1</Main-Heating-Fraction>
            <Has-FGHRS>N ['No']</Has-FGHRS>
            <Emitter-Temperature>0 ['unknown']</Emitter-Temperature>
            <Central-Heating-Pump-Age>0 ['unknown']</Central-Heating-Pump-Age>
          </Main-Heating>
        </Main-Heating-Details>
      </SAP-Heating>
      <SAP-Energy-Source>
        <Meter-Type>2 ['Single']</Meter-Type>
        <Mains-Gas>Y ['mains gas available in the property']</Mains-Gas>
        <Electricity-Smart-Meter-Present>0 ['False']</Electricity-Smart-Meter-Present>
        <Gas-Smart-Meter-Present>0 ['False']</Gas-Smart-Meter-Present>
        <Is-Dwelling-Export-Capable>0 ['False']</Is-Dwelling-Export-Capable>
        <Wind-Turbines-Count>0</Wind-Turbines-Count>
        <Wind-Turbines-Terrain-Type>4 ['not recorded']</Wind-Turbines-Terrain-Type>
        <PV-Connection>0 ['not applicable (FGHRS or no PV)']</PV-Connection>
        <Photovoltaic-Supply>
          <None-Or-No-Details>
            <Percent-Roof-Area>0</Percent-Roof-Area>
          </None-Or-No-Details>
        </Photovoltaic-Supply>
      </SAP-Energy-Source>
      <SAP-Building-Parts>
        <SAP-Building-Part>
          <Building-Part-Number>1</Building-Part-Number>
          <Construction-Age-Band>H ['England and Wales: 1991-1995; Scotland: 1992-1998; Northern Ireland: 1992-1999']</Construction-Age-Band>
          <Floor-U-Value>1.0</Floor-U-Value>
          <Floor-Heat-Loss>7 ['Ground floor']</Floor-Heat-Loss>
          <Roof-Construction>4 ['Pitched (slates or tiles), access to loft']</Roof-Construction>
          <Roof-U-Value>1.0</Roof-U-Value>
          <Roof-Insulation-Location>2 ['Joists']</Roof-Insulation-Location>
          <Wall-Construction>4 ['cavity']</Wall-Construction>
          <Wall-Dry-Lined>N ['No']</Wall-Dry-Lined>
          <Wall-U-Value>1.0</Wall-U-Value>
          <Wall-Insulation-Type>2 ['filled cavity']</Wall-Insulation-Type>
          <Wall-Thickness-Measured>N ['No']</Wall-Thickness-Measured>
          <Party-Wall-Construction>NA ['not applicable (detached property or no party wall in this building part)']</Party-Wall-Construction>
          <SAP-Floor-Dimensions>
            <SAP-Floor-Dimension>
              <Heat-Loss-Perimeter>40</Heat-Loss-Perimeter>
              <Room-Height>3</Room-Height>
              <Total-Floor-Area>100</Total-Floor-Area>
              <Floor>0 ['lowest occupied']</Floor>
              <Floor-Construction>2 ['suspended timber']</Floor-Construction>
              <Floor-Insulation>1 ['as built']</Floor-Insulation>
              <Party-Wall-Length>0</Party-Wall-Length>
            </SAP-Floor-Dimension>
          </SAP-Floor-Dimensions>
        </SAP-Building-Part>
      </SAP-Building-Parts>
      <SAP-Windows>
        <SAP-Window>
          <Window-Location>0 ['Main Property']</Window-Location>
          <Window-Height>1</Window-Height>
          <Window-Width>1</Window-Width>
          <Draught-Proofed>0 ['False']</Draught-Proofed>
          <Glazing-Type>5 ['single glazing']</Glazing-Type>
          <Window-Type>1 ['window']</Window-Type>
          <Orientation>5 ['South']</Orientation>
          <Window-Transmission-Details>
            <Data-Source>2 ['manufacturer data']</Data-Source>
            <U-Value>1</U-Value>
            <Solar-Transmittance>0.8</Solar-Transmittance>
          </Window-Transmission-Details>
          <Frame-Factor>0.9</Frame-Factor>
          <PVC-Frame>1 ['True']</PVC-Frame>
          <Window-Wall-Type>1 ['External wall type 1']</Window-Wall-Type>
          <Permanent-Shutters-Present>N ['No']</Permanent-Shutters-Present>
          <Permanent-Shutters-Insulated>N ['No']</Permanent-Shutters-Insulated>
        </SAP-Window>
      </SAP-Windows>
    </SAP-Property-Details>
  </SAP-Data>
</RdSAP-Report>