Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions skills/ifcopenshell/impl/ifcos-impl-sequence/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ metadata:
- **NEVER** pass both `work_schedule` and `parent_task` to `add_task`. These are mutually exclusive.
- **NEVER** create cyclical sequence relationships. `cascade_schedule` will recurse infinitely.
- **ALWAYS** call `cascade_schedule` after modifying task durations or sequences. Dates do NOT propagate automatically.
- **ALWAYS** pass `products` as a **list** in v0.8+ relationship functions (e.g., `assign_process`).
- **ALWAYS** pass `products` as a **list** in v0.8+ assignment functions that take one (`spatial.assign_container`, `group.assign_group`, `aggregate.assign_object`). `sequence.assign_process` and `sequence.assign_product` take a single `related_object`, **not** a list.
- **NEVER** forget to create a project bootstrap (IfcProject, units, contexts) before creating schedules.

### Version Differences: IFC2X3 vs IFC4+
Expand Down Expand Up @@ -235,13 +235,18 @@ wall = ifcopenshell.api.run("root.create_entity", model,
slab = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcSlab", name="Ground Floor Slab")

# Link products as outputs of tasks (IfcRelAssignsToProcess)
ifcopenshell.api.run("sequence.assign_process", model,
relating_process=pour,
related_object=slab)
ifcopenshell.api.run("sequence.assign_process", model,
relating_process=formwork,
related_object=wall)
# Link products as OUTPUTS of tasks (IfcRelAssignsToProduct)
# The task constructs the product, so the product is the task's output.
ifcopenshell.api.run("sequence.assign_product", model,
relating_product=slab,
related_object=pour)
ifcopenshell.api.run("sequence.assign_product", model,
relating_product=wall,
related_object=formwork)

# Products a task CONSUMES (demolition, rework) are inputs instead:
# ifcopenshell.api.run("sequence.assign_process", model,
# relating_process=demolition_task, related_object=old_wall)

# Query: which products does a task build?
# Use ifcopenshell.util.sequence.get_task_outputs(task)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,27 +310,51 @@ Every valid IFC file requires an `IfcProject` with assigned units. `IfcWorkSched

```python
# Intent: Wall is BUILT BY the construction task
# BAD: Using assign_product with wrong direction
ifcopenshell.api.run("sequence.assign_product", model,
relating_product=wall,
related_object=task)
# This says: "wall controls task" — semantically wrong for 4D BIM
# BAD: assign_process creates an INPUT relationship — the task operates on the wall
ifcopenshell.api.run("sequence.assign_process", model,
relating_process=task,
related_object=wall)
# Creates IfcRelAssignsToProcess. get_task_outputs(task) now returns nothing,
# and the wall is treated as an input rather than a constructed output.
```

### CORRECT

```python
# For 4D BIM: "task constructs/modifies product"
# Use assign_process to link products as inputs/outputs of tasks
# For a task that CONSTRUCTS or INSTALLS a product, the product is an OUTPUT
ifcopenshell.api.run("sequence.assign_product", model,
relating_product=wall,
related_object=task)
# Creates IfcRelAssignsToProduct — what get_task_outputs() reads

# assign_process is for INPUTS: products the task operates on or consumes
demolition = ifcopenshell.api.run("sequence.add_task", model,
work_schedule=schedule, name="Demolish", predefined_type="DEMOLITION")
ifcopenshell.api.run("sequence.assign_process", model,
relating_process=task,
relating_process=demolition,
related_object=wall)
# Creates IfcRelAssignsToProcess — the standard 4D BIM pattern
```

### Why

For 4D BIM visualization, the standard relationship is `IfcRelAssignsToProcess` (task operates on product). `assign_product` creates `IfcRelAssignsToProduct` which has a different semantic meaning (product is the output/deliverable). Most 4D tools expect `IfcRelAssignsToProcess`.
IFC models processes with the ICOM paradigm — Inputs, Controls, Outputs,
Mechanisms. A product that a task **creates** is an Output
(`IfcRelAssignsToProduct`); a product it **operates on or consumes** is an Input
(`IfcRelAssignsToProcess`).

The schema names the inverse attributes accordingly: `IfcTask.OperatesOn` points
at `IfcRelAssignsToProcess`, and `IfcProduct.ReferencedBy` points at
`IfcRelAssignsToProduct`. `ifcopenshell.util.sequence` follows that split —
`get_task_outputs()` reads `IfcRelAssignsToProduct`, `get_task_inputs()` reads
`OperatesOn` — as do the Inputs/Outputs panels in Bonsai's sequencing UI.

**ALWAYS** use `assign_product` when a construction or installation task creates
that product as an output. **NEVER** use `assign_process` to represent that
output: the task will otherwise have zero outputs.

(Note: `assign_product` does not express control. Control is
`IfcRelAssignsToControl`, a separate relationship used for cost items and
similar.)

---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,21 +245,21 @@ ifcopenshell.api.run("sequence.assign_sequence", model,
relating_process=task_gf_walls, related_process=task_ff_slab)

# --- 4D BIM: Link tasks to products ---
# GF slab is built by task_gf_slab
ifcopenshell.api.run("sequence.assign_process", model,
relating_process=task_gf_slab,
related_object=gf_slab)
# GF slab is built by task_gf_slab -> it is that task's OUTPUT
ifcopenshell.api.run("sequence.assign_product", model,
relating_product=gf_slab,
related_object=task_gf_slab)

# All GF walls are built by task_gf_walls
for wall in gf_walls:
ifcopenshell.api.run("sequence.assign_process", model,
relating_process=task_gf_walls,
related_object=wall)
ifcopenshell.api.run("sequence.assign_product", model,
relating_product=wall,
related_object=task_gf_walls)

# 1F slab is built by task_ff_slab
ifcopenshell.api.run("sequence.assign_process", model,
relating_process=task_ff_slab,
related_object=ff_slab)
ifcopenshell.api.run("sequence.assign_product", model,
relating_product=ff_slab,
related_object=task_ff_slab)

# Cascade and save
ifcopenshell.api.run("sequence.cascade_schedule", model, task=task_gf_slab)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ ifcopenshell.api.run("sequence.assign_process", file,
) -> IfcRelAssignsToProcess
```

Links an object (product or resource) as an input to a task. Creates an `IfcRelAssignsToProcess` relationship. Use for 4D BIM task-to-product linking.
Links an object (product or resource) as an **input**, control or resource of a task. Creates an `IfcRelAssignsToProcess` relationship. Use for products the task *consumes* — demolition, rework — not for products it builds; for those see `assign_product`.

### unassign_process

Expand Down