opensolve-pipe-data-model
OpenSolve Pipe component chain data model conventions. Use when creating or modifying components, piping segments, or project structures.
安装与使用
请根据来源仓库和你的 AI 工具说明安装此技能。先阅读技能文件和依赖要求,再添加到工作流。
查看来源 ↗使用指南技能说明
OpenSolve Pipe Data Model Skill
Component Chain Model
The primary data structure is a component chain, NOT a node-link graph.
Each component has:
-
id: unique identifier (format:{type}-{number}, e.g., "pump-1") -
type: component type enum -
name: user-friendly display name -
elevation: in project units -
upstreamPiping: optional PipingSegment -
downstreamConnections: array of Connection objects
Component ID Conventions
Use consistent naming patterns for automatic ID generation:
-
Pumps:
pump-1,pump-2, ... -
Valves:
valve-1,valve-2, ... (orvalve-prv-1for specific types) -
Tanks:
tank-1,reservoir-1, ... -
Junctions:
junction-1,junction-2, ... -
Heat Exchangers:
hx-1,hx-2, ... -
Strainers:
strainer-1,strainer-2, ... -
Orifices:
orifice-1,orifice-2, ... -
Sprinklers:
sprinkler-1,sprinkler-2, ...
Format: {type}-{incrementing-number}
PipingSegment Structure
interface PipingSegment {
pipe: {
material: string, // Reference to materials library (e.g., "carbon_steel")
nominalDiameter: number, // Nominal pipe size (e.g., 2.5, 3, 4, 6)
schedule: string, // Pipe schedule (e.g., "40", "80", "160")
length: number, // Pipe length in project units
roughness?: number // Override if user specifies custom roughness
},
fittings: Fitting[] // Array of fittings in this segment
}
Fitting Structure
interface Fitting {
id: string, // Reference to fittings library (e.g., "elbow_90_lr")
name: string, // Display name (e.g., "90° Long Radius Elbow")
quantity: number, // Number of this fitting in segment
kFactor?: number, // User override for K-factor
equivalentLengthD?: number // User override for equivalent length (L/D)
}
Notes:
- If both
kFactorandequivalentLengthDare provided,kFactortakes precedence - If neither is provided, use library default
Component Types
Node Types (Boundary Conditions)
Reservoir:
{
id: "reservoir-1",
type: "reservoir",
name: "Supply Tank",
elevation: 100, // ft or m
waterLevel: 150, // Total head (elevation + static height)
downstreamConnections: [...]
}
Tank:
{
id: "tank-1",
type: "tank",
name: "Storage Tank",
elevation: 50,
diameter: 10, // ft or m
initialLevel: 10, // ft or m above tank bottom
minLevel: 2,
maxLevel: 12,
upstreamPiping: {...},
downstreamConnections: [...]
}
Junction:
{
id: "junction-1",
type: "junction",
name: "Branch Point",
elevation: 50,
demand: 0, // Optional withdrawal (GPM or L/s)
upstreamPiping: {...},
downstreamConnections: [ // Multiple connections for branching
{ targetComponentId: "pipe-2", piping: {...} },
{ targetComponentId: "pipe-3", piping: {...} }
]
}
Link Types (Active Components)
Pump:
{
id: "pump-1",
type: "pump",
name: "Primary Pump",
elevation: 50,
curve: {
id: "curve-1",
name: "Grundfos CR10-5",
manufacturer: "Grundfos",
model: "CR10-5",
points: [
{ flow: 0, head: 150 },
{ flow: 100, head: 145 },
{ flow: 200, head: 130 },
// ... more points
],
efficiencyCurve?: [...] // Optional
},
speed: 1.0, // Fraction of rated speed (1.0 = 100%)
status: "on", // "on" or "off"
npshr?: [...], // Optional NPSH required curve
upstreamPiping: {...},
downstreamConnections: [...]
}
Valve:
{
id: "valve-prv-1",
type: "valve",
valveType: "prv", // "gate", "ball", "check", "prv", "psv", "fcv"
name: "Pressure Reducing Valve",
elevation: 50,
model: "simplified", // "simplified" or "detailed"
setpoint: 60, // Target pressure (psi or kPa)
upstreamPiping: {...},
downstreamConnections: [...]
}
Heat Exchanger:
{
id: "hx-1",
type: "heat_exchanger",
name: "Plate HX",
elevation: 50,
pressureDrop: 5, // Fixed pressure drop (psi or kPa)
upstreamPiping: {...},
downstreamConnections: [...]
}
Connection Structure
interface Connection {
targetComponentId: string, // ID of downstream component
piping: PipingSegment // Piping between this component and target
}
Validation Rules
-
Every component must have unique id
- No duplicate IDs in component array
- IDs must follow naming convention
-
Reservoir/Tank must be at start or end of chain
- Reservoir typically at start (infinite source)
- Tank typically at end (discharge point)
-
Pump must have at least one downstream connection
- Cannot be a dead end
- Must pump to somewhere
-
Branching requires Junction component
- Junction has multiple downstream connections
- Each branch modeled explicitly
-
Loops must have at least one pump
- Cannot have loop without active component
- Network solver handles loop balancing
-
Piping segments must reference valid materials/fittings
- Material ID must exist in
pipe_materials.json - Fitting ID must exist in
fittings.json
- Material ID must exist in
-
Physical constraints
- Elevations must be positive (or allow negative with datum reference)
- Pipe lengths must be positive
- Diameters must be positive
- Flow rates must be non-negative (negative = reverse flow)
Solver Conversion
Simple Solver (Single Path)
- Walks component chain in order
- Calculates head loss cumulatively
- Finds operating point by intersecting pump and system curves
Network Solver (Branching/Looped)
- Converts component chain to WNTR node-link graph
- Nodes: Reservoirs, Tanks, Junctions (implicit nodes created at pumps/valves)
- Links: Pipes (with equivalent K for fittings), Pumps, Valves
- WNTR/EPANET solves for pressures and flows
Adding New Component Types
When adding a new component type, follow these steps:
-
Add to ComponentType enum
type ComponentType = | "reservoir" | "tank" | "junction" | "pump" | "valve" | "heat_exchanger" | "strainer" // ← New type | ... -
Create interface extending BaseComponent
interface Strainer extends BaseComponent { type: "strainer"; meshSize: number; // Mesh opening size cleanPressureDrop: number; // Clean pressure drop dirtyPressureDrop: number; // Dirty pressure drop (for warnings) } -
Add to solver adapter
-
simple.py: Add component handling in chain walker -
network.py: Add conversion to WNTR equivalent
-
-
Add UI panel
-
apps/web/src/lib/components/panel/StrainerPanel.svelte
-
-
Add schematic symbol
-
apps/web/static/symbols/strainer.svg
-
-
Update data schema
- Add to
apps/api/src/opensolve_pipe/models/components.py - Add to
apps/web/src/lib/models/components.ts
- Add to
-
Document in this skill file
- Add to component types section
- Add validation rules if applicable
Example: Simple Single-Path System
{
id: "project-1",
metadata: {...},
settings: {...},
fluid: { id: "water", temperature: 68 },
components: [
{
id: "reservoir-1",
type: "reservoir",
name: "Supply Reservoir",
elevation: 0,
waterLevel: 100,
downstreamConnections: [
{
targetComponentId: "pump-1",
piping: {
pipe: {
material: "carbon_steel",
nominalDiameter: 4,
schedule: "40",
length: 20
},
fittings: [
{ id: "entrance_rounded", name: "Pipe Entrance", quantity: 1 }
]
}
}
]
},
{
id: "pump-1",
type: "pump",
name: "Main Pump",
elevation: 0,
curve: {...},
speed: 1.0,
status: "on",
upstreamPiping: null, // Connected via reservoir's downstream
downstreamConnections: [
{
targetComponentId: "tank-1",
piping: {
pipe: {
material: "carbon_steel",
nominalDiameter: 4,
schedule: "40",
length: 100
},
fittings: [
{ id: "elbow_90_lr", name: "90° Elbow", quantity: 3 },
{ id: "gate_valve", name: "Gate Valve", quantity: 1 }
]
}
}
]
},
{
id: "tank-1",
type: "tank",
name: "Elevated Tank",
elevation: 50,
diameter: 10,
initialLevel: 10,
minLevel: 2,
maxLevel: 12,
upstreamPiping: null, // Connected via pump's downstream
downstreamConnections: []
}
]
}
Common Patterns
Parallel Pumps
{
id: "junction-1",
type: "junction",
name: "Pump Suction Header",
downstreamConnections: [
{ targetComponentId: "pump-1", piping: {...} },
{ targetComponentId: "pump-2", piping: {...} }
]
},
// Both pumps discharge to junction-2
Series Pumps
// pump-1 → piping → pump-2 → piping → tank
Bypass Loop
{
id: "junction-1",
downstreamConnections: [
{ targetComponentId: "hx-1", piping: {...} }, // Main path
{ targetComponentId: "valve-bypass", piping: {...} } // Bypass path
]
}
// Both paths rejoin at junction-2
Best Practices
-
Keep component chains simple for MVP
- Start with single-path systems
- Add branching in Phase 2
-
Use descriptive names
- IDs are programmatic (
pump-1) - Names are user-facing (
"Primary Circulation Pump")
- IDs are programmatic (
-
Store piping with downstream connection
- Piping belongs to the connection, not the component
- Makes chain traversal cleaner
-
Validate early
- Check component chain validity before solving
- Provide clear error messages
-
Preserve user intent
- Don't auto-modify user's component chain
- Warn about issues, don't silently fix
-
Handle edge cases
- Zero-length pipes (K-factors only)
- Closed valves (infinite K or disconnect)
- Empty tanks (warning, don't crash)
使用示例
查看来源仓库中的使用示例与配置说明。
查看来源 ↗来源历史
- 收录时间
- 2026-01-20
- 索引更新时间
- 2026-01-26
- Branch
- main
收录与同步日期属于本站记录。源码修改历史请查看来源仓库。
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!