translator
Modules
translator module
- class Exact(**kwargs)[source]
Bases:
RuleRule that requires exact matches between pattern and semantic model elements.
The Exact rule is the most restrictive rule type, requiring that the semantic model contains exactly the same relationship as specified in the signature pattern. This rule is used when you need precise control over the pattern matching process.
Priority: 10 (highest priority)
Behavior
Requires that the semantic model contains the exact relationship specified
No traversal or flexibility in matching
Used for critical relationships that must be present exactly as specified
Examples
Controller-property relationships (from PID controller system):
>>> # Define controller nodes using real ontology classes >>> controller_node = Node(cls=core.namespace.S4BLDG.SetpointController) >>> sensor_node = Node(cls=core.namespace.SAREF.Sensor) >>> property_node = Node(cls=core.namespace.SAREF.Property) >>> >>> # Define exact relationships for precise control logic >>> controller_observes = Exact( ... subject=controller_node, ... object=property_node, ... predicate=core.namespace.SAREF.observes ... ) >>> sensor_observes = Exact( ... subject=sensor_node, ... object=property_node, ... predicate=core.namespace.SAREF.observes ... )
Damper control relationships (from damper system):
>>> # Define damper control nodes >>> damper_node = Node(cls=core.namespace.S4BLDG.Damper) >>> controller_node = Node(cls=core.namespace.S4BLDG.Controller) >>> position_node = Node(cls=core.namespace.SAREF.OpeningPosition) >>> >>> # Controller must directly control the opening position >>> control_relationship = Exact( ... subject=controller_node, ... object=position_node, ... predicate=core.namespace.SAREF.controls ... ) >>> >>> # Position must be property of the damper >>> property_relationship = Exact( ... subject=position_node, ... object=damper_node, ... predicate=core.namespace.SAREF.isPropertyOf ... )
Building space topology (from building space system):
>>> # Define building space nodes >>> supply_damper = Node(cls=core.namespace.S4BLDG.Damper) >>> return_damper = Node(cls=core.namespace.S4BLDG.Damper) >>> building_space = Node(cls=core.namespace.S4BLDG.BuildingSpace) >>> space_heater = Node(cls=core.namespace.S4BLDG.SpaceHeater) >>> >>> # Exact fluid supply relationships >>> supply_relationship = Exact( ... subject=supply_damper, ... object=building_space, ... predicate=core.namespace.FSO.suppliesFluidTo ... ) >>> return_relationship = Exact( ... subject=return_damper, ... object=building_space, ... predicate=core.namespace.FSO.hasFluidReturnedBy ... ) >>> >>> # Space heater containment >>> containment_relationship = Exact( ... subject=space_heater, ... object=building_space, ... predicate=core.namespace.S4BLDG.isContainedIn ... )
BRICK ontology relationships (from BRICK damper system):
>>> # Define BRICK nodes >>> damper_node = Node(cls=core.namespace.BRICK.Damper) >>> position_setpoint = Node(cls=core.namespace.BRICK.Damper_Position_Setpoint) >>> position_sensor = Node(cls=core.namespace.BRICK.Damper_Position_Sensor) >>> flow_sensor = Node(cls=core.namespace.BRICK.Air_Flow_Sensor) >>> >>> # BRICK-specific exact relationships >>> setpoint_relationship = Exact( ... subject=position_setpoint, ... object=damper_node, ... predicate=core.namespace.BRICK.isPointOf ... ) >>> sensor_relationship = Exact( ... subject=position_sensor, ... object=damper_node, ... predicate=core.namespace.BRICK.isPointOf ... ) >>> flow_relationship = Exact( ... subject=flow_sensor, ... object=damper_node, ... predicate=core.namespace.BRICK.isPointOf ... )
Sensor-property relationships (from sensor system):
>>> # Define sensor nodes >>> sensor_node = Node(cls=core.namespace.SAREF.Sensor) >>> temperature_node = Node(cls=core.namespace.SAREF.Temperature) >>> space_node = Node(cls=core.namespace.S4BLDG.BuildingSpace) >>> >>> # Sensor must observe the temperature property >>> sensor_observes = Exact( ... subject=sensor_node, ... object=temperature_node, ... predicate=core.namespace.SAREF.observes ... ) >>> >>> # Temperature must be property of the space >>> temperature_property = Exact( ... subject=temperature_node, ... object=space_node, ... predicate=core.namespace.SAREF.isPropertyOf ... )
- PRIORITY = 10
- class MultiPath(stop_early=True, **kwargs)[source]
Bases:
RuleRule that allows traversal along multiple paths in the semantic model.
The MultiPath rule is the most flexible rule type, allowing the pattern matcher to explore multiple paths between the subject and object in the semantic model. This is useful when there are multiple valid ways to connect components or when the semantic model has complex relationship structures.
Priority: 1 (lower priority than Exact)
Behavior
Allows traversal through multiple paths in the semantic model
Finds all possible paths between subject and object
Most flexible rule type
Can stop early if stop_early=True (default)
Note: MultiPath rules can cause infinite recursion in some complex semantic models and are used sparingly in practice. Consider using SinglePath for most flexible matching needs.
Examples
Complex building space connections (theoretical usage):
>>> # Define building space nodes using real ontology classes >>> building_space1 = Node(cls=core.namespace.S4BLDG.BuildingSpace) >>> building_space2 = Node(cls=core.namespace.S4BLDG.BuildingSpace) >>> >>> # MultiPath for complex adjacent zone relationships >>> # Note: This is commented out in real systems due to recursion issues >>> # adjacent_connection = MultiPath( >>> # subject=building_space1, >>> # object=building_space2, >>> # predicate=core.namespace.S4SYST.connectedTo >>> # ) >>> >>> # This could theoretically match multiple connection types: >>> # space1 -> shared_hvac_system -> space2 >>> # space1 -> structural_connection -> space2 >>> # space1 -> thermal_bridge -> space2 >>> # space1 -> common_corridor -> space2
Equipment network traversal (theoretical usage):
>>> # Define HVAC equipment nodes >>> chiller_node = Node(cls=core.namespace.S4BLDG.Chiller) >>> cooling_tower = Node(cls=core.namespace.S4BLDG.CoolingTower) >>> heat_exchanger = Node(cls=core.namespace.S4BLDG.HeatExchanger) >>> >>> # MultiPath for complex chilled water systems with multiple paths >>> # cooling_network = MultiPath( >>> # subject=chiller_node, >>> # object=cooling_tower, >>> # predicate=core.namespace.FSO.suppliesFluidTo >>> # ) >>> >>> # Could match various cooling system configurations: >>> # chiller -> primary_loop -> heat_exchanger -> secondary_loop -> cooling_tower >>> # chiller -> bypass_valve -> direct_connection -> cooling_tower >>> # chiller -> buffer_tank -> distribution_system -> cooling_tower
BRICK equipment hierarchies (theoretical usage):
>>> # Define BRICK nodes for air handling systems >>> ahu_node = Node(cls=core.namespace.BRICK.AHU) >>> terminal_unit = Node(cls=core.namespace.BRICK.Terminal_Unit) >>> >>> # MultiPath for complex BRICK hierarchies >>> # Note: Use with caution due to potential performance issues >>> # brick_hierarchy = MultiPath( >>> # subject=ahu_node, >>> # object=terminal_unit, >>> # predicate=core.namespace.BRICK.feeds >>> # ) >>> >>> # Could traverse multiple BRICK relationship paths: >>> # AHU -> VAV_Box -> Terminal_Unit >>> # AHU -> Duct_System -> Zone_Equipment -> Terminal_Unit >>> # AHU -> Distribution_System -> End_Use_Equipment -> Terminal_Unit
Practical alternatives to MultiPath:
>>> # Instead of MultiPath, consider using multiple SinglePath rules >>> # or combining Optional_ rules for specific known alternatives >>> >>> # Define equipment nodes >>> supply_equipment = Node(cls=( ... core.namespace.S4BLDG.Coil, ... core.namespace.S4BLDG.Fan, ... core.namespace.S4BLDG.HeatExchanger ... )) >>> distribution_node = Node(cls=( ... core.namespace.S4BLDG.Duct, ... core.namespace.S4BLDG.Pipe ... )) >>> >>> # Primary connection path >>> primary_path = SinglePath( ... subject=supply_equipment, ... object=distribution_node, ... predicate=core.namespace.FSO.suppliesFluidTo ... ) >>> >>> # Alternative: Use Optional_ for specific alternative connections >>> bypass_valve = Node(cls=core.namespace.S4BLDG.Valve) >>> optional_bypass = Optional_( ... subject=supply_equipment, ... object=bypass_valve, ... predicate=core.namespace.FSO.suppliesFluidTo ... ) >>> >>> # This approach provides controlled flexibility without recursion risks
Best Practice: In most real-world implementations, use SinglePath for flexible connections and Optional_ for alternative configurations rather than MultiPath, which can cause performance issues in complex semantic models.
- PRIORITY = 1
- class Node(cls, graph_name=None, hash_=None)[source]
Bases:
object- property id
- node_instance_count = count(0)
- property semantic_model
Get the semantic model associated with this node
- property signature_pattern
- class Optional_(**kwargs)[source]
Bases:
RuleRule that makes pattern elements optional (may or may not be present).
The Optional_ rule allows signature patterns to include elements that may or may not be present in the semantic model. This is useful for creating flexible patterns that can match a variety of system configurations.
Priority: 1 (lowest priority)
Behavior
Makes the relationship optional - it may or may not exist in the semantic model
If the relationship exists, it must match the specified pattern
If the relationship doesn’t exist, the pattern can still match
Used to create flexible patterns that accommodate variations in system configurations
Examples
Optional damper parameters (from damper system):
>>> # Define damper nodes using real ontology classes >>> damper_node = Node(cls=core.namespace.S4BLDG.Damper) >>> property_value = Node(cls=core.namespace.SAREF.PropertyValue) >>> float_value = Node(cls=core.namespace.XSD.float) >>> flow_rate_node = Node(cls=core.namespace.S4BLDG.NominalAirFlowRate) >>> >>> # Optional parameter relationships - damper may have nominal flow rate >>> optional_value = Optional_( ... subject=property_value, ... object=float_value, ... predicate=core.namespace.SAREF.hasValue ... ) >>> optional_property = Optional_( ... subject=property_value, ... object=flow_rate_node, ... predicate=core.namespace.SAREF.isValueOfProperty ... ) >>> optional_damper_param = Optional_( ... subject=damper_node, ... object=property_value, ... predicate=core.namespace.SAREF.hasPropertyValue ... ) >>> >>> # Pattern matches whether or not flow rate is specified: >>> # - If flow rate exists: must match the pattern structure >>> # - If flow rate doesn't exist: pattern still matches
Optional BRICK values (from BRICK damper system):
>>> # Define BRICK nodes >>> flow_setpoint = Node(cls=core.namespace.BRICK.Air_Flow_Setpoint) >>> float_value = Node(cls=core.namespace.XSD.float) >>> >>> # Optional BRICK value - flow setpoint may have a numeric value >>> optional_brick_value = Optional_( ... subject=flow_setpoint, ... object=float_value, ... predicate=core.namespace.BRICK.hasValue ... ) >>> >>> # This allows the pattern to match BRICK models with or without >>> # explicit setpoint values configured
Optional building space components (example pattern extension):
>>> # Define building space nodes >>> building_space = Node(cls=core.namespace.S4BLDG.BuildingSpace) >>> heat_recovery = Node(cls=core.namespace.S4BLDG.AirToAirHeatRecovery) >>> humidity_sensor = Node(cls=core.namespace.SAREF.Sensor) >>> humidity_property = Node(cls=core.namespace.SAREF.Humidity) >>> >>> # Optional heat recovery system >>> optional_heat_recovery = Optional_( ... subject=building_space, ... object=heat_recovery, ... predicate=core.namespace.S4BLDG.contains ... ) >>> >>> # Optional humidity monitoring >>> optional_humidity_sensor = Optional_( ... subject=humidity_sensor, ... object=humidity_property, ... predicate=core.namespace.SAREF.observes ... ) >>> optional_humidity_in_space = Optional_( ... subject=humidity_property, ... object=building_space, ... predicate=core.namespace.SAREF.isPropertyOf ... ) >>> >>> # Pattern works for various building space configurations: >>> # - Basic space without heat recovery or humidity sensing >>> # - Space with heat recovery but no humidity sensing >>> # - Space with humidity sensing but no heat recovery >>> # - Fully equipped space with both features
Optional controller parameters (common in control systems):
>>> # Define controller nodes >>> controller_node = Node(cls=core.namespace.S4BLDG.SetpointController) >>> deadband_node = Node(cls=core.namespace.S4BLDG.Deadband) >>> gain_node = Node(cls=core.namespace.S4BLDG.ProportionalGain) >>> integral_time = Node(cls=core.namespace.S4BLDG.IntegralTime) >>> >>> # Optional controller tuning parameters >>> optional_deadband = Optional_( ... subject=controller_node, ... object=deadband_node, ... predicate=core.namespace.SAREF.hasProperty ... ) >>> optional_gain = Optional_( ... subject=controller_node, ... object=gain_node, ... predicate=core.namespace.SAREF.hasProperty ... ) >>> optional_integral = Optional_( ... subject=controller_node, ... object=integral_time, ... predicate=core.namespace.SAREF.hasProperty ... ) >>> >>> # Controller pattern matches various configurations: >>> # - Basic on/off controller (no tuning parameters) >>> # - P controller (proportional gain only) >>> # - PI controller (proportional + integral) >>> # - Full PID controller with deadband
Flexible sensor configurations (from sensor system patterns):
>>> # Define sensor nodes for position measurement >>> sensor_node = Node(cls=core.namespace.SAREF.Sensor) >>> position_node = Node(cls=core.namespace.SAREF.OpeningPosition) >>> valve_or_damper = Node(cls=( ... core.namespace.S4BLDG.Valve, ... core.namespace.S4BLDG.Damper, ... )) >>> controller_node = Node(cls=core.namespace.S4BLDG.Controller) >>> >>> # Required: sensor observes position >>> sensor_observes = Exact( ... subject=sensor_node, ... object=position_node, ... predicate=core.namespace.SAREF.observes ... ) >>> >>> # Required: position belongs to valve/damper >>> position_property = Exact( ... subject=position_node, ... object=valve_or_damper, ... predicate=core.namespace.SAREF.isPropertyOf ... ) >>> >>> # Optional: controller controls the position >>> optional_control = Optional_( ... subject=controller_node, ... object=position_node, ... predicate=core.namespace.SAREF.controls ... ) >>> >>> # Pattern matches: >>> # - Manual valve with position sensor (no controller) >>> # - Automated valve with controller and position feedback
- PRIORITY = 1
- class Rule(subject=None, object=None, predicate=None)[source]
Bases:
objectBase class for pattern matching rules that define how signature pattern elements map to semantic model elements.
Rules are the fundamental building blocks of signature patterns, defining the constraints and flexibility of the pattern matching process. Each rule specifies how a relationship between two nodes in the signature pattern should be matched against the semantic model.
Overview
Rules define the mapping between signature pattern elements and semantic model elements through: - Subject: The source node in the signature pattern - Object: The target node in the signature pattern - Predicate: The relationship type between subject and object - Priority: The precedence level for rule application (higher values take precedence)
Rule Types
The Translator supports several types of rules, each with different matching behavior:
Exact: Requires exact matches between pattern and semantic model elements
SinglePath: Allows traversal along a single path in the semantic model
MultiPath: Allows traversal along multiple paths in the semantic model
Optional: Makes pattern elements optional (may or may not be present)
Rule Composition
Rules can be combined using logical operators: - And: Both rules must be satisfied - Or: Either rule can be satisfied
Examples
>>> # Create nodes for a fan pattern >>> fan_node = Node(Fan) >>> meter_node = Node(Meter) >>> flow_node = Node(Flow) >>> >>> # Define relationships with different rule types >>> exact_rule = Exact(meter_node, fan_node, "observes") >>> path_rule = SinglePath(meter_node, flow_node, "hasValue") >>> optional_rule = Optional_(fan_node, flow_node, "hasProperty") >>> >>> # Combine rules >>> combined_rule = exact_rule & path_rule | optional_rule
- predicate
The relationship type between subject and object
- Type:
str
- PRIORITY
The precedence level for rule application
- Type:
int
- class SignaturePattern(semantic_model_=None, id=None, pedantic=False)[source]
Bases:
objectA class for defining signature patterns that describe how component models map to semantic model instances.
Signature patterns are the core mechanism by which the Translator identifies where and how component models should be instantiated within a semantic model. Each signature pattern defines a graph structure that specifies the semantic context required for a component model to be applicable.
Overview
A signature pattern consists of: - Nodes: Represent semantic model elements (components, properties, values) - Edges: Represent relationships between nodes (predicates) - Rules: Define how pattern elements map to semantic model elements - Modeled Nodes: Specify which nodes correspond to the actual component being modeled - Parameters: Define which nodes provide parameter values for the component - Inputs: Define which nodes provide input connections for the component
Pattern Structure
Signature patterns are defined using a graph-based approach where:
Each node represents a semantic model element (e.g., a Damper, Sensor, or Property)
Each edge represents a relationship between elements (e.g., “observes”, “controls”)
Rules determine how flexible the matching process is (Exact, SinglePath, MultiPath, Optional_)
The pattern matching process finds subgraph isomorphisms between the signature pattern and the semantic model, allowing the Translator to identify valid contexts for component instantiation.
- id
Unique identifier for the signature pattern
- Type:
str
- inputs
Dictionary mapping input names to nodes and their source mappings
- Type:
Dict[str, Tuple[Node, Dict]]
Examples
Basic damper control signature pattern (from actual damper system):
>>> import twin4build.core as core >>> from twin4build.translator.translator import SignaturePattern, Node, Exact, Optional_ >>> >>> def get_signature_pattern(): ... '''Create signature pattern for damper system''' ... # Define nodes using real ontology classes ... damper_node = Node(cls=core.namespace.S4BLDG.Damper) ... controller_node = Node(cls=core.namespace.S4BLDG.Controller) ... position_node = Node(cls=core.namespace.SAREF.OpeningPosition) ... property_node = Node(cls=core.namespace.SAREF.Property) ... flow_rate_node = Node(cls=core.namespace.S4BLDG.NominalAirFlowRate) ... float_value = Node(cls=core.namespace.XSD.float) ... ... # Create signature pattern with real parameters ... sp = SignaturePattern( ... semantic_model_=core.ontologies, ... ) ... ... # Add required relationships using Exact rules ... sp.add_triple( ... Exact(subject=controller_node, object=position_node, ... predicate=core.namespace.SAREF.controls) ... ) ... sp.add_triple( ... Exact(subject=position_node, object=damper_node, ... predicate=core.namespace.SAREF.isPropertyOf) ... ) ... sp.add_triple( ... Exact(subject=controller_node, object=property_node, ... predicate=core.namespace.SAREF.observes) ... ) ... ... # Add optional parameter using Optional_ rule ... sp.add_triple( ... Optional_(subject=damper_node, object=flow_rate_node, ... predicate=core.namespace.SAREF.hasPropertyValue) ... ) ... ... # Configure inputs and parameters ... sp.add_input("damperPosition", controller_node, "inputSignal") ... sp.add_parameter("nominalAirFlowRate", float_value) ... sp.add_modeled_node(damper_node) ... ... return sp
PID controller pattern with exact relationships (from actual controller implementation):
>>> def get_signature_pattern(): ... '''Create signature pattern for PID controller''' ... # Define controller nodes using real ontology classes ... controller_node = Node(cls=core.namespace.S4BLDG.SetpointController) ... sensor_node = Node(cls=core.namespace.SAREF.Sensor) ... property_node = Node(cls=core.namespace.SAREF.Property) ... schedule_node = Node(cls=core.namespace.S4BLDG.Schedule) ... reverse_node = Node(cls=core.namespace.XSD.boolean) ... ... sp = SignaturePattern( ... semantic_model_=core.ontologies, ... ) ... ... # All relationships are exact for precise control logic ... sp.add_triple( ... Exact(subject=controller_node, object=property_node, ... predicate=core.namespace.SAREF.observes) ... ) ... sp.add_triple( ... Exact(subject=sensor_node, object=property_node, ... predicate=core.namespace.SAREF.observes) ... ) ... sp.add_triple( ... Exact(subject=controller_node, object=schedule_node, ... predicate=core.namespace.SAREF.hasProfile) ... ) ... sp.add_triple( ... Exact(subject=controller_node, object=reverse_node, ... predicate=core.namespace.S4BLDG.isReverse) ... ) ... ... # Configure controller inputs and parameters ... sp.add_input("actualValue", sensor_node, "measuredValue") ... sp.add_input("setpointValue", schedule_node, "scheduleValue") ... sp.add_parameter("isReverse", reverse_node) ... sp.add_modeled_node(controller_node) ... ... return sp
Building space pattern with SinglePath for flexible connections (from building space system):
>>> def get_signature_pattern(): ... '''Create signature pattern for building space system''' ... # Define nodes for building space components ... supply_damper = Node(cls=core.namespace.S4BLDG.Damper) # supply damper ... return_damper = Node(cls=core.namespace.S4BLDG.Damper) # return damper ... building_space = Node(cls=core.namespace.S4BLDG.BuildingSpace) ... space_heater = Node(cls=core.namespace.S4BLDG.SpaceHeater) ... schedule = Node(cls=core.namespace.S4BLDG.Schedule) ... outdoor_env = Node(cls=core.namespace.S4BLDG.OutdoorEnvironment) ... supply_equipment = Node(cls=( ... core.namespace.S4BLDG.Coil, ... core.namespace.S4BLDG.AirToAirHeatRecovery, ... core.namespace.S4BLDG.Fan, ... )) ... ... sp = SignaturePattern( ... semantic_model_=core.ontologies, ... ) ... ... # Exact relationships for system topology ... sp.add_triple( ... Exact(subject=supply_damper, object=building_space, ... predicate=core.namespace.FSO.suppliesFluidTo) ... ) ... sp.add_triple( ... Exact(subject=return_damper, object=building_space, ... predicate=core.namespace.FSO.hasFluidReturnedBy) ... ) ... sp.add_triple( ... Exact(subject=space_heater, object=building_space, ... predicate=core.namespace.S4BLDG.isContainedIn) ... ) ... ... # SinglePath allows flexible connection from damper to equipment ... sp.add_triple( ... SinglePath(subject=supply_damper, object=supply_equipment, ... predicate=core.namespace.FSO.hasFluidSuppliedBy) ... ) ... ... # Configure inputs for the building space ... sp.add_input("supplyAirFlowRate", supply_damper, "airFlowRate") ... sp.add_input("exhaustAirFlowRate", return_damper, "airFlowRate") ... sp.add_input("heatGain", space_heater, "Power") ... sp.add_input("numberOfPeople", schedule, "scheduleValue") ... sp.add_input("outdoorTemperature", outdoor_env, "outdoorTemperature") ... sp.add_input("supplyAirTemperature", supply_equipment, ... ("outletAirTemperature", "primaryTemperatureOut")) ... ... sp.add_modeled_node(building_space) ... return sp
BRICK ontology pattern (from damper BRICK system):
>>> def get_signature_pattern_brick(): ... '''Create BRICK-specific signature pattern for damper''' ... damper_node = Node(cls=core.namespace.BRICK.Damper) ... position_setpoint = Node(cls=core.namespace.BRICK.Damper_Position_Setpoint) ... position_sensor = Node(cls=core.namespace.BRICK.Damper_Position_Sensor) ... flow_sensor = Node(cls=core.namespace.BRICK.Air_Flow_Sensor) ... flow_setpoint = Node(cls=core.namespace.BRICK.Air_Flow_Setpoint) ... float_value = Node(cls=core.namespace.XSD.float) ... ... sp = SignaturePattern( ... semantic_model_=core.ontologies, ... ) ... ... # BRICK-specific relationships ... sp.add_triple( ... Exact(subject=position_setpoint, object=damper_node, ... predicate=core.namespace.BRICK.isPointOf) ... ) ... sp.add_triple( ... Exact(subject=position_sensor, object=damper_node, ... predicate=core.namespace.BRICK.isPointOf) ... ) ... sp.add_triple( ... Exact(subject=flow_sensor, object=damper_node, ... predicate=core.namespace.BRICK.isPointOf) ... ) ... ... # Optional flow rate parameter ... sp.add_triple( ... Optional_(subject=flow_setpoint, object=float_value, ... predicate=core.namespace.BRICK.hasValue) ... ) ... ... sp.add_input("damperPosition", position_setpoint, "setpoint") ... sp.add_parameter("nominalAirFlowRate", float_value) ... sp.add_modeled_node(damper_node) ... ... return sp
Using signature patterns in component classes (from actual system implementation):
>>> class DamperTorchSystem(core.System, nn.Module): ... # Multiple signature patterns with different priorities ... sp = [get_signature_pattern(), get_signature_pattern_brick()] ... ... def __init__(self, a=1, nominalAirFlowRate=0.034, **kwargs): ... super().__init__(**kwargs) ... nn.Module.__init__(self) ... # System implementation...
Sensor signature patterns for space properties (from sensor system):
>>> def get_space_temperature_signature_pattern(): ... '''Pattern for temperature sensors in building spaces''' ... sensor_node = Node(cls=core.namespace.SAREF.Sensor) ... temperature_node = Node(cls=core.namespace.SAREF.Temperature) ... space_node = Node(cls=core.namespace.S4BLDG.BuildingSpace) ... ... sp = SignaturePattern( ... semantic_model_=core.ontologies, ... ) ... ... sp.add_triple( ... Exact(subject=sensor_node, object=temperature_node, ... predicate=core.namespace.SAREF.observes) ... ) ... sp.add_triple( ... Exact(subject=temperature_node, object=space_node, ... predicate=core.namespace.SAREF.isPropertyOf) ... ) ... ... sp.add_modeled_node(sensor_node) ... return sp
- property inputs
- property modeled_nodes
- property nodes
- property parameters
- property required_nodes
- property ruleset
- class SinglePath(stop_early=True, **kwargs)[source]
Bases:
RuleRule that allows traversal along a single path in the semantic model.
The SinglePath rule is more flexible than Exact, allowing the pattern matcher to traverse through intermediate nodes in the semantic model to find a path between the subject and object. This is useful when the semantic model has additional intermediate elements that aren’t part of the core pattern.
Priority: 1 (lower priority than Exact)
Behavior
Allows traversal through intermediate nodes in the semantic model
Finds a single path between subject and object
More flexible than Exact but still constrained to one path
Can stop early if stop_early=True (default)
Examples
Building space equipment connections (from building space system):
>>> # Define building space nodes using real ontology classes >>> supply_damper = Node(cls=core.namespace.S4BLDG.Damper) >>> supply_equipment = Node(cls=( ... core.namespace.S4BLDG.Coil, ... core.namespace.S4BLDG.AirToAirHeatRecovery, ... core.namespace.S4BLDG.Fan, ... )) >>> >>> # SinglePath allows flexible connection from damper to upstream equipment >>> # This can traverse through intermediate components like ducts or junctions >>> equipment_connection = SinglePath( ... subject=supply_damper, ... object=supply_equipment, ... predicate=core.namespace.FSO.hasFluidSuppliedBy ... ) >>> >>> # This will match even if the semantic model has: >>> # damper -> duct_section -> coil >>> # damper -> junction -> fan >>> # damper -> heat_recovery_unit
BRICK ontology flexible connections (from BRICK building space system):
>>> # Define BRICK nodes >>> vav_node = Node(cls=core.namespace.BRICK.VAV) # Variable Air Volume unit >>> ahu_node = Node(cls=core.namespace.BRICK.AHU) # Air Handling Unit >>> >>> # SinglePath allows traversal through BRICK equipment hierarchy >>> ahu_connection = SinglePath( ... subject=vav_node, ... object=ahu_node, ... predicate=core.namespace.BRICK.isFedBy ... ) >>> >>> # This can match complex BRICK hierarchies: >>> # VAV -> Terminal_Unit -> Zone_Equipment -> AHU >>> # VAV -> Duct_System -> AHU
Sensor connections after equipment (from sensor system):
>>> # Define sensor nodes for temperature measurement after coil >>> sensor_node = Node(cls=core.namespace.SAREF.Sensor) >>> temperature_node = Node(cls=core.namespace.SAREF.Temperature) >>> coil_air_side = Node(cls=core.namespace.S4BLDG.Coil) >>> system_after = Node(cls=core.namespace.S4SYST.System) >>> >>> # Exact relationship for sensor observation >>> sensor_observes = Exact( ... subject=sensor_node, ... object=temperature_node, ... predicate=core.namespace.SAREF.observes ... ) >>> >>> # SinglePath allows flexible connection from coil to sensor location >>> coil_to_sensor = SinglePath( ... subject=coil_air_side, ... object=sensor_node, ... predicate=core.namespace.FSO.suppliesFluidTo ... ) >>> >>> # This matches various sensor placements: >>> # coil -> duct_section -> sensor >>> # coil -> mixing_box -> sensor >>> # coil -> damper -> sensor
Multi-type node connections (common pattern):
>>> # Node that can match multiple equipment types >>> equipment_node = Node(cls=( ... core.namespace.S4BLDG.Pump, ... core.namespace.S4BLDG.Fan, ... core.namespace.S4BLDG.Compressor ... )) >>> pipe_or_duct = Node(cls=( ... core.namespace.S4BLDG.Pipe, ... core.namespace.S4BLDG.Duct ... )) >>> >>> # SinglePath for flexible fluid/air distribution >>> distribution_path = SinglePath( ... subject=equipment_node, ... object=pipe_or_duct, ... predicate=core.namespace.FSO.suppliesFluidTo ... ) >>> >>> # This allows matching: >>> # pump -> valve -> pipe >>> # fan -> damper -> duct >>> # compressor -> expansion_valve -> pipe
Flexible system topology traversal:
>>> # Building space connections with intermediate zones >>> building_space1 = Node(cls=core.namespace.S4BLDG.BuildingSpace) >>> building_space2 = Node(cls=core.namespace.S4BLDG.BuildingSpace) >>> >>> # SinglePath for adjacent zone connections through shared systems >>> adjacent_connection = SinglePath( ... subject=building_space1, ... object=building_space2, ... predicate=core.namespace.S4SYST.connectedTo ... ) >>> >>> # This can traverse: >>> # space1 -> shared_duct_system -> space2 >>> # space1 -> common_equipment -> space2 >>> # space1 -> thermal_bridge -> space2
- PRIORITY = 1
- class Translator[source]
Bases:
objectClass for ontology-driven automated model generation and calibration in building energy systems.
- Parameters:
sim2sem_map – Dictionary mapping simulation model components to semantic model instances
sem2sim_map – Dictionary mapping semantic model instances to simulation model components
instance_to_group_map – Dictionary mapping simulation model components to their corresponding signature pattern groups
This class implements a general methodology for translating semantic models of building systems into executable simulation models, as described in:
Jakob Bjørnskov, Muhyiddine Jradi, Michael Wetter, “Automated model generation and parameter estimation of building energy models using an ontology-based framework,” Energy and Buildings, Volume 329, 2025, 115228. https://doi.org/10.1016/j.enbuild.2024.115228
Overview
The Translator enables the automated generation and calibration of building energy simulation models by leveraging semantic models and a library of reusable component models. The approach is based on the following key concepts:
Semantic Models: Structured, machine-readable representations of building systems, including topology, equipment, and sensor placement, based on ontologies such as SAREF, SAREF4BLDG, SAREF4SYST, and FSO.
Component Model Library: Modular simulation components (e.g., fans, coils, controllers) each defined with a signature pattern that describes the semantic context in which the model applies.
Signature Patterns: Generalized graph patterns (subject-predicate-object triples) that specify how component models map to semantic model instances, including rules for optionality and traversal.
Automated Model Generation: The Translator searches the semantic model for matches to signature patterns, instantiates the corresponding component models, and connects them to form a complete simulation model.
Pattern Matching Process
The core of the Translator is the pattern matching process, which identifies how signature patterns map to semantic model instances. This process involves:
Graph Representation: Both the semantic model and signature patterns are represented as directed graphs with labeled nodes and edges.
Pattern Matching: The Translator searches for subgraph isomorphisms between signature patterns and the semantic model.
Rule Application: Different types of rules (Exact, SinglePath, MultiPath, Optional) determine how pattern elements map to semantic model elements.
Example of a semantic model: This diagram shows the relationships between various components in a building system, including fans, coils, sensors, meters, valves, and pumps. The different line styles represent different types of relationships (suppliesFluidTo, observes, hasValue, etc.).
Example of signature patterns: This diagram illustrates five distinct patterns (p1-p5) of interconnected components, each representing different configurations or sub-systems within a larger model. The patterns show how generic component types (Fan, Sensor, Coil, etc.) can be arranged in different ways to match various system configurations.
Example of pattern matching: This diagram shows how signature patterns are matched against the semantic model. The central graph represents the actual system components, while the surrounding “Match of signature pX” blocks show how generic pattern elements (n₁, n₂, etc.) map to specific system components. The dotted lines connect pattern elements to their corresponding system instances.
Methodology
Pattern Matching: Signature patterns are matched against the semantic model using a graph search algorithm, identifying all valid contexts for each component model.
Model Instantiation: For each match, the corresponding component model is instantiated and mapped to the relevant semantic model instances.
Model Assembly: Components are connected according to the relationships defined in the semantic model and signature patterns, resulting in an executable simulation model.
Mathematical Formulation
The task of searching for signature patterns in the semantic model is formulated as a subgraph isomorphism problem:
Given the pattern signature represented by the graph \(p = (V_p, E_p, L_p)\) and the semantic model represented by the graph \(G = (V_G, E_G, L_G)\), find the map \(f: V_p \rightarrow V_G\) such that:
\[L_G(f(u)) \subseteq L_p(u) \quad \forall u \in V_p\]\[L_p(u, v) = L_G(f(u), f(v)) \quad \forall (u, v) \in E_p\]\[(f(u), f(v)) \subseteq E_G \quad \forall (u, v) \in E_p\]- Where:
\(L_G(f(u)) \subseteq L_p(u)\) requires that the node label (ontology class) of the semantic model is a subset of the pattern node label
\(L_p(u, v) = L_G(f(u), f(v))\) ensures that the edge label (ontology predicate) of the semantic model matches the pattern edge label
\((f(u), f(v)) \subseteq E_G\) ensures that the mapped pattern edge also exists in the semantic model
For each match found, a map \(f_i\) is generated, and the corresponding component model is instantiated.
Rule Types
The Translator supports several types of rules for pattern matching:
Exact: Requires exact matches between pattern and semantic model elements
SinglePath: Allows traversal along a single path in the semantic model
MultiPath: Allows traversal along multiple paths in the semantic model
Optional: Makes pattern elements optional (may or may not be present)
These rules are combined to create flexible signature patterns that can match various system configurations while maintaining the integrity of the model structure.
Examples
>>> import twin4build as tb >>> sem_model = tb.SemanticModel("path/to/semantic_model.ttl") # or web address >>> translator = tb.Translator() >>> sim_model = translator.translate(sem_model) >>> sim_model.visualize()
- translate(semantic_model, systems_=None)[source]
Translate semantic model to simulation model using pattern matching
- Parameters:
systems – List of system types to match against
semantic_model (
SemanticModel) – The semantic model to translate
- Return type:
- Returns:
SimulationModel instance with matched components
- property sem2sim_map
- property sim2sem_map