Skip to content

Python API

Use ifc-graph as a Python library for programmatic control over IFC processing and Neo4j storage.

Installation

pip install ifc-graph

Quick Start

from ifc_graph import filter_physical_elements, save_to_neo4j

# Extract elements from IFC file
elements, ifc_file = filter_physical_elements(
    "path/to/model.ifc",
    element_types=['IfcWall', 'IfcDoor', 'IfcWindow']
)

print(f"Found {sum(len(e) for e in elements.values())} elements")

# Store in Neo4j
stats = save_to_neo4j(
    elements,
    ifc_file,
    uri="bolt://localhost:7687",
    username="neo4j",
    password="your_password"
)

print(f"Created {stats['elements']} elements")
print(f"Created {stats['structures']} structures")
print(f"Linked {stats['materials']} materials")

Core Functions

filter_physical_elements

Extracts building elements from an IFC file.

from ifc_graph import filter_physical_elements

elements, ifc_file = filter_physical_elements(
    ifc_file_path="model.ifc",
    element_types=['IfcWall', 'IfcDoor', 'IfcWindow', 'IfcColumn'],
    config={
        'include_property_sets': True,
        'include_materials': True,
        'max_properties_per_element': 50,
    }
)

Parameters:

Parameter Type Description
ifc_file_path str Path to the IFC file
element_types list[str] IFC element types to extract (optional)
config dict Extraction configuration (optional)

Returns:

  • elements: Dictionary mapping element types to lists of IFC elements
  • ifc_file: The loaded ifcopenshell file object

Example - Extract Only Structural Elements:

elements, ifc_file = filter_physical_elements(
    "building.ifc",
    element_types=['IfcColumn', 'IfcBeam', 'IfcSlab', 'IfcFooting']
)

for element_type, elems in elements.items():
    print(f"{element_type}: {len(elems)} elements")

save_to_neo4j

Saves extracted elements to a Neo4j database.

from ifc_graph import save_to_neo4j

stats = save_to_neo4j(
    filtered_elements=elements,
    ifc_file=ifc_file,
    uri="bolt://localhost:7687",
    username="neo4j",
    password="password",
    clear_db=False,
    config={
        'include_materials': True,
        'include_property_sets': True,
    }
)

Parameters:

Parameter Type Description
filtered_elements dict Elements from filter_physical_elements()
ifc_file ifcopenshell.file Loaded IFC file object
uri str Neo4j connection URI
username str Neo4j username
password str Neo4j password
clear_db bool Clear database before import (default: False)
config dict Extraction configuration (optional)

Returns:

Dictionary with import statistics:

{
    'elements': 150,      # Number of element nodes created
    'structures': 12,     # Number of structure nodes created
    'materials': 45,      # Number of material relationships
    'property_sets': 0,   # Reserved for future use
}

Classes

IFCElementFilter

Object-oriented interface for element extraction.

from ifc_graph import IFCElementFilter

# Initialize filter
filter = IFCElementFilter(
    file_path="model.ifc",
    config={
        'include_property_sets': True,
        'include_materials': True,
    }
)

# Load IFC file
ifc_file = filter.load()

# Extract elements
elements, ifc_file = filter.extract_elements(
    element_types=['IfcWall', 'IfcDoor']
)

Neo4jConnection

Manages database connections with retry logic and proper cleanup.

from ifc_graph import Neo4jConnection

# Using context manager (recommended)
with Neo4jConnection(
    uri="bolt://localhost:7687",
    username="neo4j",
    password="password",
    max_retries=3,
    retry_delay=1.0
) as conn:
    with conn.session() as session:
        result = session.run("MATCH (n:Element) RETURN count(n)")
        print(result.single()[0])

# Manual connection management
conn = Neo4jConnection(uri, username, password)
try:
    conn.connect()
    with conn.session() as session:
        # Use session
        pass
finally:
    conn.close()

QueryLoader

Load Cypher queries from external files.

from ifc_graph import QueryLoader

# Create loader
loader = QueryLoader(use_cache=True)

# List available queries
queries = loader.list_queries()
print(queries)  # ['clear_database', 'create_elements_batch', ...]

# Load a query
query = loader.load("create_elements_batch")
print(query)

Helper Functions

load_ifc_file

Load an IFC file with validation.

from ifc_graph import load_ifc_file

ifc_file = load_ifc_file("model.ifc")
print(f"Loaded {len(ifc_file.by_type('IfcWall'))} walls")

extract_element_properties

Extract properties from a single IFC element.

from ifc_graph import extract_element_properties

element = ifc_file.by_type('IfcWall')[0]
props = extract_element_properties(element, config={})

print(props)
# {
#     'id': '123',
#     'name': 'Basic Wall:Generic - 200mm:456',
#     'guid': '2O2Fr$t4X7Zf8NOew3FLyT',
#     'type': 'IfcWall',
#     'object_type': 'Basic Wall:Generic - 200mm',
#     'description': '',
#     'tag': '456'
# }

extract_spatial_info

Get spatial containment information for an element.

from ifc_graph import extract_spatial_info

element = ifc_file.by_type('IfcWall')[0]
spatial = extract_spatial_info(element)

for info in spatial:
    print(f"Contained in: {info['name']} ({info['type']})")

extract_material_info

Get material information for an element.

from ifc_graph import extract_material_info

element = ifc_file.by_type('IfcWall')[0]
materials = extract_material_info(element)

for mat in materials:
    print(f"Material: {mat['material_name']} ({mat['material_category']})")

extract_property_sets

Get property sets for an element.

from ifc_graph import extract_property_sets

element = ifc_file.by_type('IfcWall')[0]
psets = extract_property_sets(element, max_properties=50)

for pset in psets:
    print(f"Property Set: {pset['pset_name']}")
    for name, value in pset['properties'].items():
        print(f"  {name}: {value}")

Exception Handling

The library provides specific exceptions for error handling:

from ifc_graph import (
    IFCLoadError,
    IFCValidationError,
    DatabaseConnectionError,
    DatabaseOperationError,
)

try:
    elements, ifc_file = filter_physical_elements("model.ifc")
    stats = save_to_neo4j(elements, ifc_file, uri, user, password)

except IFCValidationError as e:
    print(f"Invalid IFC file: {e}")
    # File doesn't exist, wrong extension, empty file

except IFCLoadError as e:
    print(f"Failed to load IFC file: {e}")
    # ifcopenshell couldn't parse the file

except DatabaseConnectionError as e:
    print(f"Cannot connect to Neo4j: {e}")
    # Wrong URI, credentials, or Neo4j not running

except DatabaseOperationError as e:
    print(f"Database operation failed: {e}")
    # Query error, constraint violation, etc.

Complete Example

#!/usr/bin/env python3
"""Complete example of processing an IFC file to Neo4j."""

from ifc_graph import (
    filter_physical_elements,
    save_to_neo4j,
    IFCLoadError,
    IFCValidationError,
    DatabaseConnectionError,
    DatabaseOperationError,
)

# Configuration
IFC_FILE = "building.ifc"
NEO4J_URI = "bolt://localhost:7687"
NEO4J_USER = "neo4j"
NEO4J_PASSWORD = "your_password"

# Element types to extract
ELEMENT_TYPES = [
    'IfcWall',
    'IfcWallStandardCase',
    'IfcDoor',
    'IfcWindow',
    'IfcColumn',
    'IfcBeam',
    'IfcSlab',
    'IfcStair',
    'IfcRoof',
]

def main():
    try:
        # Extract elements
        print(f"Loading IFC file: {IFC_FILE}")
        elements, ifc_file = filter_physical_elements(
            IFC_FILE,
            element_types=ELEMENT_TYPES,
            config={
                'include_property_sets': True,
                'include_materials': True,
                'max_properties_per_element': 50,
            }
        )

        total = sum(len(e) for e in elements.values())
        print(f"Found {total} elements")

        # Show breakdown by type
        for elem_type, elems in elements.items():
            print(f"  {elem_type}: {len(elems)}")

        # Save to Neo4j
        print(f"\nSaving to Neo4j at {NEO4J_URI}")
        stats = save_to_neo4j(
            elements,
            ifc_file,
            uri=NEO4J_URI,
            username=NEO4J_USER,
            password=NEO4J_PASSWORD,
            clear_db=True,  # Start fresh
        )

        print("\nImport complete!")
        print(f"  Elements: {stats['elements']}")
        print(f"  Structures: {stats['structures']}")
        print(f"  Materials: {stats['materials']}")

    except IFCValidationError as e:
        print(f"Error: Invalid IFC file - {e}")
        return 1

    except IFCLoadError as e:
        print(f"Error: Failed to load IFC file - {e}")
        return 1

    except DatabaseConnectionError as e:
        print(f"Error: Cannot connect to Neo4j - {e}")
        return 1

    except DatabaseOperationError as e:
        print(f"Error: Database operation failed - {e}")
        return 1

    return 0

if __name__ == "__main__":
    exit(main())

See Also