Group equipment into systems and spaces#
Place equipment in a room, group it into a system that meets the rest of the plant at a few points, or put components inside a larger piece of equipment.
Place equipment in a space#
An object opened with with becomes a container. Objects created inside are
linked with the predicate the ontology uses for that pair of classes:
from plumb import Model, connect
from plumb.watr import PhysicalSpace, Pump
from plumb.watr.drinking_water import ClarificationStage, RapidSandFiltrationStage
model = Model("urn:example:plant#")
with model:
with PhysicalSpace("filter-building") as building:
backwash_pump = Pump("backwash-pump")
list(backwash_pump.has_physical_location)
[<PhysicalSpace 'filter-building'>]
Equipment in a PhysicalSpace is located there with
s223:hasPhysicalLocation. A DomainSpace inside a PhysicalSpace is
enclosed by it, and spaces nest through s223:contains, exposed as
contains_.
container.contains(child)does the same without a block.via="property_name"picks the predicate when more than one applies.A class the container cannot hold raises
ContainmentError.
Group equipment into a system#
model.system(name) collects the equipment created inside it into an S223
System. boundary() marks the points where the system meets the rest of
the plant:
with model:
intake = Pump("intake-pump")
with model.system("treatment") as treatment:
clarifier = ClarificationStage("clarifier")
sand_filter = RapidSandFiltrationStage("sand-filter")
connect(intake, clarifier.inlet, name="raw-water")
connect(clarifier.clarified_water, sand_filter.inlet, name="clarified-water")
treatment.boundary(
clarifier.sludge,
sand_filter.filtered_water,
sand_filter.backwash_supply,
sand_filter.backwash_waste,
)
resolved = model.resolve()
list(resolved["treatment"].has_boundary_connection_point)
[<OutletConnectionPoint 'clarifier-sludge'>,
<InletConnectionPoint 'sand-filter-backwash_supply'>,
<OutletConnectionPoint 'sand-filter-backwash_waste'>,
<OutletConnectionPoint 'sand-filter-filtered_water'>,
<InletConnectionPoint 'clarifier-inlet'>]
A connection that crosses into the system, such as the raw-water pipe, makes
its point a boundary point when the model resolves. A boundary point may also
connect to nothing in the model; it is then a feed or product of the system.
Ports work too: intake.port("river", direction="in").
Put components inside equipment#
Equipment can contain equipment. A damper and fan created inside an air handling unit are its parts:
from plumb.s223 import AirHandlingUnit, Damper, Fan
with Model("urn:example:air#") as air:
with AirHandlingUnit("ahu") as ahu:
damper = Damper("outside-air-damper")
fan = Fan("supply-fan")
zone_damper = Damper("zone-damper")
connect(damper, fan)
connect(ahu, zone_damper, name="supply-duct")
list(ahu.contains_)
[<Damper 'outside-air-damper'>, <Fan 'supply-fan'>]
The AHU’s own inlet and outlet stand for points on its parts. maps_to says
which, so a walk can step through the AHU to the parts behind its ports:
air["outside-air-damper-in"].maps_to = air["ahu-in"]
air["supply-fan-out"].maps_to = air["ahu-out"]
air.resolve()["zone-damper"].find_all_previous(descend=True)
[<AirHandlingUnit 'ahu'>, <Fan 'supply-fan'>, <Damper 'outside-air-damper'>]
Map a part’s port onto its container#
A port can stand for a part’s point too. A cooling coil inside the AHU takes chilled water, but the AHU’s own shape has only air points. Give the AHU a port for the water and map the coil’s inlet onto it:
from plumb.s223 import Chiller
from plumb.s223.hvac import AirWaterCoolingCoil
with Model("urn:example:plant-room#") as plant:
with AirHandlingUnit("ahu") as ahu:
coil = AirWaterCoolingCoil("cooling-coil")
chiller = Chiller("chiller")
chw_in = ahu.port("chw-in", direction="in")
chw_out = ahu.port("chw-out", direction="out")
coil.water_inlet.maps_to = chw_in
coil.water_outlet.maps_to = chw_out
connect(chiller, chw_in, name="chw-supply")
connect(chw_out, chiller, name="chw-return")
resolved = plant.resolve()
resolved["chw-in"].medium, resolved["chiller"].find_all_next(descend=True)
(<enum Fluid-Water>,
[<AirHandlingUnit 'ahu'>, <AirWaterCoolingCoil 'cooling-coil'>])
The coil’s water inlet and the AHU port resolve to one medium, so the AHU port carries water although nothing on the AHU says so. Mapped points must face the same way: an inlet maps to an inlet. Pipes connect to the AHU’s port, not to the coil, as 223P requires for equipment inside equipment.
Either side of maps_to can be a port, a named point such as
coil.water_inlet, or a concrete point such as plant["ahu-in"]. A port
cannot map to a point of its own equipment.
Find what contains what#
contents, find_all(), and find_parent() search containment, and
descend=True walks into containers. See
Find objects in a model.