mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
896 lines
51 KiB
Python
896 lines
51 KiB
Python
import numpy as np
|
||
|
||
# Example - delete me
|
||
from backend.Property import Property
|
||
|
||
print("DELETE ME IN COSTS CLASS")
|
||
from epc_api.client import EpcClient
|
||
|
||
epc_client = EpcClient(auth_token=AUTH_TOKEN)
|
||
p1 = Property(
|
||
postcode="NN1 5JY",
|
||
address1="2 South Terrace",
|
||
epc_client=epc_client,
|
||
id=0
|
||
)
|
||
|
||
p2 = Property(
|
||
postcode="PO12 4TY",
|
||
address1="25 Albert Street",
|
||
epc_client=epc_client,
|
||
id=0
|
||
)
|
||
|
||
p1.search_address_epc()
|
||
p2.search_address_epc()
|
||
|
||
p1.set_basic_property_dimensions()
|
||
p2.set_basic_property_dimensions()
|
||
|
||
import pandas as pd
|
||
|
||
df = pd.read_csv("/Users/khalimconn-kowlessar/Downloads/Hestia Materials - external_wall_insulation.csv")
|
||
df = df.to_dict("records")
|
||
|
||
# This data comes from SPONs
|
||
regional_labour_variations = [
|
||
{"Region": "Outer London (Spon’s 2023)", "Adjustment_Factor": 1.00},
|
||
{"Region": "Inner London", "Adjustment_Factor": 1.05},
|
||
{"Region": "South East", "Adjustment_Factor": 0.96},
|
||
{"Region": "South West", "Adjustment_Factor": 0.90},
|
||
{"Region": "East of England", "Adjustment_Factor": 0.93},
|
||
{"Region": "East Midlands", "Adjustment_Factor": 0.88},
|
||
{"Region": "West Midlands", "Adjustment_Factor": 0.87},
|
||
{"Region": "North East", "Adjustment_Factor": 0.83},
|
||
{"Region": "North West", "Adjustment_Factor": 0.88},
|
||
{"Region": "Yorkshire and Humberside", "Adjustment_Factor": 0.86},
|
||
{"Region": "Wales", "Adjustment_Factor": 0.88},
|
||
{"Region": "Scotland", "Adjustment_Factor": 0.88},
|
||
{"Region": "Northern Ireland", "Adjustment_Factor": 0.76}
|
||
]
|
||
|
||
county_map = {
|
||
"Northamptonshire": "East Midlands",
|
||
"Hampshire": "South East",
|
||
}
|
||
|
||
|
||
class Costs:
|
||
"""
|
||
A class to calculate the costs associated with construction works,
|
||
specifically focusing on cavity wall insulation.
|
||
It includes contingency, preliminaries, profit margin, and VAT calculations.
|
||
|
||
As a sense check, there is a useful article from checkatrade on retrofitting and expected costs:
|
||
https://www.checkatrade.com/blog/cost-guides/retrofit-insulation-cost/
|
||
|
||
Another useful article for benchmarking the cost of floor insulation:
|
||
https://www.checkatrade.com/blog/cost-guides/floor-insulation-cost/
|
||
"""
|
||
|
||
# Contingency is a percentage of the total cost of the work and covers unforseen expenses
|
||
# We assume a conservative 10% contingency for all works which is a rate defined by SPONs
|
||
CONTINGENCY = 0.1
|
||
|
||
# Where there is more uncertainty, a higher contingency rate is used
|
||
HIGH_RISK_CONTINGENCY = 0.15
|
||
# When there is less uncertainty, a lower contingency rate is used
|
||
LOW_RISK_CONTINGENCY = 0.05
|
||
|
||
# Preliminaries are a percentage of the total cost of the work and covers the cost of site-specific costs
|
||
# such as site preparation, safety measures and project management. This rate can vary but we'll assume a 10%
|
||
# rate, on the total cost before VAT, as recommended by SPONs
|
||
PRELIMINARIES = 0.1
|
||
|
||
# For higher risk projects, a higher preliminaries rate is used. SPONs indicates that a higher risk project might
|
||
# have a preliminaries of 12-14% so we use 12% as the median for the preliminaries rate.
|
||
# For External wall insulation (EWI), we use 15% as the preliminaries rate if we think the property might
|
||
# need scaffolding, otherwise we use 12%. This is to account for any site preparation that might be required
|
||
EWI_NO_SCAFFOLDING_PRELIMINARIES = 0.12
|
||
EWI_SCAFFOLDING_PRELIMINARIES = 0.15
|
||
|
||
VAT_RATE = 0.2
|
||
PROFIT_MARGIN = 0.15
|
||
|
||
def __init__(self, property_instance):
|
||
"""
|
||
Initializes the Costs class with a property instance.
|
||
|
||
:param property_instance: Instance of a Property class containing relevant details like wall area.
|
||
"""
|
||
if not hasattr(property_instance, 'insulation_wall_area'):
|
||
raise ValueError("Property instance must have an 'insulation_wall_area' attribute")
|
||
self.property = property_instance
|
||
self.regional_labour_variations = regional_labour_variations
|
||
|
||
self.county = county_map.get(self.property.data["county"], None)
|
||
if self.county is None:
|
||
raise ValueError("County not found in county map")
|
||
|
||
self.labour_adjustment_factor = [
|
||
x["Adjustment_Factor"] for x in self.regional_labour_variations if
|
||
x["Region"] == self.county
|
||
][0]
|
||
|
||
if not self.labour_adjustment_factor:
|
||
raise ValueError("Labour adjustment factor not found")
|
||
|
||
def cavity_wall_insulation(self, wall_area, material):
|
||
"""
|
||
Calculates the total cost for cavity wall insulation based on material and labor costs,
|
||
including contingency, preliminaries, profit, and VAT.
|
||
|
||
:return: A dictionary containing detailed cost breakdown.
|
||
"""
|
||
# Cost per m2
|
||
# material = {
|
||
# "description": "Crown Dritherm Cavity Slab 37 (Thermal conductivity 0.037 W/mK) glass fibre batt or
|
||
# other "
|
||
# "equal; as full or partial cavity fill; including cutting and fitting around wall ties
|
||
# and "
|
||
# "retaining discs",
|
||
# "depth": 75,
|
||
# "thermal_conductivity": 0.037,
|
||
# "prime_cost": 5.17,
|
||
# "material_cost": 5.62,
|
||
# "labour_cost": 2.25,
|
||
# "labour_hours": 0.13
|
||
# }
|
||
|
||
material_cost_per_m2 = material["material_cost"]
|
||
# wall_area = self.property.insulation_wall_area
|
||
|
||
# This is the amount of material required in m3, assuming a standard 75mm depth
|
||
volume = 0.075 * wall_area
|
||
|
||
base_material_cost = material_cost_per_m2 * wall_area
|
||
labour_cost = material["labour_cost"] * wall_area * self.labour_adjustment_factor
|
||
|
||
subtotal_before_profit = base_material_cost + labour_cost
|
||
|
||
contingency_cost = subtotal_before_profit * self.CONTINGENCY
|
||
preliminaries_cost = subtotal_before_profit * self.PRELIMINARIES
|
||
profit_cost = subtotal_before_profit * self.PROFIT_MARGIN
|
||
|
||
subtotal_before_vat = subtotal_before_profit + contingency_cost + preliminaries_cost + profit_cost
|
||
|
||
vat_cost = subtotal_before_vat * self.VAT_RATE
|
||
|
||
total_cost = subtotal_before_vat + vat_cost
|
||
|
||
labour_hours = material["labour_hours"] * wall_area
|
||
|
||
return {
|
||
"total": total_cost,
|
||
"subtotal": subtotal_before_vat,
|
||
"vat": vat_cost,
|
||
"contingency": contingency_cost,
|
||
"preliminaries": preliminaries_cost,
|
||
"material": base_material_cost,
|
||
"profit": profit_cost,
|
||
"labour_hours": labour_hours
|
||
}
|
||
|
||
def loft_insulation(self, floor_area, material):
|
||
"""
|
||
Calculates the total cost for cavity wall insulation based on material and labor costs,
|
||
including contingency, preliminaries, profit, and VAT.
|
||
|
||
:return: A dictionary containing detailed cost breakdown.
|
||
"""
|
||
# Cost per m2
|
||
# material = {
|
||
# "description": "Crown Loft Roll 44 glass fibre roll",
|
||
# "depth": 270,
|
||
# "thermal_conductivity": 0.044,
|
||
# "prime_cost": None,
|
||
# "material_cost": 5.91938,
|
||
# "labour_cost": 1.96,
|
||
# "labour_hours": 0.11
|
||
# }
|
||
|
||
material_cost_per_m2 = material["material_cost"]
|
||
# floor_area = self.property.floor_area
|
||
|
||
base_material_cost = material_cost_per_m2 * floor_area
|
||
labour_cost = material["labour_cost"] * floor_area * self.labour_adjustment_factor
|
||
|
||
subtotal_before_profit = base_material_cost + labour_cost
|
||
|
||
contingency_cost = subtotal_before_profit * self.CONTINGENCY
|
||
preliminaries_cost = subtotal_before_profit * self.PRELIMINARIES
|
||
profit_cost = subtotal_before_profit * self.PROFIT_MARGIN
|
||
|
||
subtotal_before_vat = subtotal_before_profit + contingency_cost + preliminaries_cost + profit_cost
|
||
|
||
vat_cost = subtotal_before_vat * self.VAT_RATE
|
||
|
||
total_cost = subtotal_before_vat + vat_cost
|
||
|
||
labour_hours = material["labour_hours"] * floor_area
|
||
|
||
return {
|
||
"total": total_cost,
|
||
"subtotal": subtotal_before_vat,
|
||
"vat": vat_cost,
|
||
"contingency": contingency_cost,
|
||
"preliminaries": preliminaries_cost,
|
||
"material": base_material_cost,
|
||
"profit": profit_cost,
|
||
"labour_hours": labour_hours
|
||
}
|
||
|
||
def internal_wall_insulation(self, wall_area, material, non_insulation_materials):
|
||
"""
|
||
Broadly speaking, the high level steps to an internal wall insulation job are the following:
|
||
|
||
1) Demolition: This involves removing existing wall linings, fittings, and any other obstacles.
|
||
It's important to factor in the disposal of debris and the potential need for additional protective
|
||
measures to ensure the safety of the work area.
|
||
|
||
2) Insulation Installation: This is the core part of the process where the chosen insulation material is
|
||
applied. The choice of insulation material will depend on several factors including thermal performance,
|
||
wall construction, and space constraints.
|
||
|
||
3) Vapour Barrier Installation: This is crucial for preventing moisture from penetrating the insulation,
|
||
which can compromise its effectiveness and lead to mold growth.
|
||
|
||
4) Re-decoration: This involves applying plaster to the wall and then painting.
|
||
The quality of finish here is important for both aesthetic and functional reasons.
|
||
|
||
5) Trim and Finishing Work: Post-insulation, tasks such as re-installing skirting boards, door frames,
|
||
or window sills might be necessary.
|
||
:return:
|
||
"""
|
||
|
||
# Parsing the provided table into a list of dictionaries
|
||
|
||
# non_insulation_materials = [
|
||
# {'type': 'iwi_wall_demolition',
|
||
# 'description': 'Solid & Dry Lined walls: Hack of wall finishes with chipping hammer; plaster to walls.',
|
||
# 'depth': 0.0, 'depth_unit': 0.0, 'cost_unit': 'gbp_per_m2', 'thermal_conductivity': 0.0,
|
||
# 'thermal_conductivity_unit': 0.0, 'prime_material_cost': 0.0, 'material_cost': 0.0, 'labour_cost': 10.27,
|
||
# 'labour_hours_per_unit': 0.33, 'plant_cost': 1.28, 'total_cost': 11.55, 'link': 'SPONs', 'Notes': 0.0},
|
||
# {'type': 'iwi_wall_demolition',
|
||
# 'description': 'Stud walls: Remove wall linings including battening behind; plasterboard and skim',
|
||
# 'depth': 0.0, 'depth_unit': 0.0, 'cost_unit': 'gbp_per_m2', 'thermal_conductivity': 0.0,
|
||
# 'thermal_conductivity_unit': 0.0, 'prime_material_cost': 0.0, 'material_cost': 0.0, 'labour_cost': 6.23,
|
||
# 'labour_hours_per_unit': 0.2, 'plant_cost': 1.25, 'total_cost': 7.48, 'link': 'SPONs', 'Notes': 0.0},
|
||
# {'type': 'iwi_wall_demolition',
|
||
# 'description': 'Lathe and Plaster walls: Remove wall linings including battening behind; wood lath and '
|
||
# 'plaster',
|
||
# 'depth': 0.0, 'depth_unit': 0.0, 'cost_unit': 'gbp_per_m2', 'thermal_conductivity': 0.0,
|
||
# 'thermal_conductivity_unit': 0.0, 'prime_material_cost': 0.0, 'material_cost': 0.0, 'labour_cost': 6.85,
|
||
# 'labour_hours_per_unit': 0.22, 'plant_cost': 2.09, 'total_cost': 8.94, 'link': 'SPONs', 'Notes': 0.0},
|
||
# {'Notes': "",
|
||
# 'cost_unit': "",
|
||
# 'depth': "",
|
||
# 'depth_unit': "",
|
||
# 'description': 'Visqueen High Performance Vapour Barrier',
|
||
# 'labour_cost': 0.48,
|
||
# 'labour_hours_per_unit': 0.02,
|
||
# 'link': 'SPONs',
|
||
# 'material_cost': 1.21,
|
||
# 'plant_cost': 0,
|
||
# 'prime_material_cost': 0.58,
|
||
# 'thermal_conductivity': "",
|
||
# 'thermal_conductivity_unit': "",
|
||
# 'total_cost': 1.69,
|
||
# 'type': 'iwi_vapour_barrier'},
|
||
# {'Notes': "",
|
||
# 'cost_unit': "",
|
||
# 'depth': "",
|
||
# 'depth_unit': "",
|
||
# 'description': 'Plaster; one coat Thistle board finish or other equal; steel trowelled; 3 mm thick work '
|
||
# 'to walls or ceilings; one coat; to plasterboard base; over 600mm wide',
|
||
# 'labour_cost': 6.58,
|
||
# 'labour_hours_per_unit': 0.25,
|
||
# 'link': "",
|
||
# 'material_cost': 0.06,
|
||
# 'plant_cost': 0,
|
||
# 'prime_material_cost': 0.0,
|
||
# 'thermal_conductivity': "",
|
||
# 'thermal_conductivity_unit': "",
|
||
# 'total_cost': 6.64,
|
||
# 'type': 'iwi_redecoration'},
|
||
# {'Notes': "",
|
||
# 'cost_unit': "",
|
||
# 'depth': "",
|
||
# 'depth_unit': "",
|
||
# 'description': 'Two coats emulsion paint on plaster, over 40mm girth; 3.5m - '
|
||
# '5m high',
|
||
# 'labour_cost': 0.0,
|
||
# 'labour_hours_per_unit': 0.21,
|
||
# 'link': "",
|
||
# 'material_cost': 0.41,
|
||
# 'plant_cost': 0,
|
||
# 'prime_material_cost': "",
|
||
# 'thermal_conductivity': "",
|
||
# 'thermal_conductivity_unit': "",
|
||
# 'total_cost': 4.34,
|
||
# 'type': 'iwi_redecoration'},
|
||
# {'Notes': "",
|
||
# 'cost_unit': "",
|
||
# 'depth': "",
|
||
# 'depth_unit': "",
|
||
# 'description': 'Fitting existing softwood skirting or architrave to new '
|
||
# 'frames; 150mm high',
|
||
# 'labour_cost': 4.87,
|
||
# 'labour_hours_per_unit': 0.01,
|
||
# 'link': "",
|
||
# 'material_cost': 4.86,
|
||
# 'plant_cost': 0,
|
||
# 'prime_material_cost': "",
|
||
# 'thermal_conductivity': "",
|
||
# 'thermal_conductivity_unit': "",
|
||
# 'total_cost': 4.88,
|
||
# 'type': 'iwi_redecoration'}
|
||
# ]
|
||
#
|
||
# material = {
|
||
# "type": "internal_wall_insulation",
|
||
# "description": "Ecotherm Eco-Versal PIR Insulation Board",
|
||
# "depth": 150,
|
||
# "depth_unit": "mm",
|
||
# "cost_unit": "gbp_per_m2",
|
||
# "thermal_conductivity": 0.022,
|
||
# "thermal_conductivity_unit": "watt_per_meter_kelvin",
|
||
# "prime_material_cost": "",
|
||
# "material_cost": 11.68,
|
||
# "labour_cost": 3.12,
|
||
# "labour_hours_per_unit": 0.18,
|
||
# "plant_cost": "",
|
||
# "total_cost": 14.8,
|
||
# "link": "SPONs"
|
||
# }
|
||
|
||
# Cost per m2
|
||
# wall_area = self.property.insulation_wall_area
|
||
|
||
# Extract and check the different types of data we'll need
|
||
demolition_data = [x for x in non_insulation_materials if x["type"] == "iwi_wall_demolition"]
|
||
vapour_barrier_data = [x for x in non_insulation_materials if x["type"] == "iwi_vapour_barrier"]
|
||
redecoration_data = [x for x in non_insulation_materials if x["type"] == "iwi_redecoration"]
|
||
if not demolition_data:
|
||
raise ValueError("No data found for iwi_wall_demolition")
|
||
|
||
if (len(vapour_barrier_data) != 1) or (len(redecoration_data) != 3):
|
||
raise ValueError("Incorrect number of data entries for non-insulation materials")
|
||
|
||
# Break out the individual material costs
|
||
# Since we don't know the exact wall construction, we take an average for demolition costs, since
|
||
# the cost will depend on the type of wall construction
|
||
demolition_material_costs = np.mean([x["material_cost"] * wall_area for x in demolition_data])
|
||
insulation_material_costs = material["material_cost"] * wall_area
|
||
vapour_barrier_material_costs = vapour_barrier_data[0]["material_cost"] * wall_area
|
||
redecoration_material_costs = sum([x["material_cost"] * wall_area for x in redecoration_data])
|
||
|
||
demolition_plant_costs = np.mean([x["plant_cost"] * wall_area for x in demolition_data])
|
||
|
||
# Again for demolition, we average since we aren't sure which demolition process will be used
|
||
demolition_labour_costs = np.mean([x["labour_cost"] * wall_area for x in demolition_data])
|
||
insulation_labour_costs = material["labour_cost"] * wall_area
|
||
vapour_barrier_labour_costs = vapour_barrier_data[0]["labour_cost"] * wall_area
|
||
redecoration_labour_costs = sum([x["labour_cost"] * wall_area for x in redecoration_data])
|
||
|
||
labour_costs = (demolition_labour_costs + insulation_labour_costs + vapour_barrier_labour_costs +
|
||
redecoration_labour_costs)
|
||
|
||
labour_costs = labour_costs * self.labour_adjustment_factor
|
||
|
||
materials_costs = (demolition_material_costs + insulation_material_costs + vapour_barrier_material_costs +
|
||
redecoration_material_costs)
|
||
|
||
subtotal_before_profit = labour_costs + materials_costs + demolition_plant_costs
|
||
|
||
contingency_cost = subtotal_before_profit * self.CONTINGENCY
|
||
preliminaries_cost = subtotal_before_profit * self.PRELIMINARIES
|
||
profit_cost = subtotal_before_profit * self.PROFIT_MARGIN
|
||
|
||
subtotal_before_vat = subtotal_before_profit + contingency_cost + preliminaries_cost + profit_cost
|
||
|
||
vat_cost = subtotal_before_vat * self.VAT_RATE
|
||
|
||
total_cost = subtotal_before_vat + vat_cost
|
||
|
||
demolition_labour_hours = np.mean([x["labour_hours_per_unit"] * wall_area for x in demolition_data])
|
||
insulation_labour_hours = material["labour_hours_per_unit"] * wall_area
|
||
vapour_barrier_labour_hours = vapour_barrier_data[0]["labour_hours_per_unit"] * wall_area
|
||
redecoration_labour_hours = sum([x["labour_hours_per_unit"] * wall_area for x in redecoration_data])
|
||
|
||
labour_hours = (demolition_labour_hours + insulation_labour_hours + vapour_barrier_labour_hours +
|
||
redecoration_labour_hours)
|
||
|
||
# To install internal wall insulation, a small to medium size project might be conducted by a team of 3-5 people
|
||
labour_days = (labour_hours / 8) / 5
|
||
|
||
return {
|
||
"total": total_cost,
|
||
"subtotal": subtotal_before_vat,
|
||
"vat": vat_cost,
|
||
"contingency": contingency_cost,
|
||
"preliminaries": preliminaries_cost,
|
||
"material": materials_costs,
|
||
"profit": profit_cost,
|
||
"labour_hours": labour_hours,
|
||
"labour_days": labour_days
|
||
}
|
||
|
||
def suspended_floor_insulation(self, insulation_floor_area, material, non_insulation_materials):
|
||
"""
|
||
We characterise the steps for suspended floor insulation as the following tasks:
|
||
|
||
1) Removal of Carpet and Underfelt: Where necessary, remove existing floor coverings to access the floorboards.
|
||
2) Removal of Floor Boarding: Carefully remove floorboards to access the space beneath for insulation.
|
||
3) Installation of Vapour Barrier: Install a vapour barrier to prevent moisture from affecting
|
||
the insulation and floor structure.
|
||
4) Installation of Insulation: Fit the chosen insulation material between the joists in the floor void.
|
||
5) Refixing Floorboards: Replace and secure the floorboards after insulation installation.
|
||
6) Re-carpeting: Lay down the carpet or other floor coverings once the insulation and floorboards are in place.
|
||
:return:
|
||
"""
|
||
|
||
# material = {'type': 'suspended_floor_insulation', 'description': 'Thermafleece CosyWool Roll', 'depth': 140.0,
|
||
# 'depth_unit': 'mm', 'cost_unit': 'gbp_per_m2', 'thermal_conductivity': 0.039,
|
||
# 'thermal_conductivity_unit': 'watt_per_meter_kelvin', 'prime_material_cost': 0,
|
||
# 'material_cost': 11.68, 'labour_cost': 1.78, 'labour_hours_per_unit': 0.1, 'plant_cost': 0,
|
||
# 'total_cost': 13.46, 'link': 'SPONs',
|
||
# 'Notes': 'Spons did not contain labour costs so we use values for similar insulations. We use
|
||
# the '
|
||
# 'same values as in Crown loft roll 44, since it is also an insulation roll'}
|
||
#
|
||
# non_insulation_materials = [
|
||
# {'type': 'suspended_floor_demolition', 'description': 'Removal of carpet and underfelt', 'depth': 0,
|
||
# 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 0, 'labour_cost': 3.32, 'labour_hours_per_unit': 0.11,
|
||
# 'plant_cost': 0, 'total_cost': 3.32, 'link': 'SPONs',
|
||
# 'Notes': 'We ignore the plant cost that is in SPONs because we assume the carpet is not scrapped and '
|
||
# 'therefore there is no need for a skip'},
|
||
# {'type': 'suspended_floor_demolition',
|
||
# 'description': 'Remove boarding; withdraw nails; set aside for reuse; ground level', 'depth': 0,
|
||
# 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 0, 'labour_cost': 9.34, 'labour_hours_per_unit': 0.3,
|
||
# 'plant_cost': 0, 'total_cost': 9.34, 'link': 'SPONs', 'Notes': 0},
|
||
# {'type': 'suspended_floor_vapour_barrier', 'description': 'Visqueen High Performance Vapour Barrier',
|
||
# 'depth': 0, 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0,
|
||
# 'thermal_conductivity_unit': 0, 'prime_material_cost': 0.58, 'material_cost': 1.21, 'labour_cost': 0.48,
|
||
# 'labour_hours_per_unit': 0.02, 'plant_cost': 0, 'total_cost': 1.69, 'link': 'SPONs', 'Notes': 0},
|
||
# {'type': 'suspended_floor_redecoration', 'description': 'refix floorboards previously set aside',
|
||
# 'depth': 0, 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0,
|
||
# 'thermal_conductivity_unit': 0, 'prime_material_cost': 0, 'material_cost': 1.54, 'labour_cost': 24.98,
|
||
# 'labour_hours_per_unit': 0.74, 'plant_cost': 0, 'total_cost': 26.52, 'link': 'SPONs', 'Notes': 0},
|
||
# {'type': 'suspended_floor_redecoration', 'description': 'Fitting carpet', 'depth': 0, 'depth_unit': 0,
|
||
# 'cost_unit': 0, 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 0, 'labour_cost': 6.59, 'labour_hours_per_unit': 0.37,
|
||
# 'plant_cost': 0, 'total_cost': 6.59, 'link': 'SPONs',
|
||
# 'Notes': 'SPONs does not have data on re-fitting the carpet so we use the data in Fitted carpeting; '
|
||
# 'Gradus woven polypropylene tufted loop\n\n as a baseline. We assume re-use of carpets, '
|
||
# 'therefore we need just labour rates'}]
|
||
|
||
# insulation_floor_area = self.property.floor_area / self.property.number_of_floors
|
||
|
||
demolition_data = [x for x in non_insulation_materials if x["type"] == "suspended_floor_demolition"]
|
||
vapour_barrier_data = [x for x in non_insulation_materials if x["type"] == "suspended_floor_vapour_barrier"]
|
||
redecoration_data = [x for x in non_insulation_materials if x["type"] == "suspended_floor_redecoration"]
|
||
|
||
if (len(demolition_data) != 2) or (len(vapour_barrier_data) != 1) or (len(redecoration_data) != 2):
|
||
raise ValueError("Incorrect number of data entries for non-insulation materials")
|
||
|
||
# Break out the individual material costs
|
||
demolition_material_costs = sum([x["material_cost"] * insulation_floor_area for x in demolition_data])
|
||
insulation_material_costs = material["material_cost"] * insulation_floor_area
|
||
vapour_barrier_material_costs = vapour_barrier_data[0]["material_cost"] * insulation_floor_area
|
||
redecoration_material_costs = sum([x["material_cost"] * insulation_floor_area for x in redecoration_data])
|
||
|
||
demolition_labour_costs = sum([x["labour_cost"] * insulation_floor_area for x in demolition_data])
|
||
insulation_labour_costs = material["labour_cost"] * insulation_floor_area
|
||
vapour_barrier_labour_costs = vapour_barrier_data[0]["labour_cost"] * insulation_floor_area
|
||
redecoration_labour_costs = sum([x["labour_cost"] * insulation_floor_area for x in redecoration_data])
|
||
|
||
labour_costs = (demolition_labour_costs + insulation_labour_costs + vapour_barrier_labour_costs +
|
||
redecoration_labour_costs)
|
||
|
||
labour_costs = labour_costs * self.labour_adjustment_factor
|
||
|
||
materials_costs = (demolition_material_costs + insulation_material_costs + vapour_barrier_material_costs +
|
||
redecoration_material_costs)
|
||
|
||
subtotal_before_profit = labour_costs + materials_costs
|
||
|
||
contingency_cost = subtotal_before_profit * self.CONTINGENCY
|
||
preliminaries_cost = subtotal_before_profit * self.PRELIMINARIES
|
||
profit_cost = subtotal_before_profit * self.PROFIT_MARGIN
|
||
|
||
subtotal_before_vat = subtotal_before_profit + contingency_cost + preliminaries_cost + profit_cost
|
||
|
||
vat_cost = subtotal_before_vat * self.VAT_RATE
|
||
|
||
total_cost = subtotal_before_vat + vat_cost
|
||
|
||
demolition_labour_hours = sum([x["labour_hours_per_unit"] * insulation_floor_area for x in demolition_data])
|
||
insulation_labour_hours = material["labour_hours_per_unit"] * insulation_floor_area
|
||
vapour_barrier_labour_hours = vapour_barrier_data[0]["labour_hours_per_unit"] * insulation_floor_area
|
||
redecoration_labour_hours = sum([x["labour_hours_per_unit"] * insulation_floor_area for x in redecoration_data])
|
||
|
||
labour_hours = (demolition_labour_hours + insulation_labour_hours + vapour_barrier_labour_hours +
|
||
redecoration_labour_hours)
|
||
|
||
# Assume a team of 3 people for a small to medium size project
|
||
labour_days = (labour_hours / 8) / 3
|
||
|
||
return {
|
||
"total": total_cost,
|
||
"subtotal": subtotal_before_vat,
|
||
"vat": vat_cost,
|
||
"contingency": contingency_cost,
|
||
"preliminaries": preliminaries_cost,
|
||
"material": materials_costs,
|
||
"profit": profit_cost,
|
||
"labour_hours": labour_hours,
|
||
"labour_days": labour_days
|
||
}
|
||
|
||
def solid_floor_insulation(self, insulation_floor_area, material, non_insulation_materials):
|
||
"""
|
||
We characterise the steps for solid floor insulation as the following tasks:
|
||
|
||
1) Removal of Carpet and Underfelt: This is the initial stage where any existing floor coverings, like carpets,
|
||
tiles, or linoleum, are carefully removed. This exposes the solid floor beneath, which is typically concrete.
|
||
|
||
2) Preparation of Flooring: This step is critical. It involves:
|
||
- Cleaning the existing floor surface thoroughly to remove debris and ensure a flat surface.
|
||
- Assessing and repairing any damage to the concrete floor. This might include filling cracks or leveling
|
||
uneven areas.
|
||
|
||
3) Installation of a Damp Proof Membrane (DPM): Before installing insulation, a DPM is often laid down to
|
||
prevent moisture from rising into the insulation and the interior space. This step is crucial in areas prone to
|
||
dampness.
|
||
|
||
4) Install Insulation: The insulation, often in the form of rigid foam boards, is laid over the DPM.
|
||
The choice of insulation material will depend on the desired thermal properties and the available floor height.
|
||
Care is taken to minimize thermal bridges and ensure a snug fit between insulation boards.
|
||
|
||
5) Laying a New Subfloor: Over the insulation, a new subfloor is often installed. This could be a layer of
|
||
screed (a type of concrete) or wooden boarding, depending on the specific requirements and preferences.
|
||
|
||
6) Re-decoration and Finishing Touches: Once the subfloor is in place and has set or dried (if necessary),
|
||
the final floor finish can be applied. This might involve:
|
||
- Laying new tiles, wooden flooring, or other chosen materials.
|
||
- If you're planning to re-carpet, this would be the stage to do it.
|
||
- Skirting boards may need to be refitted or replaced.
|
||
|
||
7) Considerations for Doors and Fixtures: It's important to note that raising the floor level can affect door
|
||
thresholds and other fixtures. Doors may need to be trimmed, and fixtures might need adjustments.
|
||
:param material:
|
||
:param non_insulation_materials:
|
||
:return:
|
||
"""
|
||
|
||
# material = {
|
||
# 'type': 'solid_floor_insulation', 'description': 'Kay-Cel Expanded Polystyrene Board',
|
||
# 'depth': 100.0, 'depth_unit': 'mm', 'cost_unit': 'gbp_per_m2', 'thermal_conductivity': 0.033,
|
||
# 'thermal_conductivity_unit': 'watt_per_meter_kelvin', 'prime_material_cost': 0,
|
||
# 'material_cost': 12.02, 'labour_cost': 4.4, 'labour_hours_per_unit': 0.19, 'plant_cost': 0,
|
||
# 'total_cost': 16.42, 'link': 'SPONs', 'Notes': 0
|
||
# }
|
||
#
|
||
# non_insulation_materials = [
|
||
# {'type': 'solid_floor_demolition', 'description': 'Removal of carpet and underfelt', 'depth': 0,
|
||
# 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 0, 'labour_cost': 3.32, 'labour_hours_per_unit': 0.11,
|
||
# 'plant_cost': 0, 'total_cost': 3.32, 'link': 'SPONs',
|
||
# 'Notes': 'We ignore the plant cost that is in SPONs because we assume the carpet is not scrapped and '
|
||
# 'therefore there is no need for a skip'},
|
||
# {'type': 'solid_floor_preparation',
|
||
# 'description': 'clean surface of concrete to receive new damp-proof membrane', 'depth': 0,
|
||
# 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 0, 'labour_cost': 4.36, 'labour_hours_per_unit': 0.14,
|
||
# 'plant_cost': 0, 'total_cost': 4.36, 'link': 0, 'Notes': 0}, {'type': 'solid_floor_preparation',
|
||
# 'description': 'Clean out crack to '
|
||
# 'form a 20mm×20mm '
|
||
# 'groove and fill with '
|
||
# 'cement: mortar mixed '
|
||
# 'with bonding agent',
|
||
# 'depth': 0, 'depth_unit': 0,
|
||
# 'cost_unit': 0,
|
||
# 'thermal_conductivity': 0,
|
||
# 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0,
|
||
# 'material_cost': 6.91,
|
||
# 'labour_cost': 18.99,
|
||
# 'labour_hours_per_unit': 0.61,
|
||
# 'plant_cost': 0.16,
|
||
# 'total_cost': 26.06, 'link': 0,
|
||
# 'Notes': 'This step is the '
|
||
# 'assessment and repair of '
|
||
# 'any damage to the concrete '
|
||
# 'floor such as filling '
|
||
# 'cracks or levelling uneven '
|
||
# 'areas'},
|
||
# {'type': 'solid_floor_vapour_barrier', 'description': 'Visqueen High Performance Vapour Barrier',
|
||
# 'depth': 0, 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0,
|
||
# 'thermal_conductivity_unit': 0, 'prime_material_cost': 0.58, 'material_cost': 1.21, 'labour_cost': 0.48,
|
||
# 'labour_hours_per_unit': 0.02, 'plant_cost': 0, 'total_cost': 1.69, 'link': 'SPONs', 'Notes': 0},
|
||
# {'type': 'solid_floor_redecoration',
|
||
# 'description': 'Screeded beds; protection to compressible formwork exceeding 600mm wide', 'depth': 0,
|
||
# 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 9.6, 'material_cost': 9.89, 'labour_cost': 2.67, 'labour_hours_per_unit': 0.15,
|
||
# 'plant_cost': 0, 'total_cost': 12.56, 'link': 'SPONs',
|
||
# 'Notes': 'This is the screed layer, placed on top of the insulation'},
|
||
# {'type': 'solid_floor_redecoration', 'description': 'Fitting carpet', 'depth': 0, 'depth_unit': 0,
|
||
# 'cost_unit': 0, 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 0, 'labour_cost': 6.59, 'labour_hours_per_unit': 0.37,
|
||
# 'plant_cost': 0, 'total_cost': 6.59, 'link': 'SPONs',
|
||
# 'Notes': 'SPONs does not have data on re-fitting the carpet so we use the data in Fitted carpeting; '
|
||
# 'Gradus woven polypropylene tufted loop\n\n as a baseline. We assume re-use of carpets, '
|
||
# 'therefore we need just labour rates'},
|
||
# {'type': 'solid_floor_redecoration',
|
||
# 'description': 'Fitting existing softwood skirting or architrave to new frames; 150mm high', 'depth': 0,
|
||
# 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 0.01, 'labour_cost': 4.87, 'labour_hours_per_unit': 0.12,
|
||
# 'plant_cost': 0, 'total_cost': 4.88, 'link': 'SPONs', 'Notes': 0}
|
||
# ]
|
||
|
||
# insulation_floor_area = self.property.floor_area / self.property.number_of_floors
|
||
|
||
demolition_data = [x for x in non_insulation_materials if x["type"] == "solid_floor_demolition"]
|
||
preparation_data = [x for x in non_insulation_materials if x["type"] == "solid_floor_preparation"]
|
||
vapour_barrier_data = [x for x in non_insulation_materials if x["type"] == "solid_floor_vapour_barrier"]
|
||
redecoration_data = [x for x in non_insulation_materials if x["type"] == "solid_floor_redecoration"]
|
||
|
||
if ((len(demolition_data) != 1) or (len(preparation_data) != 2) or (len(vapour_barrier_data) != 1) or
|
||
(len(redecoration_data) != 3)):
|
||
raise ValueError("Incorrect number of data entries for non-insulation materials")
|
||
|
||
# Break out the individual material costs
|
||
preparation_material_costs = sum([x["material_cost"] * insulation_floor_area for x in preparation_data])
|
||
insulation_material_costs = material["material_cost"] * insulation_floor_area
|
||
vapour_barrier_material_costs = vapour_barrier_data[0]["material_cost"] * insulation_floor_area
|
||
redecoration_material_costs = sum([x["material_cost"] * insulation_floor_area for x in redecoration_data])
|
||
|
||
demolition_labour_costs = sum([x["labour_cost"] * insulation_floor_area for x in demolition_data])
|
||
preparation_labour_costs = sum([x["labour_cost"] * insulation_floor_area for x in preparation_data])
|
||
insulation_labour_costs = material["labour_cost"] * insulation_floor_area
|
||
vapour_barrier_labour_costs = vapour_barrier_data[0]["labour_cost"] * insulation_floor_area
|
||
redecoration_labour_costs = sum([x["labour_cost"] * insulation_floor_area for x in redecoration_data])
|
||
|
||
preparation_plant_costs = sum([x["plant_cost"] * insulation_floor_area for x in preparation_data])
|
||
|
||
labour_costs = (demolition_labour_costs + insulation_labour_costs + vapour_barrier_labour_costs +
|
||
redecoration_labour_costs + preparation_labour_costs)
|
||
|
||
labour_costs = labour_costs * self.labour_adjustment_factor
|
||
|
||
materials_cost = (preparation_material_costs + insulation_material_costs + vapour_barrier_material_costs +
|
||
redecoration_material_costs)
|
||
|
||
subtotal_before_profit = labour_costs + materials_cost + preparation_plant_costs
|
||
|
||
# We use HIGH_RISH_CONTINGENCY because of the potential for issues with moving fittings and trimming doors,
|
||
# as well as scope for damage to the existing floor during preparation.
|
||
contingency_cost = subtotal_before_profit * self.HIGH_RISK_CONTINGENCY
|
||
preliminaries_cost = subtotal_before_profit * self.PRELIMINARIES
|
||
profit_cost = subtotal_before_profit * self.PROFIT_MARGIN
|
||
|
||
subtotal_before_vat = subtotal_before_profit + contingency_cost + preliminaries_cost + profit_cost
|
||
vat_cost = subtotal_before_vat * self.VAT_RATE
|
||
total_cost = subtotal_before_vat + vat_cost
|
||
|
||
demolition_labour_hours = sum([x["labour_hours_per_unit"] * insulation_floor_area for x in demolition_data])
|
||
preparation_labour_hours = sum([x["labour_hours_per_unit"] * insulation_floor_area for x in preparation_data])
|
||
insulation_labour_hours = material["labour_hours_per_unit"] * insulation_floor_area
|
||
vapour_barrier_labour_hours = vapour_barrier_data[0]["labour_hours_per_unit"] * insulation_floor_area
|
||
redecoration_labour_hours = sum([x["labour_hours_per_unit"] * insulation_floor_area for x in redecoration_data])
|
||
|
||
labour_hours = (demolition_labour_hours + insulation_labour_hours + vapour_barrier_labour_hours +
|
||
redecoration_labour_hours + preparation_labour_hours)
|
||
|
||
# Assume a team of 3 people for a small to medium size project
|
||
labour_days = (labour_hours / 8) / 3
|
||
|
||
return {
|
||
"total": total_cost,
|
||
"subtotal": subtotal_before_vat,
|
||
"vat": vat_cost,
|
||
"contingency": contingency_cost,
|
||
"preliminaries": preliminaries_cost,
|
||
"material": materials_cost,
|
||
"profit": profit_cost,
|
||
"labour_hours": labour_hours,
|
||
"labour_days": labour_days
|
||
}
|
||
|
||
def external_wall_insulation(self, wall_area, material, non_insulation_materials):
|
||
"""
|
||
We characterise external wall insulation as the following steps:
|
||
|
||
1) Preparation of the Area: Tidying up the surroundings, trimming back foliage, and laying down protective
|
||
sheets to protect the flooring and landscaping around the work area.
|
||
|
||
2) Scaffolding Setup (if needed): Erecting scaffolding for safe access to the walls of semi-detached or
|
||
detached houses. For terraced houses or lower-level work, scaffolding might not be necessary.
|
||
|
||
3) Wall Surface Preparation: Cleaning the wall surface, removing any loose or flaking material,
|
||
and possibly applying a primer. If the existing wall is weak or damaged, partial or full replacement
|
||
of the top surface may be necessary.
|
||
|
||
4) Applying Primer: If the existing wall is suitable, applying a primer to improve adhesion of the insulation
|
||
boards and stabilize the wall surface, especially if it's old or weathered.
|
||
|
||
5) Insulation Application: Attaching insulation boards to the primed wall using adhesive, mechanical fixings,
|
||
or a combination of both.
|
||
|
||
6) Basecoat and Mesh Application: Applying a basecoat embedded with a reinforcing mesh over the insulation.
|
||
This layer provides strength and helps prevent cracking.
|
||
|
||
7) Decorative Finish: Applying a decorative finish, such as render or cladding, which protects the insulation
|
||
and provides an aesthetic look.
|
||
|
||
8) Reinstalling Fixtures: Reattaching any fixtures like downpipes, satellite dishes, or lighting fixtures that
|
||
were removed during preparation. Extensions or adjustments may be required due to the increased wall thickness.
|
||
|
||
9) Inspection and Cleanup: Conducting a thorough inspection to ensure quality and integrity of the EWI system,
|
||
followed by cleaning up the site to remove all debris and materials.
|
||
|
||
In the actual materials data, at this point, we have costing for:
|
||
- wall preparation, hacking off existing wall finishes, linings, etc (ewi_wall_demolition)
|
||
- wall surface cleaning and priming (ewi_wall_preparation)
|
||
- insulation (external_wall_insulation)
|
||
- basecoat and mesh with decorative render topcoat finish (ewi_basecoat_and_mesh)
|
||
|
||
All of this data comes from SPONS, however there are some clear features missing. Because we could not find
|
||
suitable cost records in SPONS for steps like cleaning the area, setting up small scale scaffolding,
|
||
re-attaching any fitings and cleaning up the area afterwards, instead we have accounted for these steps by
|
||
increasing the preliminaries rate. It is acknowldeged though, that this is not ideal and that the cost of these
|
||
steps should be included in the materials data. We will look to improve this in the future, with data from
|
||
installers
|
||
|
||
:param wall_area:
|
||
:param material:
|
||
:param non_insulation_materials:
|
||
:return:
|
||
"""
|
||
|
||
# For semi detatched and detatched houses, as well as maisonettes, we price for scaffolding
|
||
|
||
if self.property.data["property-type"] == "House":
|
||
if self.property.data["built-form"] in ['Semi-Detached', 'Detached', "End-Terrace"]:
|
||
preliminaries_rate = self.EWI_SCAFFOLDING_PRELIMINARIES
|
||
else:
|
||
preliminaries_rate = self.EWI_NO_SCAFFOLDING_PRELIMINARIES
|
||
elif self.property.data["property-type"] == "Maisonette":
|
||
preliminaries_rate = self.EWI_SCAFFOLDING_PRELIMINARIES
|
||
elif self.property.data["property-type"] == "Bungalow":
|
||
preliminaries_rate = self.EWI_NO_SCAFFOLDING_PRELIMINARIES
|
||
else:
|
||
raise ValueError("Unsupported property type - haven't handled flats")
|
||
|
||
# non_insulation_materials = [x for x in df if x["type"] != "external_wall_insulation"]
|
||
# insulation_materials = [x for x in df if x["type"] == "external_wall_insulation"]
|
||
# material = {'type': 'external_wall_insulation', 'description': 'Ecotherm Eco-Versal PIR Insulation Board',
|
||
# 'depth': 150.0, 'depth_unit': 'mm', 'cost_unit': 'gbp_per_m2', 'thermal_conductivity': 0.022,
|
||
# 'thermal_conductivity_unit': 'watt_per_meter_kelvin', 'prime_material_cost': 23.53,
|
||
# 'material_cost': 34.62, 'labour_cost': 33.06, 'labour_hours_per_unit': 1.4, 'plant_cost': 0,
|
||
# 'total_cost': 67.68, 'link': 'SPONs', 'Notes': 0}
|
||
# non_insulation_materials = [
|
||
# {'type': 'ewi_wall_demolition',
|
||
# 'description': 'Solid & Dry Lined walls: Hack of wall finishes with chipping '
|
||
# 'hammer; plaster to walls.',
|
||
# 'depth': 0, 'depth_unit': 0, 'cost_unit': 'gbp_per_m2',
|
||
# 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 0, 'labour_cost': 10.27,
|
||
# 'labour_hours_per_unit': 0.33, 'plant_cost': 1.28, 'total_cost': 11.55,
|
||
# 'link': 'SPONs', 'Notes': 0}, {'type': 'ewi_wall_demolition',
|
||
# 'description': 'Stud walls: Remove wall linings '
|
||
# 'including battening behind; '
|
||
# 'plasterboard and skim',
|
||
# 'depth': 0, 'depth_unit': 0,
|
||
# 'cost_unit': 'gbp_per_m2',
|
||
# 'thermal_conductivity': 0,
|
||
# 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 0,
|
||
# 'labour_cost': 6.23, 'labour_hours_per_unit': 0.2,
|
||
# 'plant_cost': 1.25, 'total_cost': 7.48,
|
||
# 'link': 'SPONs', 'Notes': 0},
|
||
# {'type': 'ewi_wall_demolition',
|
||
# 'description': 'Lathe and Plaster walls: Remove wall linings including battening '
|
||
# 'behind; wood lath and plaster',
|
||
# 'depth': 0, 'depth_unit': 0, 'cost_unit': 'gbp_per_m2',
|
||
# 'thermal_conductivity': 0, 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 0, 'labour_cost': 6.85,
|
||
# 'labour_hours_per_unit': 0.22, 'plant_cost': 2.09, 'total_cost': 8.94,
|
||
# 'link': 'SPONs', 'Notes': 0}, {'type': 'ewi_wall_preparation',
|
||
# 'description': 'Clean and prepare surfaces, '
|
||
# 'one coat Keim dilution, '
|
||
# 'one coat primer and two coats '
|
||
# 'of Keim Ecosil paint; Brick or '
|
||
# 'block walls; over 300 mm girth',
|
||
# 'depth': 0, 'depth_unit': 0, 'cost_unit': 0,
|
||
# 'thermal_conductivity': 0,
|
||
# 'thermal_conductivity_unit': 0,
|
||
# 'prime_material_cost': 0, 'material_cost': 7.3,
|
||
# 'labour_cost': 5.62, 'labour_hours_per_unit': 0.3,
|
||
# 'plant_cost': 0, 'total_cost': 12.92,
|
||
# 'link': 'SPONs',
|
||
# 'Notes': 'This work covers the preparation and '
|
||
# 'priming of the wall before insulating'},
|
||
# {'type': 'ewi_wall_redecoration',
|
||
# 'description': 'EPS insulation fixed with adhesive to SFS structure (measured '
|
||
# 'separately) with horizontal PVC intermediate track and vertical '
|
||
# 'T-spines; with glassfibre mesh reinforcement embedded in Sto '
|
||
# 'Armat Classic Basecoat Render and Stolit K 1.5 Decorative '
|
||
# 'Topcoat Render (white)',
|
||
# 'depth': 0, 'depth_unit': 0, 'cost_unit': 0, 'thermal_conductivity': 0,
|
||
# 'thermal_conductivity_unit': 0, 'prime_material_cost': 0, 'material_cost': 0,
|
||
# 'labour_cost': 0, 'labour_hours_per_unit': 0, 'plant_cost': 0,
|
||
# 'total_cost': 69.94, 'link': 'SPONs',
|
||
# 'Notes': 'This material in SPONs is for 70mm EPS insulation, which comes in at a '
|
||
# 'cost of 99.17 per meter square. This includes the cost of insulation. '
|
||
# 'To get the costing for just the works and not the insulation, '
|
||
# 'we subtract the cost of EPS insulation, using Ravathem 75mm insulation '
|
||
# 'as an example, which costs £29.23 per meter square, giving us the cost '
|
||
# 'of the remaining works without insulation. This material gives us a '
|
||
# 'cost for basecoat, mesh application and a render finish'}]
|
||
|
||
demolition_data = [x for x in non_insulation_materials if x["type"] == "ewi_wall_demolition"]
|
||
preparation_data = [x for x in non_insulation_materials if x["type"] == "ewi_wall_preparation"]
|
||
redecoration_data = [x for x in non_insulation_materials if x["type"] == "ewi_wall_redecoration"]
|
||
|
||
if (len(demolition_data) != 3) or (len(preparation_data) != 1) or (len(redecoration_data) != 1):
|
||
raise ValueError("Incorrect number of data entries for non-insulation materials")
|
||
|
||
# Break out the individual material costs
|
||
# Since we don't know the exact wall construction, we take an average for demolition costs, since
|
||
# the cost will depend on the type of wall construction
|
||
demolition_material_costs = np.mean([x["material_cost"] * wall_area for x in demolition_data])
|
||
insulation_material_costs = material["material_cost"] * wall_area
|
||
preparation_material_costs = preparation_data[0]["material_cost"] * wall_area
|
||
redecoration_material_costs = redecoration_data[0]["material_cost"] * wall_area
|
||
|
||
demolition_plant_costs = np.mean([x["plant_cost"] * wall_area for x in demolition_data])
|
||
|
||
demolition_labour_costs = np.mean([x["labour_cost"] * wall_area for x in demolition_data])
|
||
insulation_labour_costs = material["labour_cost"] * wall_area
|
||
preparation_labour_costs = preparation_data[0]["labour_cost"] * wall_area
|
||
redecoration_labour_costs = redecoration_data[0]["labour_cost"] * wall_area
|
||
|
||
labour_costs = (demolition_labour_costs + insulation_labour_costs + redecoration_labour_costs +
|
||
preparation_labour_costs)
|
||
|
||
labour_costs = labour_costs * self.labour_adjustment_factor
|
||
|
||
materials_costs = (demolition_material_costs + insulation_material_costs + preparation_material_costs +
|
||
redecoration_material_costs)
|
||
|
||
subtotal_before_profit = labour_costs + materials_costs + demolition_plant_costs
|
||
|
||
contingency_cost = subtotal_before_profit * self.CONTINGENCY
|
||
preliminaries_cost = subtotal_before_profit * preliminaries_rate
|
||
profit_cost = subtotal_before_profit * self.PROFIT_MARGIN
|
||
|
||
subtotal_before_vat = subtotal_before_profit + contingency_cost + preliminaries_cost + profit_cost
|
||
vat_cost = subtotal_before_vat * self.VAT_RATE
|
||
total_cost = subtotal_before_vat + vat_cost
|
||
|
||
demolition_labour_hours = np.mean([x["labour_hours_per_unit"] * wall_area for x in demolition_data])
|
||
insulation_labour_hours = material["labour_hours_per_unit"] * wall_area
|
||
preparation_labour_hours = preparation_data[0]["labour_hours_per_unit"] * wall_area
|
||
redecoration_labour_hours = redecoration_data[0]["labour_hours_per_unit"] * wall_area
|
||
|
||
labour_hours = (demolition_labour_hours + insulation_labour_hours + redecoration_labour_hours +
|
||
preparation_labour_hours)
|
||
|
||
# Assume a team of 3-5 people for a small to medium size project
|
||
labour_days = (labour_hours / 8) / 4
|
||
|
||
return {
|
||
"total": total_cost,
|
||
"subtotal": subtotal_before_vat,
|
||
"vat": vat_cost,
|
||
"contingency": contingency_cost,
|
||
"preliminaries": preliminaries_cost,
|
||
"material": materials_costs,
|
||
"profit": profit_cost,
|
||
"labour_hours": labour_hours,
|
||
"labour_days": labour_days
|
||
}
|