Skip to content

Extract a Storey from the Database

Feature Group: Extract | PosgreSQL

Data and Spatial visualization

Extractions are twofold: the invisible part is the set of data that pertain to the spatial unit at hand. On these data, processes can be run to provide metrics / indicators (surfaces and volumes, space types and usage, energy transfer, life cycle, reuse, ...).

The visible part is there to help understand the structure of the spatial unit, but also to identify issues, such as components that exibit misclassification and other anomalies.

Extraction of a Storey from the Database

Here, we work with the database and extract all the elements that are somehow part of a Spatial Unit, referred to in the code as a container. For the container, we start with a building storey.

Initially, we work with Duplex_A_20110907_optimized.ifc, which has been filtered (no furnitures) and has several storeys.

The target is an IFC(STEP file) that we can visualize with a standard IFC Viewer.

Submit the processing request

The extract is started by sending a POST with a Json Body as defined in pydantic with:

  • the bundleId (bundle_id in PostgreSQL) of the bundle that contains the data of the IfcJSON from the conversion of the IFC file
  • the GlobalId of the Storey in the elementId
  • IfcBuildingStorey as elementType
  • withIFC as True or False; if True, an IFC will also be produced
#
# Extract a spatial unit from the database
#
class ExtractSpatialUnit_Instruction(BaseModel):
    bundleId: str | None = "1"
    useRepresentationsCache: bool | None = False
    elementType: Literal['IfcBuildingStorey', 'IfcZone', 'IfcSpatialZone', 'IfcSpace', 'IfcGroup']
    elementId: str | None = 'e58c68d0-1297-4210-9416-2412e1e6acc1'
    withIFC: bool | None = False

    @computed_field()
    def includeRelationshipTypes(self) -> str:
        if self.elementType == 'IfcBuildingStorey':
            return ['IfcRelAggregates','IfcRelContainedInSpatialStructure','IfcRelFillsElement','IfcRelVoidsElement']
        elif self.elementType == 'IfcSpatialZone' or self.elementType == 'IfcSpace':
            return ['IfcRelAggregates','IfcRelContainedInSpatialStructure','IfcRelFillsElement','IfcRelVoidsElement','IfcRelSpaceBoundary','IfcRelReferencedInSpatialStructure']
        elif self.elementType == 'IfcZone' or self.elementType == 'IfcGroup':
            return ['IfcRelAggregates','IfcRelContainedInSpatialStructure','IfcRelFillsElement','IfcRelVoidsElement','IfcRelSpaceBoundary','IfcRelReferencedInSpatialStructure']
        else:
            return ['IfcRelAggregates','IfcRelContainedInSpatialStructure','IfcRelFillsElement','IfcRelVoidsElement']   

class ExtractSpatialUnit_Result(BaseModel):
    resultPath: str # relative path of the result file (json)
    runtime: float | None = 0.0 # in seconds
# When withIFC = True, the conversion to IFC is also included and its result also     
class ConvertIfcJsonToIfc_Result(BaseModel):
    resultPath: str # relative path of the result file (ifc)
    runtime: float | None = 0.0 # in seconds

What needs to be included into includeRelationshipTypes may be tuned to the source model data and the elementType, - here an IfcBuildingStorey

Processing

We will use standard features of a database

  • temporary table creation populated by the result of a query
  • recursive query to find all 'descendants' of the Storey.

The processing is outlined hereunder:

  1. Get the header of the bundle (all ifc's have a header); but we could also create a new one from scratch
  2. Get the container, i.e. 'Spatial Unit', e.g. the storey
  3. Get the parents of the container with respect to the IfcRelAggregates hierarchy (if the container is e.g., a storey, the parent is usually the building, then the site, then the project). We could possibly attach the selected Storey to the projet, but it's safer to have the hierarchy if relative positioning of elements is the default in the model
  4. Get all 'children elements' of the container, and their own 'children', etc. where the 'children' are the elements that are in a graph where 'parents' are the relating elements and the 'children' are the related elements in a relationship and 'descent' from the container.
    • we need to get the objects
    • we need to get the object types
    • we need to get the representations
    • we need to get the 'down' relationships for the objects, i.e. the relationships where the object is the 'relating' element
    • we need to get the 'up' relationships for the objects, i.e. the relationships where the object is the 'related' element
    • we need to get the propertySets for the objects
  5. Now that we have 'all' elements, we need to look at the elements that are referenced in one the element that we have but are NOT in the elements that we have. These referenced elements can be objects, representations or propertysets (referenced by an object type). We need to get all these elements and add them to the list of elements. This is a recursive process as a referenced element can also reference other elements that are not in the list of elements
  6. We can process the IfcStyledItems if any. They can reference presentation elements deep in the representation structure of be referenced by materials.
  7. We need to prune the related list of relationships to ensure we do not include related elements that are not in the spatial unit. This applies to IfcRelDefinesByProperties, IfcRelDefinesByType, IfcRelAssociatesMaterial.
  8. Now that we have all that is needed for a model, we build an ifcJSON
  9. And convert it to an IFC(Step file).

View with BIMcollab of extracted Level 1 of Duplex_A_20110907_optimized

BimCollab display of extracted Level 1 of Duplex_A_20110907_optimized.ifc

We have the elements that we had in IfcPatch (above), but now we also have the stairs.

Additionally, with the misconfigured walls in the source IFC we also gained the doors of those walls under 'Unreferenced items' .

View with OpenIFCViewer of extracted Level 1 of Duplex_A_20110907_optimized

OpenIFCViewer display of extracted Level 1 of Duplex_A_20110907_optimized.ifc

Compared with BIMcollab, we don't see 'Unregistered items', hence, the erroneously registered walls don't get their doors.

View with That Open of extracted Level 1 of Duplex_A_20110907_optimized

That Open display of extracted Level 1 of Duplex_A_20110907_optimized.ifc