Bug #663 - Implement support for COBie jobs spreadsheet

This commit is contained in:
Dion Moult
2019-10-08 17:33:14 +11:00
parent 959609db99
commit 38972d7ee4
+66 -20
View File
@@ -19,6 +19,7 @@ class IfcCobieCsv():
self.connections = {}
self.spares = {}
self.resources = {}
self.jobs = {}
self.type_assets = [
'IfcDoorStyle',
'IfcBuildingElementProxyType',
@@ -152,10 +153,10 @@ class IfcCobieCsv():
'ExternalSiteIdentifier': self.get_site_globalid_from_building(building),
'ExternalFacilityObject': self.get_ext_object(building),
'ExternalFacilityIdentifier': building.GlobalId,
'Description': self.get_object_attribute(building, 'Description'),
'ProjectDescription': self.get_object_attribute(self.get_parent_spatial_element(building, 'IfcProject'), 'Description'),
'SiteDescription': self.get_object_attribute(self.get_parent_spatial_element(building, 'IfcSite'), 'Description'),
'Phase': self.get_object_attribute(self.get_parent_spatial_element(building, 'IfcProject'), 'Phase')
'Description': self.get_object_attribute(building, 'Description', default='n/a'),
'ProjectDescription': self.get_object_attribute(self.get_parent_spatial_element(building, 'IfcProject'), 'Description', default='n/a'),
'SiteDescription': self.get_object_attribute(self.get_parent_spatial_element(building, 'IfcSite'), 'Description', default='n/a'),
'Phase': self.get_object_attribute(self.get_parent_spatial_element(building, 'IfcProject'), 'Phase', default='n/a')
}
def get_floors(self):
@@ -169,8 +170,8 @@ class IfcCobieCsv():
'ExtSystem': self.get_ext_system_from_history(storey.OwnerHistory),
'ExtObject': self.get_ext_object(storey),
'ExtIdentifier': storey.GlobalId,
'Description': self.get_object_attribute(storey, 'Description'),
'Elevation': self.get_object_attribute(storey, 'Elevation'),
'Description': self.get_object_attribute(storey, 'Description', default='n/a'),
'Elevation': self.get_object_attribute(storey, 'Elevation', default='n/a'),
'Height': self.get_height_from_storey(storey)
}
@@ -182,8 +183,8 @@ class IfcCobieCsv():
'CreatedBy': self.get_email_from_history(space.OwnerHistory),
'CreatedOn': self.get_created_on_from_history(space.OwnerHistory),
'Category': self.get_category_from_object(space, 'Category-Space'),
'FloorName': self.get_object_attribute(self.get_parent_spatial_element(space, 'IfcBuildingStorey'), 'Name', True),
'Description': self.get_object_attribute(space, 'Description'),
'FloorName': self.get_object_attribute(self.get_parent_spatial_element(space, 'IfcBuildingStorey'), 'Name', is_primary_key=True, default='n/a'),
'Description': self.get_object_attribute(space, 'Description', default='n/a'),
'ExtSystem': self.get_ext_system_from_history(space.OwnerHistory),
'ExtObject': self.get_ext_object(space),
'ExtIdentifier': space.GlobalId,
@@ -205,7 +206,7 @@ class IfcCobieCsv():
'ExtSystem': self.get_ext_system_from_history(zone.OwnerHistory),
'ExtObject': self.get_ext_object(zone),
'ExtIdentifier': zone.GlobalId,
'Description': self.get_object_attribute(zone, 'Description'),
'Description': self.get_object_attribute(zone, 'Description', default='n/a'),
}
def get_types(self):
@@ -228,7 +229,7 @@ class IfcCobieCsv():
'Category': self.get_category_from_object(type, 'Category-Product'),
# The responsibility matrix states two possible fallbacks. I
# choose the 'n/a' option as opposed to repeating the name.
'Description': self.get_object_attribute(type, 'Description'),
'Description': self.get_object_attribute(type, 'Description', default='n/a'),
'AssetType': self.get_pset_value_from_object(type, 'COBie_Asset', 'AssetType', 'n/a', 'AssetType'),
'Manufacturer': self.get_contact_pset_value_from_object(type, 'Pset_ManufacturerTypeInformation', 'Manufacturer'),
'ModelNumber': self.get_pset_value_from_object(type, 'Pset_ManufacturerTypeInformation', 'ModelLabel', 'n/a'),
@@ -280,7 +281,7 @@ class IfcCobieCsv():
'CreatedOn': self.get_created_on_from_history(component.OwnerHistory),
'TypeName': self.get_type_name_from_object(component),
'Space': self.get_space_name_from_component(component),
'Description': self.get_object_attribute(component, 'Description'),
'Description': self.get_object_attribute(component, 'Description', default='n/a'),
'ExtSystem': self.get_ext_system_from_history(component.OwnerHistory),
'ExtObject': self.get_ext_object(component),
'ExtIdentifier': component.GlobalId,
@@ -304,7 +305,7 @@ class IfcCobieCsv():
'ExtSystem': self.get_ext_system_from_history(system.OwnerHistory),
'ExtObject': self.get_ext_object(system),
'ExtIdentifier': system.GlobalId,
'Description': self.get_object_attribute(system, 'Description'),
'Description': self.get_object_attribute(system, 'Description', default='n/a'),
}
def get_assemblies(self):
@@ -323,7 +324,7 @@ class IfcCobieCsv():
'ExtSystem': self.get_ext_system_from_history(assembly.OwnerHistory),
'ExtObject': self.get_ext_object(assembly),
'ExtIdentifier': assembly.GlobalId,
'Description': self.get_object_attribute(assembly, 'Description'),
'Description': self.get_object_attribute(assembly, 'Description', default='n/a'),
}
def get_connections(self):
@@ -334,7 +335,7 @@ class IfcCobieCsv():
'CreatedBy': self.get_email_from_history(connection.OwnerHistory),
'CreatedOn': self.get_created_on_from_history(connection.OwnerHistory),
# There is ambiguity for what the ConnectionType mapping should be
'ConnectionType': self.get_object_attribute(connection, 'Description'),
'ConnectionType': self.get_object_attribute(connection, 'Description', default='n/a'),
'SheetName': 'Connections',
'RowName1': self.get_row_name_from_connection(connection, 'RelatingElement'),
'RowName2': self.get_row_name_from_connection(connection, 'RelatedElement'),
@@ -344,7 +345,7 @@ class IfcCobieCsv():
'ExtSystem': self.get_ext_system_from_history(connection.OwnerHistory),
'ExtObject': self.get_ext_object(connection),
'ExtIdentifier': connection.GlobalId,
'Description': self.get_object_attribute(connection, 'Description'),
'Description': self.get_object_attribute(connection, 'Description', default='n/a'),
}
def get_spares(self):
@@ -360,7 +361,7 @@ class IfcCobieCsv():
'ExtSystem': self.get_ext_system_from_history(spare.OwnerHistory),
'ExtObject': self.get_ext_object(spare),
'ExtIdentifier': spare.GlobalId,
'Description': self.get_object_attribute(spare, 'Description'),
'Description': self.get_object_attribute(spare, 'Description', default='n/a'),
'SetNumber': self.get_contact_pset_value_from_object(spare, 'COBie_Spare', 'SetNumber'),
'PartNumber': self.get_contact_pset_value_from_object(spare, 'COBie_Spare', 'PartNumber'),
}
@@ -372,13 +373,55 @@ class IfcCobieCsv():
self.resources[resource_name] = {
'CreatedBy': self.get_email_from_history(resource.OwnerHistory),
'CreatedOn': self.get_created_on_from_history(resource.OwnerHistory),
'Category': self.get_category_from_object(resource, 'ResourceType'),
'Category': self.get_object_attribute(resource, 'ObjectType', picklist='ResourceType', default='n/a'),
'ExtSystem': self.get_ext_system_from_history(resource.OwnerHistory),
'ExtObject': self.get_ext_object(resource),
'ExtIdentifier': resource.GlobalId,
'Description': self.get_object_attribute(resource, 'Description'),
'Description': self.get_object_attribute(resource, 'Description', default='n/a'),
}
def get_jobs(self):
jobs = self.file.by_type('IfcTask')
for job in jobs:
job_name = self.get_object_name(job)
task_time = job.TaskTime
self.jobs[job_name] = {
'CreatedBy': self.get_email_from_history(job.OwnerHistory),
'CreatedOn': self.get_created_on_from_history(job.OwnerHistory),
'Category': self.get_object_attribute(job, 'ObjectType', picklist='JobType', default='n/a'),
'Status': self.get_object_attribute(job, 'Status', picklist='JobStatusType', default='n/a'),
'TypeName': self.get_type_name_from_object(job),
'Description': self.get_object_attribute(job, 'Description', default='n/a'),
'Duration': self.get_object_attribute(task_time, 'ScheduleDuration', default=0),
'DurationUnit': 'day',
'Start': self.get_object_attribute(task_time, 'ScheduleStart', default=0),
'TaskStartUnit': 'day',
'Frequency': self.get_object_attribute(task_time.Recurrence, 'Occurrences', default=0) if hasattr(task_time, 'Recurrence') else 0,
'FrequencyUnit': 'day',
'ExtSystem': self.get_ext_system_from_history(job.OwnerHistory),
'ExtObject': self.get_ext_object(job),
'ExtIdentifier': job.GlobalId,
'TaskNumber': self.get_object_attribute(job, 'Identification'),
'Priors': self.get_priors_from_job(job),
'ResourceNames': self.get_resource_names_from_job(job),
}
def get_resource_names_from_job(self, job):
names = []
if job.OperatesOn \
and job.OperatesOn.RelatedObjects:
for object in job.OperatesOn.RelatedObjects:
names.append(object.Name)
return ','.join(names)
def get_priors_from_job(self, job):
# The responsibility matrix is vague as to whether it expects a task
# name or a task identification. I chose task name.
if job.IsSuccessorFrom \
and job.IsSuccessorFrom.RelatingProcess \
and job.IsSuccessorFrom.RelatingProcess.is_a('IfcTask'):
return self.get_object_name(job.IsSuccessorFrom.RelatingProcess)
def get_row_name_from_connection(self, connection, key):
if not connection.is_a('IfcRelConnectsElements'):
return None
@@ -526,15 +569,17 @@ class IfcCobieCsv():
logging.warning('A created on date was not found for {}'.format(history))
return self.default_date
def get_object_attribute(self, object, attribute, is_primary_key = False):
def get_object_attribute(self, object, attribute, is_primary_key = False, picklist = None, default=None):
result = getattr(object, attribute)
if result:
if picklist:
self.picklists[picklist].append(result)
return result
if is_primary_key:
logging.error('The primary key attribute {} was not found for {}'.format(attribute, object))
else:
logging.warning('The attribute {} was not found for {}'.format(attribute, object))
return 'n/a'
return default
def get_ext_project_object(self):
self.picklists['objType'].append('IfcProject')
@@ -758,4 +803,5 @@ pprint.pprint(ifc_cobie_csv.assemblies)
pprint.pprint(ifc_cobie_csv.connections)
pprint.pprint(ifc_cobie_csv.spares)
pprint.pprint(ifc_cobie_csv.resources)
pprint.pprint(ifc_cobie_csv.jobs)
print('# Finished conversion in {}s'.format(time.time() - start))