diff --git a/src/ifc4d/ifc4d/csv2ifc.py b/src/ifc4d/ifc4d/csv2ifc.py index 7ef6a8b6d8..e60d45dd4a 100644 --- a/src/ifc4d/ifc4d/csv2ifc.py +++ b/src/ifc4d/ifc4d/csv2ifc.py @@ -20,6 +20,7 @@ import csv import ifcopenshell import ifcopenshell.api import ifcopenshell.util.unit +import datetime class Csv2Ifc: @@ -28,6 +29,14 @@ class Csv2Ifc: self.file = None self.resources = [] self.units = {} + self.resource_map = { + "CREW": "IfcCrewResource", + "LABOR": "IfcLaborResource", + "EQUIPMENT": "IfcConstructionEquipmentResource", + "SUBCONTRACTOR": "IfcSubContractResource", + "MATERIAL": "IfcConstructionMaterialResource", + "PRODUCT": "IfcConstructionProductResource", + } def execute(self): self.parse_csv() @@ -41,43 +50,46 @@ class Csv2Ifc: for row in reader: if not row[0]: continue - if row[0] == "Hierarchy": + 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) + resource_data = self.get_row_resource_data(row) hierarchy_key = int(row[0]) if hierarchy_key == 1: - self.resources.append(cost_data) + self.resources.append(resource_data) else: - self.parents[hierarchy_key - 1]["children"].append(cost_data) - self.parents[hierarchy_key] = cost_data + self.parents[hierarchy_key - 1]["children"].append(resource_data) + self.parents[hierarchy_key] = resource_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 + name = row[self.headers["ACTIVITY/RESOURCE NAME"]] + resource_class = self.resource_map[row[self.headers["TYPE"]]] + base_cost_value = row[self.headers["COST"]] + productivity = {} - 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"]] + if resource_class in ["IfcConstructionEquipmentResource", "IfcLaborResource"]: + output_ratio = row[self.headers["LABOR OUTPUT"]] + if not output_ratio: + output_ratio = row[self.headers["EQUIPMENT OUTPUT"]] + if output_ratio: + time_consumed = datetime.timedelta(minutes=float(output_ratio) * 60) + time_consumed = ifcopenshell.util.date.datetime2ifc(time_consumed, "IfcDuration") - productivity = { - "BaseQuantityConsumed": row[self.headers["BaseQuantityConsumed"]], - "BaseQuantityProducedName": row[self.headers["BaseQuantityProducedName"]], - "BaseQuantityProducedValue": row[self.headers["BaseQuantityProducedValue"]], - } + productivity = { + "BaseQuantityConsumed": time_consumed, + "BaseQuantityProducedName": row[self.headers["QUANTITY NAME"]], + "BaseQuantityProducedValue": 1, + } return { - "Identification": str(identification).strip() if identification else None, "Name": str(name).strip() if name else None, - "Type": type, + "Description": row[self.headers["DESCRIPTION"]], + "class": resource_class, "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).strip() if base_cost_unit else None, - "Productivity": productivity if productivity["BaseQuantityProducedName"] else None, + "Productivity": productivity, "children": [], } @@ -92,45 +104,25 @@ class Csv2Ifc: def create_resource(self, resource, parent): if parent is None: - resource["ifc"] = ifcopenshell.api.run("resource.add_resource", self.file, ifc_class=resource["Type"]) + resource["ifc"] = ifcopenshell.api.run("resource.add_resource", self.file, ifc_class=resource["class"]) else: resource["ifc"] = ifcopenshell.api.run( - "resource.add_resource", self.file, parent_resource=parent, ifc_class=resource["Type"] + "resource.add_resource", self.file, parent_resource=parent, ifc_class=resource["class"] ) resource["ifc"].Name = resource["Name"] - resource["ifc"].Identification = resource["Identification"] - productivity = resource["Productivity"] - if productivity: + if resource.get("Description", None): + resource["ifc"].Description = resource.get("Description") + if resource["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, + properties=resource["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"]) - print(measure_class) - value_component = self.file.create_entity(measure_class, resource["BaseCostQuantity"]) - print(value_component) - 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) - print(unit_type) - 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"], unit_type) - print(unit_component) - cost_value.UnitBasis = self.file.createIfcMeasureWithUnit(value_component, unit_component) self.create_resources(resource["children"], resource["ifc"]) def create_unit(self, symbol, unit_type): diff --git a/src/ifc4d/ifc4d/resource_spreadsheet.csv b/src/ifc4d/ifc4d/resource_spreadsheet.csv new file mode 100644 index 0000000000..47fea5d101 --- /dev/null +++ b/src/ifc4d/ifc4d/resource_spreadsheet.csv @@ -0,0 +1,63 @@ +HIERARCHY,TYPE,ACTIVITY/RESOURCE NAME,DESCRIPTION,COST,USAGE,UNIT,QUANTITY NAME,LABOR OUTPUT,EQUIPMENT OUTPUT,Productivity Unit, +1,CREW,CONCRETE WORKS,,,,,,,,, +2,LABOR,BEAMS,,,,,,,,, +3,LABOR,"Beams, 745 kg/m ",3 m span,,,Cubic Meters ,,27.3,8.61,Hr / Meter, +4,LABOR,Foreman,,25,1,Cubic Meters ,Length,27.3,,Hr / Meter, +4,LABOR, Mason,,25,4,Cubic Meters ,Length,109.2,,Hr / Meter, +4,LABOR,Carpenter &Steelman,,25,10,Cubic Meters ,Length,273,,Hr / Meter, +4,LABOR,Laborer,,25,0.25,Cubic Meters ,Length,6.825,,Hr / Meter, +4,EQUIPMENT,Crane,,25,0.125,Cubic Meters ,Length,,1.07625,Hr / Meter, +,,,,,,,,,,, +3,LABOR,"Beams, 745 kg/m ",7.5 m span,,,Cubic Meters ,,22.02,6.94,Hr / Meter, +4,LABOR,Foreman,,25,1,Cubic Meters ,Length,22.02,,Hr / Meter, +4,LABOR, Mason,,25,4,Cubic Meters ,Length,88.08,,Hr / Meter, +4,LABOR,Carpenter &Steelman,,25,10,Cubic Meters ,Length,220.2,,Hr / Meter, +4,LABOR,Laborer,,25,0.25,Cubic Meters ,Length,5.505,,Hr / Meter, +4,EQUIPMENT,Crane,,25,0.125,Cubic Meters ,Length,,0.8675,Hr / Meter, +,,,,,,,,,,, +2,LABOR,SLABS,,,,,,,,, +3,LABOR,In-situ,200 mm thick (concreting & finish only),,,Square Meters ,,0.22,0.2,Hr / Square Meters, +4,LABOR,Foreman,,25,0.5,Square Meters ,GrossArea,0.11,,Hr / Square Meters, +4,LABOR,Laborer,,25,3,Square Meters ,GrossArea,0.66,,Hr / Square Meters, +4,LABOR,Carpenter,,25,4,Square Meters ,GrossArea,0.88,,Hr / Square Meters, +4,LABOR,Steelfixers,,25,2.5,Square Meters ,GrossArea,0.55,,Hr / Square Meters, +4,EQUIPMENT,Crane,,25,0.4,Square Meters ,GrossArea,,0.08,Hr / Square Meters, +,,,,,,,,,,, +2,LABOR,FOUNDATIONS,,,,,,,,, +3,LABOR,Drainage,,25,,Meters,Length,3.5,,Hr / Meter, +,,,,,,,,,,, +,,,,,,,,,,, +2,LABOR,WATERPROOFING,,,,,,,,, +3,LABOR,Drainage,,25,,Square Meters ,GrossArea,0.5,,Hr / Square Meters, +,,,,,,,,,,, +,,,,,,,,,,, +2,LABOR,STAIRS,,,,,,,,, +3,LABOR,STAIRS,"300 mm wide (Incld. forms, rebar, & finish)",,,Cubic Meters ,,102.16,36.89,Hr / Cubic Meters, +4,LABOR,Foreman,,25,0.5,Cubic Meters ,GrossVolume,51.08,,Hr / Cubic Meters, +4,LABOR,Carpenter,,25,6,Cubic Meters ,GrossVolume,612.96,,Hr / Cubic Meters, +4,LABOR,Steelman,,25,2,Cubic Meters ,GrossVolume,204.32,,Hr / Cubic Meters, +4,LABOR,Mason,,25,2,Cubic Meters ,GrossVolume,204.32,,Hr / Cubic Meters, +4,LABOR,Laborer,,25,2.5,Cubic Meters ,GrossVolume,255.4,,Hr / Cubic Meters, +4,EQUIPMENT,Crane,,25,0.375,Cubic Meters ,GrossVolume,,13.83375,Hr / Cubic Meters, +3,LABOR,STAIRS LANDING,"Incld. forms, rebar, & finish",,,Cubic Meters ,,12.76,4.02,Hr / Cubic Meters, +4,LABOR,Foreman,,25,1,Cubic Meters ,GrossVolume,12.76,,Hr / Cubic Meters, +4,LABOR,Carpenter & SteelFixers,,25,10,Cubic Meters ,GrossVolume,127.6,,Hr / Cubic Meters, +4,LABOR,Laborer,,25,4,Cubic Meters ,GrossVolume,51.04,,Hr / Cubic Meters, +4,LABOR,Mason,,25,0.125,Cubic Meters ,GrossVolume,1.595,,Hr / Cubic Meters, +4,EQUIPMENT,Crane,,25,0.125,Cubic Meters ,GrossVolume,,0.5025,Hr / Cubic Meters, +,,,,,,,,,,, +1,CREW,MASONRY,,,,,,,,, +2,LABOR,CONCRETE BLOCKS,,,,,,,,, +3,LABOR,Hollow Blocks 100mm,100mm thick,,,Square Meters ,,1.17,0.29,Hr / Cubic Meters, +4,LABOR,Foreman,,25,0.25,Square Meters ,GrossSideArea,0.2925,,Hr / Cubic Meters, +4,LABOR,Mason,,25,4,Square Meters ,GrossSideArea,4.68,,Hr / Cubic Meters, +4,LABOR,Laborer,,25,2,Square Meters ,GrossSideArea,2.34,,Hr / Cubic Meters, +4,EQUIPMENT,Crane,,25,0.125,Square Meters ,GrossSideArea,,0.03625,Hr / Cubic Meters, +4,EQUIPMENT,Fork Lift,,25,0.125,Square Meters ,GrossSideArea,,0.03625,Hr / Cubic Meters, +4,EQUIPMENT,Truck,,25,0.125,Square Meters ,GrossSideArea,,0.03625,Hr / Cubic Meters, +3,LABOR,Hollow Blocks 200mm,100mm thick,,,Square Meters ,,1.32,0.33,Hr / Cubic Meters, +4,LABOR,Foreman,,25,0.25,Square Meters ,GrossSideArea,0.33,,Hr / Cubic Meters, +4,LABOR,Mason,,25,4,Square Meters ,GrossSideArea,5.28,,Hr / Cubic Meters, +4,LABOR,Laborer,,25,2,Square Meters ,GrossSideArea,2.64,,Hr / Cubic Meters, +4,EQUIPMENT,Crane,,25,0.125,Square Meters ,GrossSideArea,,0.5025,Hr / Cubic Meters, +4,EQUIPMENT,Fork Lift,,25,0.125,Square Meters ,GrossSideArea,,0.5025,Hr / Cubic Meters, diff --git a/src/ifc4d/ifc4d/resource_spreadsheet.ods b/src/ifc4d/ifc4d/resource_spreadsheet.ods new file mode 100644 index 0000000000..d2deaf274f Binary files /dev/null and b/src/ifc4d/ifc4d/resource_spreadsheet.ods differ