{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"authorship_tag": "ABX9TyN7KrJ5aFUDzz8ZbDcCHGEo",
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"source": [
"# Intro\n",
"\n",
"This notebook demonstrates an example of how to use [the Primavera P6 xer files reader](https://pypi.org/project/xerparser/0.10.3/) library for data preparation.\n",
"\n",
"\n",
"The XER file contains the same data presented in the [notebook](https://nbviewer.org/github/inigmat/exupery/blob/main/Schedule_CPLEX.ipynb) which is shown in the [\"Optimizing Project Planning and Material transportation\"](https://inigmat.github.io/home/2023/11/29/Transport-and-Resources.html) post.\n",
"\n",
"By obtaining the file via URL link, the required data—task names, durations, precedences, and release dates (intervals between each house's earliest starting date)—is transformed into Python objects.\n"
],
"metadata": {
"id": "BhG4x-GqoR_3"
}
},
{
"cell_type": "markdown",
"source": [
"# Installing xerparser\n"
],
"metadata": {
"id": "EYEH5p-0oF4Z"
}
},
{
"cell_type": "code",
"source": [
"import importlib\n",
"\n",
"# Check if xerparser is already installed\n",
"try:\n",
" importlib.import_module('xerparser')\n",
" print(\"xerparser is already installed.\")\n",
"except ImportError:\n",
" try:\n",
" # Attempt installation\n",
" %pip install xerparser\n",
" except Exception as e:\n",
" print(\"An error occurred while installing xerparser:\", e)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "gbiCgG_RUiY0",
"outputId": "bb1d4cc0-73ad-410f-ee4c-0fe89d11d7a2"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"xerparser is already installed.\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"# Getting the XER file"
],
"metadata": {
"id": "sya1fu_QqTgW"
}
},
{
"cell_type": "code",
"source": [
"import requests\n",
"\n",
"url = \"https://raw.githubusercontent.com/inigmat/exupery/main/files/schedule/MDL4D.xer\"\n",
"\n",
"try:\n",
" response = requests.get(url)\n",
" if response.status_code == 200:\n",
" print(\"Request successful!\")\n",
" else:\n",
" print(f\"Failed to retrieve data. Status code: {response.status_code}\")\n",
"except requests.exceptions.RequestException as e:\n",
" print(f\"An error occurred: {e}\")"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "sjlr83pETrsi",
"outputId": "9559e561-2f45-496c-9ab3-a0276502c925"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Request successful!\n"
]
}
]
},
{
"cell_type": "markdown",
"source": [
"# Read the downloaded file with checking for errors"
],
"metadata": {
"id": "9nLeMn863_fl"
}
},
{
"cell_type": "code",
"source": [
"from xerparser import Xer, CorruptXerFile\n",
"\n",
"try:\n",
" xer = Xer(response.text)\n",
"except CorruptXerFile as e:\n",
" for error in e.errors:\n",
" print(error)"
],
"metadata": {
"id": "-G_0Dr4lJhul"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"# Getting the project data"
],
"metadata": {
"id": "2qKhVOAF37Yl"
}
},
{
"cell_type": "code",
"source": [
"project = list(xer.projects.values())[0]"
],
"metadata": {
"id": "q1zW1dI7fxJT"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"We have to get the following data\n",
"\n",
"```\n",
"NbWorkers = 3\n",
"NbHouses = 5\n",
"\n",
"TaskNames = (\"masonry\",\"carpentry\",\"plumbing\",\n",
" \"ceiling\",\"roofing\",\"painting\",\n",
" \"windows\",\"facade\",\"garden\",\"moving\")\n",
"\n",
"Duration = [35, 15, 40, 15, 5, 10, 5, 10, 5, 5]\n",
"\n",
"ReleaseDate = [31, 0, 90, 120, 90]\n",
"\n",
"Precedences = [(\"masonry\", \"carpentry\"), (\"masonry\", \"plumbing\"), (\"masonry\", \"ceiling\"),\n",
" (\"carpentry\", \"roofing\"), (\"ceiling\", \"painting\"), (\"roofing\", \"windows\"),\n",
" (\"roofing\", \"facade\"), (\"plumbing\", \"facade\"), (\"roofing\", \"garden\"),\n",
" (\"plumbing\", \"garden\"), (\"windows\", \"moving\"), (\"facade\", \"moving\"),\n",
" (\"garden\", \"moving\"), (\"painting\", \"moving\")]\n",
"```\n",
"\n"
],
"metadata": {
"id": "WwED080mhUzT"
}
},
{
"cell_type": "markdown",
"source": [
"# Start with getting the WBS (house numbers)\n",
"\n",
"We skip the first two levels using WBS_LVL variable"
],
"metadata": {
"id": "9ECY5LtO4l-F"
}
},
{
"cell_type": "code",
"source": [
"WBS_LVL = 2\n",
"houses = [obj.name for obj in project.wbs_nodes[WBS_LVL:]]\n",
"NbHouses= len(houses)\n",
"houses"
],
"metadata": {
"id": "h_slxPqjRvWH",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "2db66196-9c1f-4646-e4e4-a9f8791ea424"
},
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"['House 1', 'House 2', 'House 3', 'House 4', 'House 5']"
]
},
"metadata": {},
"execution_count": 5
}
]
},
{
"cell_type": "markdown",
"source": [
"# Obtain the labor resources of the project to get the number of workers"
],
"metadata": {
"id": "mnuxHbRR5mqB"
}
},
{
"cell_type": "code",
"source": [
"workers = {}\n",
"for res in project.resources:\n",
" if res.rsrc_type == \"RT_Labor\":\n",
" workers[res.rsrc_id] = res.resource.name\n",
"NbWorkers = len(workers)"
],
"metadata": {
"id": "spxHZUTpareG"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"# Prepare pandas dataframe to check out the tasks data such as 'TASK ID','Name','Type', 'WBS ID', 'Duration', 'Successors (ID, Link, Lag)'"
],
"metadata": {
"id": "RFsILb_753_3"
}
},
{
"cell_type": "code",
"source": [
"import pandas as pd\n",
"\n",
"tasks_df = pd.DataFrame(columns=['TASK ID','Name','Type', 'WBS ID', 'Duration', 'Successors (ID, Link, Lag)'])\n",
"\n",
"for task in project.tasks:\n",
" task_sucs = []\n",
" for pred_link in task.successors:\n",
" task_suc = pred_link.task.uid\n",
" task_link = pred_link.link\n",
" task_lag = pred_link.lag\n",
" task_sucs.append((task_suc, task_link, task_lag))\n",
"\n",
" tasks_df = pd.concat([tasks_df, pd.DataFrame(\n",
" {'TASK ID': [task.uid],\n",
" 'Name': [task.name],\n",
" 'Type': [task.type],\n",
" 'WBS ID': [task.wbs_id],\n",
" 'Duration': [task.duration],\n",
" 'Successors (ID, Link, Lag)': [task_sucs],\n",
" })], ignore_index=True)"
],
"metadata": {
"id": "SdzXOiYMmBiK"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"tasks_df.head(15)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 514
},
"id": "dAkhLXxm5ph6",
"outputId": "36199cdb-a44e-4d67-d913-35478941617c"
},
"execution_count": null,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" TASK ID Name Type WBS ID Duration \\\n",
"0 104836 House 1 Start TaskType.TT_Mile 26152 0 \n",
"1 104837 Masonry TaskType.TT_Task 26154 35 \n",
"2 104838 Carpentry TaskType.TT_Task 26154 15 \n",
"3 104839 Plumbing TaskType.TT_Task 26154 40 \n",
"4 104840 Ceiling TaskType.TT_Task 26154 15 \n",
"5 104841 Roofing TaskType.TT_Task 26154 5 \n",
"6 104842 Painting TaskType.TT_Task 26154 10 \n",
"7 104843 Windows TaskType.TT_Task 26154 5 \n",
"8 104844 Facade TaskType.TT_Task 26154 10 \n",
"9 104845 Garden TaskType.TT_Task 26154 5 \n",
"10 104846 Moving TaskType.TT_Rsrc 26154 5 \n",
"11 104847 House 2 Start TaskType.TT_Mile 26152 0 \n",
"12 104848 Masonry TaskType.TT_Task 26155 35 \n",
"13 104849 Carpentry TaskType.TT_Task 26155 15 \n",
"14 104850 Plumbing TaskType.TT_Task 26155 40 \n",
"\n",
" Successors (ID, Link, Lag) \n",
"0 [] \n",
"1 [(104838, FS, 0), (104839, FS, 0), (104840, FS... \n",
"2 [(104841, FS, 0)] \n",
"3 [(104844, FS, 0), (104845, FS, 0)] \n",
"4 [(104842, FS, 0)] \n",
"5 [(104843, FS, 0), (104844, FS, 0), (104845, FS... \n",
"6 [(104846, FS, 0)] \n",
"7 [(104846, FS, 0)] \n",
"8 [(104846, FS, 0)] \n",
"9 [(104846, FS, 0)] \n",
"10 [(104883, FF, 0)] \n",
"11 [] \n",
"12 [(104849, FS, 0), (104850, FS, 0), (104851, FS... \n",
"13 [(104852, FS, 0)] \n",
"14 [(104855, FS, 0), (104856, FS, 0)] "
],
"text/html": [
"\n",
"
| \n", " | TASK ID | \n", "Name | \n", "Type | \n", "WBS ID | \n", "Duration | \n", "Successors (ID, Link, Lag) | \n", "
|---|---|---|---|---|---|---|
| 0 | \n", "104836 | \n", "House 1 Start | \n", "TaskType.TT_Mile | \n", "26152 | \n", "0 | \n", "[] | \n", "
| 1 | \n", "104837 | \n", "Masonry | \n", "TaskType.TT_Task | \n", "26154 | \n", "35 | \n", "[(104838, FS, 0), (104839, FS, 0), (104840, FS... | \n", "
| 2 | \n", "104838 | \n", "Carpentry | \n", "TaskType.TT_Task | \n", "26154 | \n", "15 | \n", "[(104841, FS, 0)] | \n", "
| 3 | \n", "104839 | \n", "Plumbing | \n", "TaskType.TT_Task | \n", "26154 | \n", "40 | \n", "[(104844, FS, 0), (104845, FS, 0)] | \n", "
| 4 | \n", "104840 | \n", "Ceiling | \n", "TaskType.TT_Task | \n", "26154 | \n", "15 | \n", "[(104842, FS, 0)] | \n", "
| 5 | \n", "104841 | \n", "Roofing | \n", "TaskType.TT_Task | \n", "26154 | \n", "5 | \n", "[(104843, FS, 0), (104844, FS, 0), (104845, FS... | \n", "
| 6 | \n", "104842 | \n", "Painting | \n", "TaskType.TT_Task | \n", "26154 | \n", "10 | \n", "[(104846, FS, 0)] | \n", "
| 7 | \n", "104843 | \n", "Windows | \n", "TaskType.TT_Task | \n", "26154 | \n", "5 | \n", "[(104846, FS, 0)] | \n", "
| 8 | \n", "104844 | \n", "Facade | \n", "TaskType.TT_Task | \n", "26154 | \n", "10 | \n", "[(104846, FS, 0)] | \n", "
| 9 | \n", "104845 | \n", "Garden | \n", "TaskType.TT_Task | \n", "26154 | \n", "5 | \n", "[(104846, FS, 0)] | \n", "
| 10 | \n", "104846 | \n", "Moving | \n", "TaskType.TT_Rsrc | \n", "26154 | \n", "5 | \n", "[(104883, FF, 0)] | \n", "
| 11 | \n", "104847 | \n", "House 2 Start | \n", "TaskType.TT_Mile | \n", "26152 | \n", "0 | \n", "[] | \n", "
| 12 | \n", "104848 | \n", "Masonry | \n", "TaskType.TT_Task | \n", "26155 | \n", "35 | \n", "[(104849, FS, 0), (104850, FS, 0), (104851, FS... | \n", "
| 13 | \n", "104849 | \n", "Carpentry | \n", "TaskType.TT_Task | \n", "26155 | \n", "15 | \n", "[(104852, FS, 0)] | \n", "
| 14 | \n", "104850 | \n", "Plumbing | \n", "TaskType.TT_Task | \n", "26155 | \n", "40 | \n", "[(104855, FS, 0), (104856, FS, 0)] | \n", "