Class LoopedPipeNetwork

All Implemented Interfaces:
Serializable, Runnable, ProcessEquipmentInterface, SimulationInterface, NamedInterface

public class LoopedPipeNetwork extends ProcessEquipmentBaseClass
Pipeline network supporting looped topologies with Hardy Cross solver.

This class extends the basic pipeline network concept to support looped configurations commonly found in water distribution systems, oil and gas gathering networks, and gas transmission systems. The Hardy Cross method is used to iteratively solve for flow distribution in networks with loops.

Hardy Cross Method

The Hardy Cross method is an iterative technique for solving networks with loops:

  1. Initial flow estimates are made for each pipe
  2. Independent loops are identified using DFS spanning tree algorithm
  3. For each loop, calculate head loss imbalance: ΔH = ∑(h·sign)
  4. Calculate flow correction: ΔQ = -ΔH / ∑(|dh/dQ|)
  5. Apply corrections to all pipes in each loop
  6. Repeat until convergence (ΔH < tolerance for all loops)

Network Topology

The network supports:

  • Multiple source nodes (wells, compressor stations)
  • Multiple sink nodes (customers, export terminals)
  • Junction nodes where pipes connect
  • Looped configurations for redundancy

Example Usage


// Create a simple ring main network
SystemInterface gas = new SystemSrkEos(298.15, 50.0);
gas.addComponent("methane", 0.9);
gas.addComponent("ethane", 0.1);
gas.setMixingRule("classic");

LoopedPipeNetwork network = new LoopedPipeNetwork("ring main");
network.setFluidTemplate(gas);

// Add nodes
network.addSourceNode("supply", 50.0, 1000.0); // 50 bar, 1000 kg/hr
network.addJunctionNode("A");
network.addJunctionNode("B");
network.addJunctionNode("C");
network.addSinkNode("customer1", 100.0); // 100 kg/hr demand
network.addSinkNode("customer2", 200.0);

// Connect with pipes (creates loops)
network.addPipe("supply", "A", "pipe1", 1000.0, 0.3);
network.addPipe("A", "B", "pipe2", 500.0, 0.2);
network.addPipe("B", "C", "pipe3", 500.0, 0.2);
network.addPipe("C", "A", "pipe4", 500.0, 0.2); // Creates a loop
network.addPipe("B", "customer1", "pipe5", 200.0, 0.15);
network.addPipe("C", "customer2", "pipe6", 200.0, 0.15);

// Solve using Hardy Cross
network.setSolverType(SolverType.HARDY_CROSS);
network.setTolerance(1e-6);
network.run();

// Get results
System.out.println("Converged in " + network.getIterationCount() + " iterations");
for (String pipeName : network.getPipeNames()) {
  System.out.println(pipeName + ": " + network.getPipeFlowRate(pipeName) + " kg/hr");
}

Version:
1.0
Author:
Even Solbraa
See Also:
  • Field Details

  • Constructor Details

    • LoopedPipeNetwork

      public LoopedPipeNetwork(String name)
      Create a new looped pipe network.
      Parameters:
      name - network name
  • Method Details

    • setFluidTemplate

      public void setFluidTemplate(SystemInterface fluid)
      Set the fluid template for the network.
      Parameters:
      fluid - the fluid system to use as template
    • getFluidTemplate

      public SystemInterface getFluidTemplate()
      Get the fluid template.
      Returns:
      the fluid template
    • addSourceNode

      public void addSourceNode(String name, double pressureBar, double flowRateKgHr)
      Add a source node to the network.
      Parameters:
      name - node name
      pressureBar - fixed pressure in bara
      flowRateKgHr - supply flow rate in kg/hr (optional, for validation)
    • addSinkNode

      public void addSinkNode(String name, double demandKgHr)
      Add a sink node (demand point) to the network.
      Parameters:
      name - node name
      demandKgHr - demand flow rate in kg/hr
    • addJunctionNode

      public void addJunctionNode(String name)
      Add a junction node to the network.
      Parameters:
      name - node name
    • addPipe

      public LoopedPipeNetwork.NetworkPipe addPipe(String fromNode, String toNode, String pipeName, double lengthM, double diameterM)
      Add a pipe connecting two nodes.
      Parameters:
      fromNode - source node name
      toNode - target node name
      pipeName - pipe name
      lengthM - pipe length in meters
      diameterM - pipe inner diameter in meters
      Returns:
      the created pipe
    • setSolverType

      public void setSolverType(LoopedPipeNetwork.SolverType type)
      Set the solver type.
      Parameters:
      type - solver type
    • getSolverType

      public LoopedPipeNetwork.SolverType getSolverType()
      Get the solver type.
      Returns:
      solver type
    • setTolerance

      public void setTolerance(double tol)
      Set convergence tolerance for head loss balance (Pa).
      Parameters:
      tol - tolerance in Pa
    • getTolerance

      public double getTolerance()
      Get convergence tolerance.
      Returns:
      tolerance in Pa
    • setMaxIterations

      public void setMaxIterations(int max)
      Set maximum number of iterations.
      Parameters:
      max - maximum iterations
    • getMaxIterations

      public int getMaxIterations()
      Get maximum iterations.
      Returns:
      max iterations
    • setRelaxationFactor

      public void setRelaxationFactor(double factor)
      Set relaxation factor for Hardy Cross (0 < factor <= 1).
      Parameters:
      factor - relaxation factor
    • getRelaxationFactor

      public double getRelaxationFactor()
      Get relaxation factor.
      Returns:
      relaxation factor
    • getIterationCount

      public int getIterationCount()
      Get number of iterations in last solve.
      Returns:
      iteration count
    • getMaxResidual

      public double getMaxResidual()
      Get maximum residual from last iteration.
      Returns:
      max residual in Pa
    • isConverged

      public boolean isConverged()
      Check if solution converged.
      Returns:
      true if converged
    • getLoops

      public List<NetworkLoop> getLoops()
      Get detected loops in the network.
      Returns:
      list of loops
    • getNumberOfLoops

      public int getNumberOfLoops()
      Get number of loops in the network.
      Returns:
      number of loops
    • getPipeNames

      public List<String> getPipeNames()
      Get all pipe names.
      Returns:
      list of pipe names
    • getPipeFlowRate

      public double getPipeFlowRate(String pipeName)
      Get flow rate for a specific pipe in kg/hr.
      Parameters:
      pipeName - pipe name
      Returns:
      flow rate in kg/hr
    • getNodePressure

      public double getNodePressure(String nodeName)
      Get pressure at a node in bara.
      Parameters:
      nodeName - node name
      Returns:
      pressure in bara
    • initializeFlowEstimates

      private void initializeFlowEstimates()
      Initialize pipe flow estimates using topological analysis.
    • getTotalConductance

      private double getTotalConductance()
      Get total conductance of all pipes.
      Returns:
      total conductance
    • calculateHeadLoss

      private double calculateHeadLoss(LoopedPipeNetwork.NetworkPipe pipe, SystemInterface fluid)
      Calculate head loss for a pipe using Darcy-Weisbach equation.
      Parameters:
      pipe - the pipe
      fluid - fluid properties
      Returns:
      head loss in Pa
    • calculateHeadLossDerivative

      private double calculateHeadLossDerivative(LoopedPipeNetwork.NetworkPipe pipe, SystemInterface fluid)
      Calculate derivative of head loss with respect to flow rate.
      Parameters:
      pipe - the pipe
      fluid - fluid properties
      Returns:
      dh/dQ in Pa/(kg/s)
    • detectLoops

      private void detectLoops()
      Detect loops in the network using DFS spanning tree algorithm.
    • runHardyCross

      private void runHardyCross(UUID id)
      Run Hardy Cross iterative solver.
      Parameters:
      id - calculation identifier
    • runSequential

      private void runSequential(UUID id)
      Run sequential solver for tree networks.
      Parameters:
      id - calculation identifier
    • initializePipeModels

      private void initializePipeModels()
      Initialize AdiabaticPipe models for each pipe.
    • updateNodePressures

      private void updateNodePressures(SystemInterface fluid)
      Update node pressures based on calculated head losses.
      Parameters:
      fluid - fluid for calculations
    • propagatePressure

      private void propagatePressure(String nodeName, SystemInterface fluid)
      Propagate pressure from a node to connected nodes.
      Parameters:
      nodeName - starting node name
      fluid - fluid for calculations
    • run

      public void run(UUID id)
      Description copied from interface: SimulationInterface

      In this method all thermodynamic and unit operations will be calculated in a steady state calculation.

      Parameters:
      id - UUID
    • getSolutionSummary

      public Map<String,Object> getSolutionSummary()
      Get a summary of the network solution.
      Returns:
      summary map
    • toJson

      public String toJson()
      Description copied from class: ProcessEquipmentBaseClass

      Serializes the Process Equipment along with its state to a JSON string.

      Specified by:
      toJson in interface ProcessEquipmentInterface
      Overrides:
      toJson in class ProcessEquipmentBaseClass
      Returns:
      json string.