Write docs for system API module

This commit is contained in:
Dion Moult
2023-01-04 16:09:26 +11:00
parent b86818ead3
commit 92623b98e2
10 changed files with 322 additions and 47 deletions
@@ -21,13 +21,38 @@ import ifcopenshell.api
class Usecase:
def __init__(self, file, **settings):
def __init__(self, file, element=None):
"""Adds a new distribution port to an element
A distribution port represents a connection point on an element, where
a distribution element may be connected to another distribution element.
For example, a duct segment will typically have two ports, one at either
end, because you can attach another segment or fitting to either end of
the duct segment.
This will both add a distribution port and automatically assign it to a
distribution element.
:param element: The IfcDistributionElement you want to add a
distribution port to.
:type element: ifcopenshell.entity_instance.entity_instance
:return: The newly created IfcDistributionPort
:rtype: ifcopenshell.entity_instance.entity_instance
Example::
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create 2 ports, one for either end.
port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
"""
self.file = file
self.settings = {
"element": None,
"element": element,
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
port = ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcDistributionPort")
@@ -21,11 +21,30 @@ import ifcopenshell.api
class Usecase:
def __init__(self, file, **settings):
def __init__(self, file, ifc_class="IfcDistributionSystem"):
"""Add a new distribution system
A distribution system is a group of distribution elements, like ducts,
pipes, pumps, filters, fans, and so on that distribute a medium (air,
liquid, or electricity) throughout a facility. Systems may be
hierarchical, with larger systems composed of smaller subsystems.
:param ifc_class: The type of system, chosen from IfcDistributionSystem
for mechanical, electrical, communications, plumbing, fire, or
security systems. Alternatively you may choose IfcBuildingSystem for
specialised building facade systems or similar. For IFC2X3, choose
IfcSystem.
:type ifc_class: str
:return: The newly created IfcSystem.
:rtype: ifcopenshell.entity_instance.entity_instance
Example::
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
"""
self.file = file
self.settings = {"ifc_class": "IfcSystem"}
for key, value in settings.items():
self.settings[key] = value
self.settings = {"ifc_class": ifc_class}
def execute(self):
return self.file.create_entity(
@@ -22,14 +22,42 @@ import ifcopenshell.util.placement
class Usecase:
def __init__(self, file, **settings):
def __init__(self, file, element=None, port=None):
"""Assigns a port to an element
If you have an orphaned port, you may assign it to a distribution
element using this function. Ports should typically not be orphaned, but
it may be useful when patching up models.
:param element: The IfcDistributionElement to assign the port to.
:type element: ifcopenshell.entity_instance.entity_instance
:param port: The IfcDistributionPort you want to assign.
:type port: ifcopenshell.entity_instance.entity_instance
:return: The IfcRelNests relationship, or the
IfcRelConnectsPortToElement for IFC2X3.
:rtype: ifcopenshell.entity_instance.entity_instance
Example::
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create 2 ports, one for either end.
port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
# Unassign one port for some weird reason.
ifcopenshell.api.run("system.unassign_port", model, element=duct, port=port1)
# Reassign it back
ifcopenshell.api.run("system.assign_port", model, element=duct, port=port1)
"""
self.file = file
self.settings = {
"element": None,
"port": None,
"element": element,
"port": port,
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
if self.file.schema == "IFC2X3":
@@ -49,14 +49,35 @@ def is_assignable(product, system) -> bool:
class Usecase:
def __init__(self, file, **settings):
def __init__(self, file, product=None, system=None):
"""Assigns a distribution element to a system
Note that it is not necessary to assign distribution ports to a system.
:param product: The IfcDistributionElement to assign to the system.
:type product: ifcopenshell.entity_instance.entity_instance
:param system: The IfcSystem you want to assign the element to.
:type system: ifcopenshell.entity_instance.entity_instance
:return: The IfcRelAssignsToGroup relationship
:rtype: ifcopenshell.entity_instance.entity_instance
Example::
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# This duct is part of the system
ifcopenshell.api.run("system.assign_system", model, product=duct, system=system)
"""
self.file = file
self.settings = {
"product": None,
"system": None,
"product": product,
"system": system,
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
system = self.settings["system"]
@@ -21,16 +21,80 @@ import ifcopenshell.api
class Usecase:
def __init__(self, file, **settings):
def __init__(self, file, port1=None, port2=None, direction="NOTDEFINED", element=None):
"""Connects two ports together
A distribution element (e.g. a duct) may be connected to another
distribution element (e.g. a fitting) by connecting a port at one of the
duct to a port at the same end of the fitting.
Ports may only have one connection, so you cannot have multiple things
connected to the same port. Nor can you have incompatible port
connections, such as an electrical port connected to an airflow port.
Port connectivity may be explicit or implicit. Explicit connections are
where the port connectivity is described for every single distribution
element in detail. For example, a duct segment would have port
connections to a duct fitting, which would have port connections to
another duct segment, all the way from a fan to an air terminal exactly
as constructed on site. Implicit connections only consider the key
distribution control elements (e.g. the fan and the terminal) and ignore
all of the details of the duct segments and fittings in between.
Generally, explicit connectivity is preferred for later detailed design,
and implicit connectivity is preferred for early phase design.
:param port1: The port of the first distribution element to connect.
:type port1: ifcopenshell.entity_instance.entity_instance
:param port2: The port of the second distribution element to connect.
:type port2: ifcopenshell.entity_instance.entity_instance
:param direction: The directionality of distribution flow through the
port connection. NOTDEFINED means that the direction has not yet
been determined. This is useful during preliminary system design.
SOURCE means that the flow is from the first element to the second
element. SINK means that the flow is from the second element to the
first element. SOURCEANDSINK means that flow is bi-directional
between the first and second element. SOURCEANDSINK is a relatively
rare scenario.
:type direction: str
:param element: Optionally set an element through which the port
connectivity is made, such as a segment or fitting. This is only to
be used for implicit port connectivity where the segments and
fittings are less important.
:type element: ifcopenshell.entity_instance.entity_instance
Example::
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Create a duct and a 90 degree bend fitting
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
fitting = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctFitting", predefined_type="BEND")
# The duct and fitting is part of the system
ifcopenshell.api.run("system.assign_system", model, product=duct, system=system)
ifcopenshell.api.run("system.assign_system", model, product=fitting, system=system)
# Create 2 ports, one for either end of both the duct and fitting.
duct_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
duct_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
fitting_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
fitting_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
# Connect the duct and fitting together. At this point, we have not
# yet determined the direction of the flow, so we leave direction as
# NOTDEFINED.
ifcopenshell.api.run("system.connect_port", model, port1=duct_port2, port2=fitting_port1)
"""
self.file = file
self.settings = {
"port1": None,
"port2": None,
"direction": "NOTDEFINED",
"element": None,
"port1": port1,
"port2": port2,
"direction": direction,
"element": element,
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
# Note: there are a number of ambiguities with port connectivity. We
@@ -21,13 +21,51 @@ import ifcopenshell.api
class Usecase:
def __init__(self, file, **settings):
def __init__(self, file, port=None):
"""Disconnects a port from any other port
A port may only be connected to one other port, so the other port is not
needed to be specified.
:param port: The IfcDistributionPort to disconnect.
:type port: ifcopenshell.entity_instance.entity_instance
:return: None
:rtype: None
Example::
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Create a duct and a 90 degree bend fitting
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
fitting = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctFitting", predefined_type="BEND")
# The duct and fitting is part of the system
ifcopenshell.api.run("system.assign_system", model, product=duct, system=system)
ifcopenshell.api.run("system.assign_system", model, product=fitting, system=system)
# Create 2 ports, one for either end of both the duct and fitting.
duct_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
duct_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
fitting_port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
fitting_port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
# Connect the duct and fitting together. At this point, we have not
# yet determined the direction of the flow, so we leave direction as
# NOTDEFINED.
ifcopenshell.api.run("system.connect_port", model, port1=duct_port2, port2=fitting_port1)
# Disconnect the port. note we could've equally disconnected
# fitting_port1 instead of duct_port2
ifcopenshell.api.run("system.disconnect_port", model, port=duct_port2)
"""
self.file = file
self.settings = {
"port": None,
"port": port,
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
rels = self.settings["port"].ConnectedTo or []
@@ -18,11 +18,30 @@
class Usecase:
def __init__(self, file, **settings):
def __init__(self, file, system=None, attributes=None):
"""Edits the attributes of an IfcSystem
For more information about the attributes and data types of an
IfcSystem, consult the IFC documentation.
:param system: The IfcSystem entity you want to edit
:type system: ifcopenshell.entity_instance.entity_instance
:param attributes: a dictionary of attribute names and values.
:type attributes: dict, optional
:return: None
:rtype: None
Example::
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Change the name of the system to "HW" for Hot Water
ifcopenshell.api.run("system.edit_system", model, system=system, attributes={"Name": "HW"})
"""
self.file = file
self.settings = {"system": None, "attributes": {}}
for key, value in settings.items():
self.settings[key] = value
self.settings = {"system": system, "attributes": attributes or {}}
def execute(self):
for name, value in self.settings["attributes"].items():
@@ -18,11 +18,26 @@
class Usecase:
def __init__(self, file, **settings):
def __init__(self, file, system=None):
"""Removes a distribution system
All the distribution elements within the system are retained.
:param system: The IfcSystem to remove.
:type system: ifcopenshell.entity_instance.entity_instance
:return: None
:rtype: None
Example::
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Delete it.
ifcopenshell.api.run("system.remove_system", model, system=system)
"""
self.file = file
self.settings = {"system": None}
for key, value in settings.items():
self.settings[key] = value
self.settings = {"system": system}
def execute(self):
for rel in self.settings["system"].IsGroupedBy or []:
@@ -21,14 +21,38 @@ import ifcopenshell.api
class Usecase:
def __init__(self, file, **settings):
def __init__(self, file, element=None, port=None):
"""Unassigns a port to an element
Ports are typically always assigned to a distribution element, but in
some edge cases you may want to unassign the port to create an orphaned
port for cleaning or patchin purposes.
:param element: The IfcDistributionElement to unassign the port from.
:type element: ifcopenshell.entity_instance.entity_instance
:param port: The IfcDistributionPort you want to unassign.
:type port: ifcopenshell.entity_instance.entity_instance
:return: None
:rtype: None
Example::
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# Create 2 ports, one for either end.
port1 = ifcopenshell.api.run("system.add_port", model, element=duct)
port2 = ifcopenshell.api.run("system.add_port", model, element=duct)
# Unassign one port for some weird reason.
ifcopenshell.api.run("system.unassign_port", model, element=duct, port=port1)
"""
self.file = file
self.settings = {
"element": None,
"port": None,
"element": element,
"port": port,
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
if self.file.schema == "IFC2X3":
@@ -21,14 +21,36 @@ import ifcopenshell.api
class Usecase:
def __init__(self, file, **settings):
def __init__(self, file, product=None, system=None):
"""Unassigns a product from a system
:param product: The IfcDistributionElement to unassign from the system.
:type product: ifcopenshell.entity_instance.entity_instance
:param system: The IfcSystem you want to unassign the element from.
:type system: ifcopenshell.entity_instance.entity_instance
:return: None
:rtype: None
Example::
# A completely empty distribution system
system = ifcopenshell.api.run("system.add_system", model)
# Create a duct
duct = ifcopenshell.api.run("root.create_entity", model,
ifc_class="IfcDuctSegment", predefined_type="RIGIDSEGMENT")
# This duct is part of the system
ifcopenshell.api.run("system.assign_system", model, product=duct, system=system)
# Not anymore!
ifcopenshell.api.run("system.unassign_system", model, product=duct, system=system)
"""
self.file = file
self.settings = {
"product": None,
"system": None,
"product": product,
"system": system,
}
for key, value in settings.items():
self.settings[key] = value
def execute(self):
if not self.settings["system"].IsGroupedBy: