Model/recommendations/Costs.py
2023-11-23 08:47:37 +00:00

688 lines
37 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 - solid_floor_insulation.csv")
df = df.to_dict("records")
# This data comes from SPONs
regional_labour_variations = [
{"Region": "Outer London (Spons 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 walls and expected costs:
https://www.checkatrade.com/blog/cost-guides/retrofit-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_RISH_CONTINGENCY = 0.15
# 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
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])
demolition_labour_costs = sum([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 = sum([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_RISH_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
}