See #2017. Fix bug in P6 importer where nonlabor types were not considered.

This commit is contained in:
Dion Moult
2022-02-04 09:10:40 +11:00
parent 6a8292d24c
commit 868ced2990
2 changed files with 54 additions and 63 deletions
+11 -11
View File
@@ -1,6 +1,5 @@
# Ifc4D - IFC scheduling utility # Ifc4D - IFC scheduling utility
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com> # Copyright (C) 2021, 2022 Dion Moult <dion@thinkmoult.com>
# #
# This file is part of Ifc4D. # This file is part of Ifc4D.
# #
@@ -25,6 +24,7 @@ import ifcopenshell.util.date
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from .common import ScheduleIfcGenerator from .common import ScheduleIfcGenerator
class P62Ifc: class P62Ifc:
def __init__(self): def __init__(self):
self.xml = None self.xml = None
@@ -53,10 +53,12 @@ class P62Ifc:
"Finish to Start": "FINISH_START", "Finish to Start": "FINISH_START",
"Finish to Finish": "FINISH_FINISH", "Finish to Finish": "FINISH_FINISH",
} }
self.RESOURCE_TYPES_MAPPING = { self.resource_type_map = {
'Labor': "LABOR", "Labor": "LABOR",
'Mat': "MATERIAL", "Mat": "MATERIAL",
'Equip': "EQUIPMENT" "Equip": "EQUIPMENT",
# https://www.primaverascheduling.com/category/primavera-resources/
"Nonlabor": "EQUIPMENT",
} }
def execute(self): def execute(self):
@@ -66,14 +68,14 @@ class P62Ifc:
print("Started") print("Started")
self.parse_xml() self.parse_xml()
settings = { settings = {
"work_plan":self.work_plan, "work_plan": self.work_plan,
"project": self.project, "project": self.project,
"calendars": self.calendars, "calendars": self.calendars,
"wbs": self.wbs, "wbs": self.wbs,
"root_activities": self.root_activites, "root_activities": self.root_activites,
"activities": self.activities, "activities": self.activities,
"relationships": self.relationships, "relationships": self.relationships,
"resources": self.resources "resources": self.resources,
} }
ifcCreator = ScheduleIfcGenerator(self.file, self.output, settings) ifcCreator = ScheduleIfcGenerator(self.file, self.output, settings)
end = time.time() end = time.time()
@@ -202,7 +204,6 @@ class P62Ifc:
def get_wbs(self, wbs): def get_wbs(self, wbs):
return {"Name": wbs.find("pr:Name", self.ns).text, "subtasks": []} return {"Name": wbs.find("pr:Name", self.ns).text, "subtasks": []}
def parse_resources_xml(self, project): def parse_resources_xml(self, project):
resources = project.findall("pr:Resource", self.ns) resources = project.findall("pr:Resource", self.ns)
for resource in resources: for resource in resources:
@@ -211,9 +212,8 @@ class P62Ifc:
"Name": resource.find("pr:Name", self.ns).text, "Name": resource.find("pr:Name", self.ns).text,
"Code": resource.find("pr:Id", self.ns).text, "Code": resource.find("pr:Id", self.ns).text,
"ParentObjectId": resource.find("pr:ParentObjectId", self.ns).text, "ParentObjectId": resource.find("pr:ParentObjectId", self.ns).text,
"Type": self.RESOURCE_TYPES_MAPPING[resource.find("pr:ResourceType", self.ns).text], "Type": self.resource_type_map[resource.find("pr:ResourceType", self.ns).text],
"ifc": None, "ifc": None,
"rel": None, "rel": None,
} }
print("Resource found", self.resources) print("Resource found", self.resources)
+29 -38
View File
@@ -1,5 +1,5 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on # BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 Dion Moult <dion@thinkmoult.com> # Copyright (C) 2020, 2021, 2022 Dion Moult <dion@thinkmoult.com>
# #
# This file is part of BlenderBIM Add-on. # This file is part of BlenderBIM Add-on.
# #
@@ -24,12 +24,8 @@ from datetime import datetime, timedelta, date
from .common import ScheduleIfcGenerator from .common import ScheduleIfcGenerator
class P6XER2Ifc(): class P6XER2Ifc:
status_map = { status_map = {"TK_NotStart": "Not Start", "TK_Complete": "Completed", "TK_Active": "Progress"}
"TK_NotStart": "Not Start",
"TK_Complete": "Completed",
"TK_Active": "Progress"
}
TASK_TYPE_MAP = { TASK_TYPE_MAP = {
"TT_Task": "Task", "TT_Task": "Task",
@@ -37,20 +33,22 @@ class P6XER2Ifc():
"TT_LOE": "Level of Effort", "TT_LOE": "Level of Effort",
"TT_Mile": "Start Milestone", "TT_Mile": "Start Milestone",
"TT_FinMile": "Finish Milestone", "TT_FinMile": "Finish Milestone",
"TT_WBS": "WBS Summary" "TT_WBS": "WBS Summary",
} }
RELATIONSHIP_TYPE_MAPPING = { RELATIONSHIP_TYPE_MAPPING = {
"PR_SS": "START_START", "PR_SS": "START_START",
"PR_FS": "FINISH_START", "PR_FS": "FINISH_START",
"PR_SF": "START_FINISH", "PR_SF": "START_FINISH",
"PR_FF": "FINISH_FINISH" "PR_FF": "FINISH_FINISH",
} }
RESOURCE_TYPES_MAPPING = { resource_type_map = {
'RT_Labor': "LABOR", "RT_Labor": "LABOR",
'RT_Mat': "MATERIAL", "RT_Mat": "MATERIAL",
'RT_Equip': "EQUIPMENT" # https://www.primaverascheduling.com/category/primavera-resources/
"RT_Nonlabor": "EQUIPMENT",
"RT_Equip": "EQUIPMENT",
} }
def __init__(self): def __init__(self):
@@ -68,32 +66,30 @@ class P6XER2Ifc():
self.output = None self.output = None
self.day_map2 = { self.day_map2 = {
'1': "Monday", "1": "Monday",
'2': "Tuesday", "2": "Tuesday",
'3': "Wednesday", "3": "Wednesday",
'4': "Thursday", "4": "Thursday",
'5': "Friday", "5": "Friday",
'6': "Saturday", "6": "Saturday",
'7': "Sunday", "7": "Sunday",
} }
def execute(self): def execute(self):
self.parse_xer() self.parse_xer()
settings = { settings = {
"work_plan":self.work_plan, "work_plan": self.work_plan,
"project": self.project, "project": self.project,
"calendars": self.calendars, "calendars": self.calendars,
"wbs": self.wbs, "wbs": self.wbs,
"root_activities": self.root_activites, "root_activities": self.root_activites,
"activities": self.activities, "activities": self.activities,
"relationships": self.relationships, "relationships": self.relationships,
"resources": self.resources "resources": self.resources,
} }
ifcCreator = ScheduleIfcGenerator(self.file, self.output, settings) ifcCreator = ScheduleIfcGenerator(self.file, self.output, settings)
ifcCreator.create_ifc() ifcCreator.create_ifc()
def parse_xer(self): def parse_xer(self):
self.model = Reader(self.xer) self.model = Reader(self.xer)
# for project in self.model.projects: # for project in self.model.projects:
@@ -104,9 +100,8 @@ class P6XER2Ifc():
self.parse_activity_xer() self.parse_activity_xer()
self.parse_relationship_xer() self.parse_relationship_xer()
self.parse_resource_xer() self.parse_resource_xer()
#work_schedule = self.create_work_schedule() # work_schedule = self.create_work_schedule()
#self.create_tasks(work_schedule) # self.create_tasks(work_schedule)
def parse_wbs_xer(self): def parse_wbs_xer(self):
for wbs in self.model.wbss: for wbs in self.model.wbss:
@@ -118,7 +113,7 @@ class P6XER2Ifc():
"rel": None, "rel": None,
"activities": [], "activities": [],
} }
#print(self.wbs) # print(self.wbs)
def parse_calendar_xer(self): def parse_calendar_xer(self):
standard_work_week = [] standard_work_week = []
@@ -127,10 +122,10 @@ class P6XER2Ifc():
standard_work_week = cal.working_hours standard_work_week = cal.working_hours
except_lst = cal.exceptions except_lst = cal.exceptions
for exception in except_lst: for exception in except_lst:
month = exceptions.setdefault(exception.year, {}).setdefault(exception.month, {}) month = exceptions.setdefault(exception.year, {}).setdefault(exception.month, {})
month.setdefault("FullDay", []) month.setdefault("FullDay", [])
month.setdefault("WorkTime", []) month.setdefault("WorkTime", [])
exceptions[exception.year][exception.month]["FullDay"].append(exception.day) exceptions[exception.year][exception.month]["FullDay"].append(exception.day)
self.calendars[cal.clndr_id] = { self.calendars[cal.clndr_id] = {
"Name": cal.clndr_name, "Name": cal.clndr_name,
@@ -158,7 +153,7 @@ class P6XER2Ifc():
"PlannedDuration": activity.target_drtn_hr_cnt, "PlannedDuration": activity.target_drtn_hr_cnt,
"Status": self.status_map[activity.status_code], "Status": self.status_map[activity.status_code],
"CalendarObjectId": activity.clndr_id, "CalendarObjectId": activity.clndr_id,
"ifc": None "ifc": None,
} }
def parse_relationship_xer(self): def parse_relationship_xer(self):
@@ -174,23 +169,19 @@ class P6XER2Ifc():
"Lag": rel.lag_hr_cnt, "Lag": rel.lag_hr_cnt,
} }
def parse_resource_xer(self): def parse_resource_xer(self):
for rsrc in self.model.resources: for rsrc in self.model.resources:
self.resources[rsrc.rsrc_id] = { self.resources[rsrc.rsrc_id] = {
"Name": rsrc.rsrc_name, "Name": rsrc.rsrc_name,
"Code": rsrc.rsrc_short_name, "Code": rsrc.rsrc_short_name,
"ParentObjectId": rsrc.parent_rsrc_id, "ParentObjectId": rsrc.parent_rsrc_id,
"Type": self.RESOURCE_TYPES_MAPPING[rsrc.rsrc_type], "Type": self.resource_type_map[rsrc.rsrc_type],
"ifc": None, "ifc": None,
"rel": None, "rel": None,
} }
# TODO: add support for resources # TODO: add support for resources
# TODO: consider showing progress bar for better user experience # TODO: consider showing progress bar for better user experience
# TODO: support multiple projects in a single file # TODO: support multiple projects in a single file
# TODO: prompt user to select activities and/or wbs nodes to import instead of the full project # TODO: prompt user to select activities and/or wbs nodes to import instead of the full project