Skip to content

22447 Add Cooling infrastructure modeling#22517

Open
arthanson wants to merge 36 commits into
featurefrom
22447-cooling
Open

22447 Add Cooling infrastructure modeling#22517
arthanson wants to merge 36 commits into
featurefrom
22447-cooling

Conversation

@arthanson

@arthanson arthanson commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Closes: #22447

Adds cooling infrastructure modeling to DCIM, mirroring the shape of the power-distribution stack and reusing the standard NetBox model features (contacts and image attachments on the facility plant, plus change logging, custom fields, and tags). This lets operators model liquid- and hybrid-cooled environments (CDUs, manifolds, RDHx, facility plant) as a source of truth.

NetBox models design intent and physical topology, not live conditions — flow and capacity are design/rated specifications, not telemetry.

The topology parallels power, with two deliberate differences:

  1. Coolant connections are direct foreign keys, not cables. Hoses aren't structured cabling, so there's no Cable/CablePath machinery; tracing a loop is an FK walk.
  2. A feed is the whole loop. One CoolingFeed represents both the supply (cold) and return (warm) paths of a single loop, rather than modeling each direction as a separate feed.
POWER:    PowerPanel    → PowerFeed    →[cable]→ PowerPort      ↔ PowerOutlet
COOLING:  CoolingSource → CoolingFeed  (serves a rack)          CoolingIntake ↔(FK) CoolingOutflow

End-to-end picture

CoolingSource  (facility plant: chiller / cooling tower / dry cooler / CRAC / CRAH)
    └── CoolingFeed  (entire loop — supply + return; serves a rack)
            ┆ serves
            ▼
          Rack   (devices installed here derive their serving feed from the rack)
            │
            ├── CDU (Device)
            │     CoolingIntake   (facility side — chilled water in)
            │     CoolingOutflow  (to in-rack equipment) ◀─┐
            │                                              │ FK: CoolingIntake.cooling_outflow
            ├── Manifold (Device)                          │
            │     CoolingIntake ───────────────────────────┘
            │     CoolingOutflow  ◀─────────────────────┐
            │                                           │ FK: CoolingIntake.cooling_outflow
            └── Server (Device)                         │
                  CoolingIntake ────────────────────────┘  (server cold-plate inlet)

Coolant connectivity is a chain of direct FKs on the downstream (consuming) side: a CoolingIntake is fed by one upstream CoolingOutflow (CoolingIntake.cooling_outflow), and a CoolingOutflow belongs to a parent CoolingIntake on the same device (CoolingOutflow.cooling_intake) — the device takes coolant in through its intake and passes it back out through its outflow. The CoolingFeed serving a device is derived from the rack the device is installed in, not stored on each intake.

In-rack cooling equipment — CDUs, manifolds, and rear-door heat exchangers (RDHx) — is modeled generically as Devices (typically zero-U) carrying these components, exactly how NetBox models a PDU as a device with power ports/outlets. No bespoke CDU/manifold/RDHx models were added.

New models

  • CoolingSource — facility plant (chiller / cooling tower / dry cooler / CRAC / CRAH), scoped to a site/location; carries the loop fluid_type and a rated cooling capacity. Reuses contacts and image attachments.
  • CoolingFeed — a single coolant loop (supply + return) delivered from a source to a rack; rated cooling capacity and rated (design) flow rate.
  • CoolingIntake — a device coolant intake (CDU facility intake, server cold-plate inlet); connector type, diameter, rated maximum flow. Fed by one upstream CoolingOutflow.
  • CoolingOutflow — a device coolant supply point (CDU / manifold outlet); connector type, diameter, optionally linked to a parent CoolingIntake on the same device.
  • CoolingIntakeTemplate / CoolingOutflowTemplate — component templates, auto-instantiated when a device or module is created.

Changes to existing models

  • Device / DeviceType / ModuleType: new cooling_method (air / liquid / hybrid / immersion). A Device inherits the value from its DeviceType on creation and may override it (like airflow); DeviceType and ModuleType carry it as a product-level attribute (ModuleType mirrors airflow — type-level only, no per-instance override). On the edit and filter forms, cooling_method and airflow are grouped under a dedicated Cooling section. Each also gains cooling component counter caches (cooling_intake_count / cooling_outflow_count, or the _template_count variants on the types).
  • Rack / RackType: cooling_capability (air-only / liquid-capable / liquid-required) and cooling_capacity (kW) defined on the shared RackBase — set on the RackType and propagated to racks (like max_weight).
  • No Cable changes — coolant connectivity is FK-based (CoolingIntake.cooling_outflow, CoolingOutflow.cooling_intake); no new cable type or cable-termination registration.

Field conventions on the new cooling models

Several quantities are modeled as value + unit with a normalized field for correct cross-unit sorting (the same pattern as weight). All are design/rated specifications, not live readings:

  • Connector type — industry-standard set: UQD, UQDB, QDC, camlock, NPT, BSP, proprietary (no single-vendor names).
  • Diameter (intakes/outflows) — mm / cm / in, normalized to mm (DiameterMixin).
  • Flow rateCoolingFeed.rated_flow_rate and CoolingIntake.maximum_flow — L/min / m³/h / GPM, normalized to L/min (MaximumFlowMixin; the feed inlines the same value/unit/normalized pattern).
  • Fluid type — recorded once on the CoolingSource (water / water-glycol / dielectric / refrigerant / other); the whole loop shares it.
  • Capacity (cooling_capacity) stays single-unit kW — the universal standard for IT cooling load, so no unit selector.

No temperature fields: supply/return temperatures are operating conditions that go stale immediately, so they belong in a monitoring stack rather than the source of truth.

No pressure field: "operating pressure" has no meaning as a design value independent of live conditions, so it's omitted rather than inviting a stored telemetry reading. If a rated pressure spec is needed later, it can be added deliberately.

Design rationale

  • No live metrics. A source of truth shouldn't store point-in-time telemetry (temperature, pressure, instantaneous flow) — it goes stale immediately and belongs in a monitoring stack (Prometheus/BMS). Retained values are stable specs: rated flow, rated capacity, fluid type, connector geometry.
  • Coolant isn't cabling. Hoses lack structured-cabling semantics (no pass-through/CablePath), so connections are direct FKs; individual hoses aren't inventoried.
  • One feed per loop. A loop's supply and return are physically inseparable, so a single CoolingFeed represents the whole loop rather than splitting it into a supply feed and a return feed.
  • Feed derived, not denormalized. A CoolingIntake doesn't store its serving CoolingFeed; the feed is resolved from the device's rack. This avoids a denormalized FK that could drift out of sync when a device is moved.
  • Simple FKs, no through model. CoolingIntake → CoolingOutflow is many-to-one, so there's no M2M requiring a through; the intake row is already the per-connection record. A dedicated connection model would only be warranted for multi-source intakes (redundancy is modeled as multiple intakes, like dual-PSU) or physical-hose inventory.
  • In-rack equipment is a device. RDHx, CDUs, and manifolds are real appliances with a make/model, so they're modeled as ordinary (typically zero-U) Devices rather than rack booleans — mirroring how NetBox has no has_pdu/has_ups flag. Rack-level liquid readiness is still expressed via Rack.cooling_capability.

Deferred (non-schema) decisions

  • Vertical/rail-mounted manifolds and RDHx — model as zero-U (u_height=0) devices, reusing the vertical-PDU pattern. A generic mounting-type field, if wanted, is a DCIM-wide enhancement, not cooling-specific.
  • Cooling-path visualization — a graphical trace widget over the FK chain is a separable UI enhancement; the MVP is an FK-walk trace.

Data model (fields & relationships)

New models list all declared fields; existing models list only the fields added by this feature. FK → marks a foreign key; _abs_* are internal columns holding the normalized value (L/min, mm) for consistent sorting/filtering.

New models

CoolingSource — facility plant
  name
  site                     FK → Site
  location                 FK → Location          (optional)
  type                     chiller | cooling-tower | dry-cooler | crac | crah
  status                   offline | active | planned | failed
  fluid_type               water | water-glycol | dielectric | refrigerant | other
  cooling_capacity         rated kW
  (also: contacts, image attachments, description, comments, tags, custom fields)

CoolingFeed — coolant loop (source → rack); one feed = supply + return
  cooling_source           FK → CoolingSource
  rack                     FK → Rack              (optional)
  tenant                   FK → Tenant            (optional)
  name
  status                   offline | active | planned | failed
  cooling_capacity         rated kW
  rated_flow_rate          design  + rated_flow_rate_unit / _abs_rated_flow_rate   (L/min)

CoolingIntake — device coolant intake
  device                   FK → Device
  module                   FK → Module            (optional)
  name / label / description
  type                     connector: uqd | uqdb | qdc | camlock | npt | bsp | proprietary
  diameter                 + diameter_unit / _abs_diameter        (mm)
  maximum_flow             rated  + maximum_flow_unit / _abs_maximum_flow   (L/min)
  cooling_outflow          FK → CoolingOutflow    (optional, upstream — the feeding outflow)

CoolingOutflow — device coolant supply
  device                   FK → Device
  module                   FK → Module            (optional)
  name / label / description
  type                     connector type
  diameter                 + diameter_unit / _abs_diameter        (mm)
  cooling_intake           FK → CoolingIntake     (optional, parent; same device)

CoolingIntakeTemplate — instantiated as a CoolingIntake on device/module creation
  device_type              FK → DeviceType        (optional)
  module_type              FK → ModuleType        (optional)
  name / label / description
  type (connector), diameter (+unit, mm), maximum_flow (rated; +unit, L/min)

CoolingOutflowTemplate — instantiated as a CoolingOutflow on device/module creation
  device_type              FK → DeviceType        (optional)
  module_type              FK → ModuleType        (optional)
  name / label / description
  type (connector), diameter (+unit, mm)
  cooling_intake           FK → CoolingIntakeTemplate  (optional, parent)

Existing models — added fields only

Device       cooling_method (air|liquid|hybrid|immersion; inherited from DeviceType)
             cooling_intake_count, cooling_outflow_count            (counter caches)
DeviceType   cooling_method
             cooling_intake_template_count, cooling_outflow_template_count
ModuleType   cooling_method
             cooling_intake_template_count, cooling_outflow_template_count
Rack         cooling_capability (air-only|liquid-capable|liquid-required)
             cooling_capacity (kW)
RackType     cooling_capability, cooling_capacity (kW)

Relationships (all foreign keys — no new many-to-many)

Site           1 ──▶ N  CoolingSource
Location       1 ──▶ N  CoolingSource                                        (optional)
CoolingSource  1 ──▶ N  CoolingFeed
Rack           1 ──▶ N  CoolingFeed                                          (optional)
Tenant         1 ──▶ N  CoolingFeed                                          (optional)
CoolingOutflow 1 ──▶ N  CoolingIntake   via CoolingIntake.cooling_outflow    (an intake is fed by one outflow)
CoolingIntake  1 ──▶ N  CoolingOutflow  via CoolingOutflow.cooling_intake    (parent intake; same device)
Device         1 ──▶ N  CoolingIntake, CoolingOutflow
Module         1 ──▶ N  CoolingIntake, CoolingOutflow                        (optional)
DeviceType /
ModuleType     1 ──▶ N  CoolingIntakeTemplate, CoolingOutflowTemplate
CoolingIntakeTemplate  1 ──▶ N  CoolingOutflowTemplate                       (parent)

A device's serving CoolingFeed is not a stored FK; it is derived from the device's rack (Rack.cooling_feeds).

Scope

Full surface area for every new model: choice sets, filtersets, forms (model/bulk-edit/bulk-import/filter/create), tables, REST API (serializers, viewsets, routes), GraphQL (types, filters, queries), search indexes, navigation (new Cooling menu), UI panels/templates, and database migrations.

@netbox-community netbox-community deleted a comment from github-actions Bot Jun 25, 2026
@arthanson

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@arthanson

This comment was marked as outdated.

@github-actions

This comment was marked as outdated.

@arthanson

This comment was marked as outdated.

@arthanson

Copy link
Copy Markdown
Collaborator Author

@claude /review Only report on issues of potential concern; we don't need commentary on anything that doesn't require further consideration. Also see comments on previous review of Declined requested changes and reasoning.

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Claude finished @arthanson's task in 7m 33s —— View job


Code Review — 22447 Add Cooling Infrastructure Modeling

  • Read key changed files
  • Analyze models, migrations, and mixins
  • Analyze API serializers and views
  • Analyze forms, filtersets, and tables
  • Check test coverage
  • Post review findings

Two issues of concern follow. Items already discussed and declined in the previous review round are not repeated.


1. New conversion functions lack unit tests

utilities/tests/test_conversions.py only covers to_grams and to_meters. The four new functions added by this PR have no test coverage:

  • to_celsius — used for _abs_supply_temperature / _abs_return_temperature normalization
  • to_millimeters — used for _abs_diameter normalization
  • to_liters_per_minute — used for _abs_flow_rate normalization
  • to_kilopascals — used for _abs_pressure normalization

These functions are the sole mechanism ensuring denormalized ordering columns are accurate. A regression (wrong conversion factor, wrong branch taken) would silently corrupt ordering and filtering across all cooling objects without any test catching it.

Fix this →


2. CoolingPort.maximum_flow has an implicit unit (L/min) inconsistent with CoolingFeed.flow_rate

CoolingPort.maximum_flow (device_components.py:714) is a raw DecimalField with help text "(L/min)". Its partner on the feed side — CoolingFeed.flow_rate — uses FlowRateMixin, meaning it carries an explicit flow_rate_unit and a normalized _abs_flow_rate (in L/min) for ordering/filtering.

The asymmetry means:

  • A feed carrying 10 GPM is stored with flow_rate=10, flow_rate_unit='gpm', _abs_flow_rate≈37.85.
  • The port it connects to may have maximum_flow=40 (intended as L/min) — close enough — but there is no unit field to confirm this, and no way to filter "ports whose max flow ≥ feed flow rate" across units without application-level logic.

This is a design decision rather than a bug, but it creates a subtle inconsistency: two fields that represent the same physical quantity on either side of a connection use different representations. Worth considering whether maximum_flow should also use FlowRateMixin (adding maximum_flow_unit + _abs_maximum_flow) to be consistent with the rest of the cooling field conventions.

Fix this →

@arthanson

Copy link
Copy Markdown
Collaborator Author

Both Claude review issues addressed.

@arthanson
arthanson marked this pull request as ready for review June 25, 2026 23:24
@arthanson
arthanson requested review from a team and jeremystretch and removed request for a team June 25, 2026 23:24

@jeremystretch jeremystretch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good start, but let's rethink the data model some. Specifically consider:

  1. Do we need to model individual hoses? If so, how do we handle multi-point connectors (e.g. a hose with a 1-to-n splitter)?
  2. Do we need to explicitly model the return path in addition to the supply path?
  3. What are the canonical types of physical inlet & outlet connectors that we need to capture? Is diameter alone sufficient to convey these?
  4. What temperature information belongs in the data model vs. observability metrics?

The description in FR #22447 was lifted from an initial feature draft; it probably needs a lot more consideration regarding real-world modeling and constraints. It might help to investigate various real-world cooling distribution implementations and determine how we would optimally model those specific instances in NetBox.

Comment thread netbox/dcim/models/cooling.py Outdated
Comment thread netbox/netbox/models/mixins.py Outdated
Comment thread netbox/netbox/models/mixins.py Outdated
Comment thread netbox/netbox/models/mixins.py Outdated
Comment thread netbox/dcim/models/device_components.py Outdated
Comment thread netbox/dcim/models/device_components.py Outdated
@adamboutcher

Copy link
Copy Markdown
Contributor

Historical related issue #6987 useful for searching etc.

Comment thread netbox/dcim/models/device_components.py Outdated
Comment thread netbox/dcim/models/cooling.py Outdated
Comment thread netbox/dcim/models/device_components.py Outdated
Comment thread netbox/dcim/models/mixins.py Outdated
Comment thread netbox/dcim/models/mixins.py
Comment thread netbox/dcim/models/racks.py Outdated
Comment thread netbox/dcim/models/device_components.py Outdated
Comment thread netbox/dcim/models/device_components.py Outdated
Comment thread netbox/dcim/models/device_component_templates.py Outdated
Comment thread netbox/dcim/models/cooling.py Outdated
@mrmrcoleman

Copy link
Copy Markdown
Collaborator

Overall a solid keeping the power-model shape. Most deviations from FR #22447 are reasonable simplifications (several requested in review). Notes below, kept short.

Decisions

  • Design supply/return temperatures — defer. Not telemetry (they're design setpoints, like rated capacity), but a clean two-way door: adding nullable °C fields later is a purely additive migration, no backfill. Fine to leave out of v1 and add as a fast-follow.
  • RDHx — defer, with notes below. Keep the current "model it as a zero-U device" direction; don't add a Rack.has_rdhx boolean now (it'd create a second source of truth that drifts from the device).

RDHx notes (for whoever picks it up)

  • An RDHx is 1:1 with a rack — a water-cooled coil that replaces the rear door of one cabinet. It isn't shared or free-standing, and it doesn't occupy a U-slot, so a zero-U device is a slightly forced fit (no rear-door mount concept exists).
  • "Which racks have an RDHx?" is not free with the device approach. Verified: RackFilterSet has no devices__ traversal filter, and there's no built-in RDHx device role/type. Today you can only filter the Device list by role — that returns devices, not a rack list, and can't do the inverse ("racks missing one").
  • If we later add RDHx-as-device, plan to also add a small RackFilterSet filter traversing devices__role (needs distinct=True). Otherwise the FR's "RDHx tracking" reporting need is quietly dropped.
  • Also unaddressed (defer, but flag): partial-U-coverage RDHx and active-vs-passive (raised by @adamboutcher on the FR).

Endorsed simplifications (no change requested)

  • FK instead of cooling-hose cables — reasonable; handles 1-to-n splitters and dual-feed redundancy (multiple intakes), reviewer-endorsed.
  • One feed = whole loop (supply + return combined) — fine simplification; return is modeled implicitly.

Documentation suggestions

  • Add a short mapping from the new names/relationships back to power so existing users' mental model transfers: CoolingIntakePowerPort, CoolingOutflowPowerOutlet, FK chain ≈ cable.
  • Explicitly document the deliberate v1 limitations so they read as conscious cuts, not gaps: return path implicit, path tracing / impact-analysis deferred, no per-hose inventory, no design pressure/temperature yet.

Deferred but acceptable (noted, not blocking)

  • Design/rated pressure on the feed — likely fast-follow depending on feedback.
  • Independent supply/return modeling (asymmetric routing, separate return failure).
  • Path tracing + impact analysis ("if this loop fails, what loses cooling?") — an FR headline use case, deferred pending model approval; make sure it lands soon after.

@arthanson
arthanson requested a review from jeremystretch July 21, 2026 17:28

@jeremystretch jeremystretch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unclear on the intended use of CoolingIntake. Is it meant to model the return path of warm coolant from a device back to its originating cooling feed/source, or is it to be used solely for the distribution of cold coolant (and the return path is implied to mirror the cold path)?

Comment thread docs/features/cooling.md

## Relationship to Power

The cooling stack deliberately mirrors the [power distribution](./power-tracking.md) model:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is accurate any longer, given that connections among power ports & outlets are represented using cables. I would avoid referencing the power data model, and just present cooling as its own independent entity.

@adamboutcher adamboutcher Jul 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So not in my data centre but there is certainly scope where the cold (in) and warm (out) may not mirror.

I will add that the in and out feed in my case are not numbered the same so referencing to plumbers I couldn't say connection 22 is a cold and warm.

Comment thread docs/features/cooling.md

## Cooling Sources

A [cooling source](../models/dcim/coolingsource.md) is the furthest upstream cooling element modeled in NetBox, representing facility plant such as a chiller, cooling tower, dry cooler, or CRAC/CRAH unit. Each source is associated with a site, and may optionally be associated with a particular location within that site. A cooling source is not a device; it represents external facility plant, and records the coolant (fluid type) and total rated cooling capacity for the loops it originates.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A [cooling source](../models/dcim/coolingsource.md) is the furthest upstream cooling element modeled in NetBox, representing facility plant such as a chiller, cooling tower, dry cooler, or CRAC/CRAH unit. Each source is associated with a site, and may optionally be associated with a particular location within that site. A cooling source is not a device; it represents external facility plant, and records the coolant (fluid type) and total rated cooling capacity for the loops it originates.
A [cooling source](../models/dcim/coolingsource.md) is the furthest upstream cooling element modeled in NetBox, representing a chiller, cooling tower, dry cooler, or CRAC/CRAH unit. Each source is associated with a site, and may optionally be associated with a particular location within that site. A cooling source is not a device; it represents external facility plant, and records the coolant (fluid type) and total rated cooling capacity for the loops it originates.

Comment thread docs/features/cooling.md

## Cooling Feeds

A [cooling feed](../models/dcim/coolingfeed.md) represents a coolant loop originating from a cooling source and serving a particular rack. Each feed records an operational status, a rated cooling capacity, and a rated (design) flow rate.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A [cooling feed](../models/dcim/coolingfeed.md) represents a coolant loop originating from a cooling source and serving a particular rack. Each feed records an operational status, a rated cooling capacity, and a rated (design) flow rate.
A [cooling feed](../models/dcim/coolingfeed.md) represents a coolant loop running between a cooling source and a particular rack. Each feed records an operational status, a rated cooling capacity, and a rated (design) flow rate.

Comment thread docs/features/cooling.md
Comment on lines +29 to +30
The [cooling intakes](../models/dcim/coolingintake.md) a feed supplies are not listed on the feed explicitly; they are derived from the devices installed in the rack the feed serves. Moving a device to a different rack therefore reassigns it to that rack's feed automatically.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems redundant to the section below.

Suggested change
The [cooling intakes](../models/dcim/coolingintake.md) a feed supplies are not listed on the feed explicitly; they are derived from the devices installed in the rack the feed serves. Moving a device to a different rack therefore reassigns it to that rack's feed automatically.

Comment thread docs/features/cooling.md
Comment on lines +48 to +54
!!! note "Scope of the initial version"
The cooling model captures topology and design specifications. A few capabilities are intentionally left out at this point:

- **The return path is implicit.** A single feed models the whole loop; the supply and return legs are not traced as separate objects.
- **Path tracing and impact analysis are not yet surfaced.** The reference chain supports tracing a loop, but there is no graphical trace or "what does this source feed?" view yet.
- **Individual hoses are not inventoried.** Connections are modeled as direct references, not as first-class cable objects.
- **No design pressure or temperature.** These are operating conditions with no stable design value independent of live readings, so they are recorded in a monitoring system rather than in NetBox.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scope of the documentation is limited to what the application currently supports.

Suggested change
!!! note "Scope of the initial version"
The cooling model captures topology and design specifications. A few capabilities are intentionally left out at this point:
- **The return path is implicit.** A single feed models the whole loop; the supply and return legs are not traced as separate objects.
- **Path tracing and impact analysis are not yet surfaced.** The reference chain supports tracing a loop, but there is no graphical trace or "what does this source feed?" view yet.
- **Individual hoses are not inventoried.** Connections are modeled as direct references, not as first-class cable objects.
- **No design pressure or temperature.** These are operating conditions with no stable design value independent of live readings, so they are recorded in a monitoring system rather than in NetBox.

Comment thread netbox/netbox/choices.py
)


class PressureUnitChoices(ChoiceSet):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this if we remove to_kilopascals().

Comment thread netbox/netbox/choices.py

# Metric
UNIT_LITERS_PER_MINUTE = 'lpm'
UNIT_CUBIC_METERS_PER_HOUR = 'm3h'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should arguably include the "p" for consistency with lpm and gpm.

Suggested change
UNIT_CUBIC_METERS_PER_HOUR = 'm3h'
UNIT_CUBIC_METERS_PER_HOUR = 'm3ph'

Comment on lines +26 to +29
### Type

Indicates whether the outlet carries supply (cold) or return (warm) coolant.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a remnant from an earlier implementation.

Suggested change
### Type
Indicates whether the outlet carries supply (cold) or return (warm) coolant.

required=False,
allow_null=True
)
cooling_outflow = serializers.PrimaryKeyRelatedField(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be some form of a nested CoolingOutflowSerializer. (You might need to create a standalone NestedCoolingOutflowSerializer class to resolve the circular dependency.)


class CoolingIntake(DiameterMixin, MaximumFlowMixin, ModularComponentModel, TrackingModelMixin):
"""
A coolant intake/outlet port within a Device (e.g. a server cold-plate inlet or CDU intake). A

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A coolant intake/outlet port within a Device (e.g. a server cold-plate inlet or CDU intake). A
A coolant intake port within a Device (e.g. a server cold-plate inlet or CDU intake). A

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants