completed pricing for ewi

This commit is contained in:
Khalim Conn-Kowlessar 2023-11-23 14:51:30 +00:00
parent dea9a7fb17
commit 63de7c19df

View file

@ -29,7 +29,7 @@ p2.set_basic_property_dimensions()
import pandas as pd
df = pd.read_csv("/Users/khalimconn-kowlessar/Downloads/Hestia Materials - solid_floor_insulation.csv")
df = pd.read_csv("/Users/khalimconn-kowlessar/Downloads/Hestia Materials - external_wall_insulation.csv")
df = df.to_dict("records")
# This data comes from SPONs
@ -61,8 +61,11 @@ class Costs:
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 walls and expected costs:
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
@ -70,13 +73,22 @@ class Costs:
CONTINGENCY = 0.1
# Where there is more uncertainty, a higher contingency rate is used
HIGH_RISH_CONTINGENCY = 0.15
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
@ -355,7 +367,8 @@ class Costs:
demolition_plant_costs = np.mean([x["plant_cost"] * wall_area for x in demolition_data])
demolition_labour_costs = sum([x["labour_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])
@ -380,7 +393,7 @@ class Costs:
total_cost = subtotal_before_vat + vat_cost
demolition_labour_hours = sum([x["labour_hours_per_unit"] * wall_area for x in demolition_data])
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])
@ -553,70 +566,70 @@ class Costs:
: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}
]
# 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
@ -655,7 +668,7 @@ class 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_RISH_CONTINGENCY
contingency_cost = subtotal_before_profit * self.HIGH_RISK_CONTINGENCY
preliminaries_cost = subtotal_before_profit * self.PRELIMINARIES
profit_cost = subtotal_before_profit * self.PROFIT_MARGIN
@ -686,3 +699,198 @@ class Costs:
"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
}