From 36576c8d40adbf20173a71b51fafda1914de258b Mon Sep 17 00:00:00 2001 From: Sigma Dimensions <79010126+myoualid@users.noreply.github.com> Date: Mon, 5 Sep 2022 01:51:53 +0100 Subject: [PATCH] IFC resources utility: batch import Resource Data from CSV --- src/ifcresources/ifcresources/csv2ifc.py | 147 ++++++++++++++++++++ src/ifcresources/ifcresources/resources.csv | 30 ++++ 2 files changed, 177 insertions(+) create mode 100644 src/ifcresources/ifcresources/csv2ifc.py create mode 100644 src/ifcresources/ifcresources/resources.csv diff --git a/src/ifcresources/ifcresources/csv2ifc.py b/src/ifcresources/ifcresources/csv2ifc.py new file mode 100644 index 0000000000..28022e2956 --- /dev/null +++ b/src/ifcresources/ifcresources/csv2ifc.py @@ -0,0 +1,147 @@ +# IfcResources - IFC resources utility +# Copyright (C) 2021,2022 Dion Moult , Yassine Oualid +# +# This file is part of IfcResources. +# +# IfcResources is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# IfcResources is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcResources. If not, see . + +import csv +import ifcopenshell +import ifcopenshell.api +import ifcopenshell.util.unit + + +class Csv2Ifc: + def __init__(self): + self.csv = None + self.file = None + self.resource_items = [] + self.cost_schedule = None + self.is_schedule_of_rates = False + self.units = {} + + def execute(self): + self.parse_csv() + self.create_ifc() + + def parse_csv(self): + self.parents = {} + self.headers = {} + with open(self.csv, "r") as csv_file: + reader = csv.reader(csv_file) + for row in reader: + if not row[0]: + continue + if row[0] == "Hierarchy": + for i, col in enumerate(row): + if not col: + continue + self.headers[col] = i + continue + cost_data = self.get_row_resource_data(row) + hierarchy_key = int(row[0]) + if hierarchy_key == 1: + self.resource_items.append(cost_data) + else: + self.parents[hierarchy_key - 1]["children"].append(cost_data) + self.parents[hierarchy_key] = cost_data + + def get_row_resource_data(self, row): + name = row[self.headers["Name"]] + identification = row[self.headers["Identification"]] if "Identification" in self.headers else None + + type = row[self.headers["Type"]] + base_cost_value = row[self.headers["BaseCostValue"]] + base_cost_quantity = row[self.headers["BaseCostQuantity"]] + base_cost_unit = row[self.headers["QuantityUnit"]] + + productivity = { + "BaseQuantityConsumed": row[self.headers["BaseQuantityConsumed"]], + "BaseQuantityProducedName": row[self.headers["BaseQuantityProducedName"]], + "BaseQuantityProducedValue": row[self.headers["BaseQuantityProducedValue"]], + } + + return { + "Identification": str(identification) if identification else None, + "Name": str(name) if name else None, + "Type": type, + "BaseCostValue": float(base_cost_value) if base_cost_value else None, + "BaseCostQuantity": float(base_cost_quantity) if base_cost_quantity else None, + "Unit": str(base_cost_unit) if base_cost_unit else None, + "Productivity": productivity if productivity["BaseQuantityProducedName"] else None, + "children": [], + } + + def create_ifc(self): + if not self.file: + self.create_boilerplate_ifc() + self.create_resources(self.resource_items) + + def create_resources(self, resource_items, parent=None): + for resource in resource_items: + self.create_resource(resource, parent) + + def create_resource(self, resource, parent): + if parent is None: + resource["ifc"] = ifcopenshell.api.run("resource.add_resource", self.file, ifc_class=resource["Type"]) + else: + resource["ifc"] = ifcopenshell.api.run( + "resource.add_resource", self.file, parent_resource=parent, ifc_class=resource["Type"] + ) + resource["ifc"].Name = resource["Name"] + resource["ifc"].Identification = resource["Identification"] + productivity = resource["Productivity"] + if productivity: + pset = ifcopenshell.api.run("pset.add_pset", self.file, product=resource["ifc"], name="EPset_Productivity") + ifcopenshell.api.run( + "pset.edit_pset", + self.file, + pset=pset, + properties=productivity, + ) + if resource["BaseCostValue"]: + cost_value = ifcopenshell.api.run("cost.add_cost_value", self.file, parent=resource["ifc"]) + cost_value.AppliedValue = self.file.createIfcMonetaryMeasure(resource["BaseCostValue"]) + if resource["Unit"]: + measure_class = ifcopenshell.util.unit.get_symbol_measure_class(resource["Unit"]) + value_component = self.file.create_entity(measure_class, resource["BaseCostQuantity"]) + unit_component = None + if measure_class == "IfcNumericMeasure": + unit_component = self.create_unit(resource["Unit"]) + else: + unit_type = ifcopenshell.util.unit.get_measure_unit_type(measure_class) + unit_assignment = ifcopenshell.util.unit.get_unit_assignment(self.file) + if unit_assignment: + units = [u for u in unit_assignment.Units if getattr(u, "UnitType", None) == unit_type] + if units: + unit_component = units[0] + if not unit_component: + unit_component = self.create_unit(resource["Unit"]) + cost_value.UnitBasis = self.file.createIfcMeasureWithUnit(value_component, unit_component) + self.create_resources(resource["children"], resource["ifc"]) + + def create_unit(self, symbol): + unit = self.units.get(symbol, None) + if unit: + return unit + unit = self.file.createIfcContextDependentUnit( + self.file.createIfcDimensionalExponents(0, 0, 0, 0, 0, 0, 0), "USERDEFINED", symbol + ) + self.units[symbol] = unit + return unit + + def create_boilerplate_ifc(self): + self.file = ifcopenshell.file(schema="IFC4") + ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcProject") + ifcopenshell.api.run("unit.assign_unit", self.file) diff --git a/src/ifcresources/ifcresources/resources.csv b/src/ifcresources/ifcresources/resources.csv new file mode 100644 index 0000000000..b74c781f11 --- /dev/null +++ b/src/ifcresources/ifcresources/resources.csv @@ -0,0 +1,30 @@ +,,,,,,,Epset_Productivity,Epset_Productivity,Epset_Productivity +Hierarchy,Identification,Name,Type,BaseCostValue,BaseCostQuantity,QuantityUnit,BaseQuantityConsumed,BaseQuantityProducedName,BaseQuantityProducedValue +1,1,Self-Production,IfcCrewResource,,,,,, +,,,,,,,,, +2,1.1, Concrete Works,IfcLaborResource,,,,,, +,,,,,,,,, +3,1.1.1,In-situ Slabs,IfcLaborResource,220,9,hour ,15,GrossArea,10 +3,1.1.2,In-situ Walls,IfcLaborResource,220,9,hour ,18,GrossArea,10 +3,1.1.3,In-situ Beams,IfcLaborResource,220,9,hour ,8,Length,1 +3,1.1.4,In-situ Columns,IfcLaborResource,220,9,hour ,5,Count,1 +3,1.1.5,Finish Concrete,IfcLaborResource,220,9,hour ,5,GrossArea,10 +3,1.1.6,Drainage,IfcLaborResource,220,9,hour ,35,Length,10 +3,1.1.7,Piles Trimming,IfcLaborResource,220,9,hour ,5,Count,1 +3,1.1.8,Pile Caps,IfcLaborResource,220,9,hour ,10,Count,1 +3,1.1.9,Waterproofing/Insulation,IfcLaborResource,220,9,hour ,5,GrossArea,10 +3,1.1.10,Slabs SteelWork,IfcSubContractResource,2500,1000,m3,,GrossWeight,75 +,,,,,,,,, +2,1.2,Logistics,IfcLaborResource,,,,,, +,,,,,,,,, +3,1.2.1,Equipment,IfcConstructionEquipmentResource,,,,,, +,,,,,,,,, +4,1.2.1.1,Mobile Crane,IfcConstructionEquipmentResource,,,,,, +4,1.2.1.2,TC 1,IfcConstructionEquipmentResource,,,,,, +4,1.2.1.3,TC 2,IfcConstructionEquipmentResource,,,,,, +,,,,,,,,, +3,1.2.2,Logistics Team,IfcLaborResource,,,,,, +,,,,,,,,, +4,1.2.2.1,Crane Supervisor,IfcLaborResource,,,,,, +4,1.2.2.2,Crane Driver,IfcLaborResource,,,,,, +4,1.2.2.3,Slinger/Signaller,IfcLaborResource,,,,,,