330 lines
7.4 KiB
TypeScript
330 lines
7.4 KiB
TypeScript
/**
|
|
* Sample flow networks for demonstration
|
|
*/
|
|
|
|
import type { FlowNetwork, FlowNode } from './types'
|
|
import { updateFlowNodeProperties, calculateFlowNetworkTotals } from './utils'
|
|
|
|
/**
|
|
* Create a simple linear flow: A → B → C
|
|
* Flow enters A, passes through to C
|
|
*/
|
|
export function createLinearFlowNetwork(): FlowNetwork {
|
|
const nodes: FlowNode[] = [
|
|
{
|
|
id: 'alice',
|
|
name: 'Alice',
|
|
x: 100,
|
|
y: 200,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 10,
|
|
maxAbsorption: 50,
|
|
inflow: 100, // Start with 100 flow
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'healthy',
|
|
externalFlow: 100,
|
|
isOverflowSink: false,
|
|
},
|
|
{
|
|
id: 'bob',
|
|
name: 'Bob',
|
|
x: 300,
|
|
y: 200,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 10,
|
|
maxAbsorption: 30,
|
|
inflow: 0,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'starved',
|
|
externalFlow: 0,
|
|
isOverflowSink: false,
|
|
},
|
|
{
|
|
id: 'carol',
|
|
name: 'Carol',
|
|
x: 500,
|
|
y: 200,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 10,
|
|
maxAbsorption: 40,
|
|
inflow: 0,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'starved',
|
|
externalFlow: 0,
|
|
isOverflowSink: false,
|
|
},
|
|
]
|
|
|
|
const allocations = [
|
|
{ id: 'alloc_1', sourceNodeId: 'alice', targetNodeId: 'bob', percentage: 1.0 },
|
|
{ id: 'alloc_2', sourceNodeId: 'bob', targetNodeId: 'carol', percentage: 1.0 },
|
|
]
|
|
|
|
return calculateFlowNetworkTotals({
|
|
name: 'Linear Flow (A → B → C)',
|
|
nodes: nodes.map(updateFlowNodeProperties),
|
|
allocations,
|
|
totalInflow: 0,
|
|
totalAbsorbed: 0,
|
|
totalOutflow: 0,
|
|
overflowNodeId: null,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Create a split flow: A → B and C
|
|
* Flow enters A, splits between B and C
|
|
*/
|
|
export function createSplitFlowNetwork(): FlowNetwork {
|
|
const nodes: FlowNode[] = [
|
|
{
|
|
id: 'source',
|
|
name: 'Source',
|
|
x: 100,
|
|
y: 200,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 5,
|
|
maxAbsorption: 20,
|
|
inflow: 100,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'healthy',
|
|
externalFlow: 100,
|
|
isOverflowSink: false,
|
|
},
|
|
{
|
|
id: 'project_a',
|
|
name: 'Project A',
|
|
x: 300,
|
|
y: 100,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 15,
|
|
maxAbsorption: 40,
|
|
inflow: 0,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'starved',
|
|
externalFlow: 0,
|
|
isOverflowSink: false,
|
|
},
|
|
{
|
|
id: 'project_b',
|
|
name: 'Project B',
|
|
x: 300,
|
|
y: 300,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 15,
|
|
maxAbsorption: 40,
|
|
inflow: 0,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'starved',
|
|
externalFlow: 0,
|
|
isOverflowSink: false,
|
|
},
|
|
{
|
|
id: 'commons',
|
|
name: 'Commons',
|
|
x: 500,
|
|
y: 200,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 10,
|
|
maxAbsorption: 30,
|
|
inflow: 0,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'starved',
|
|
externalFlow: 0,
|
|
isOverflowSink: false,
|
|
},
|
|
]
|
|
|
|
const allocations = [
|
|
{ id: 'alloc_1', sourceNodeId: 'source', targetNodeId: 'project_a', percentage: 0.6 },
|
|
{ id: 'alloc_2', sourceNodeId: 'source', targetNodeId: 'project_b', percentage: 0.4 },
|
|
{ id: 'alloc_3', sourceNodeId: 'project_a', targetNodeId: 'commons', percentage: 1.0 },
|
|
{ id: 'alloc_4', sourceNodeId: 'project_b', targetNodeId: 'commons', percentage: 1.0 },
|
|
]
|
|
|
|
return calculateFlowNetworkTotals({
|
|
name: 'Split Flow (Source → Projects → Commons)',
|
|
nodes: nodes.map(updateFlowNodeProperties),
|
|
allocations,
|
|
totalInflow: 0,
|
|
totalAbsorbed: 0,
|
|
totalOutflow: 0,
|
|
overflowNodeId: null,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Create a circular flow: A → B → C → A
|
|
* Flow circulates through the network
|
|
*/
|
|
export function createCircularFlowNetwork(): FlowNetwork {
|
|
const centerX = 350
|
|
const centerY = 250
|
|
const radius = 150
|
|
|
|
const nodes: FlowNode[] = [
|
|
{
|
|
id: 'alice',
|
|
name: 'Alice',
|
|
x: centerX + radius * Math.cos(0) - 60,
|
|
y: centerY + radius * Math.sin(0) - 50,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 10,
|
|
maxAbsorption: 30,
|
|
inflow: 50,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'healthy',
|
|
externalFlow: 50,
|
|
isOverflowSink: false,
|
|
},
|
|
{
|
|
id: 'bob',
|
|
name: 'Bob',
|
|
x: centerX + radius * Math.cos((2 * Math.PI) / 3) - 60,
|
|
y: centerY + radius * Math.sin((2 * Math.PI) / 3) - 50,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 10,
|
|
maxAbsorption: 30,
|
|
inflow: 0,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'starved',
|
|
externalFlow: 0,
|
|
isOverflowSink: false,
|
|
},
|
|
{
|
|
id: 'carol',
|
|
name: 'Carol',
|
|
x: centerX + radius * Math.cos((4 * Math.PI) / 3) - 60,
|
|
y: centerY + radius * Math.sin((4 * Math.PI) / 3) - 50,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 10,
|
|
maxAbsorption: 30,
|
|
inflow: 0,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'starved',
|
|
externalFlow: 0,
|
|
isOverflowSink: false,
|
|
},
|
|
]
|
|
|
|
const allocations = [
|
|
{ id: 'alloc_1', sourceNodeId: 'alice', targetNodeId: 'bob', percentage: 1.0 },
|
|
{ id: 'alloc_2', sourceNodeId: 'bob', targetNodeId: 'carol', percentage: 1.0 },
|
|
{ id: 'alloc_3', sourceNodeId: 'carol', targetNodeId: 'alice', percentage: 1.0 },
|
|
]
|
|
|
|
return calculateFlowNetworkTotals({
|
|
name: 'Circular Flow (A → B → C → A)',
|
|
nodes: nodes.map(updateFlowNodeProperties),
|
|
allocations,
|
|
totalInflow: 0,
|
|
totalAbsorbed: 0,
|
|
totalOutflow: 0,
|
|
overflowNodeId: null,
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Create an empty network for user to build
|
|
*/
|
|
export function createEmptyFlowNetwork(): FlowNetwork {
|
|
const nodes: FlowNode[] = [
|
|
{
|
|
id: 'node1',
|
|
name: 'Node 1',
|
|
x: 150,
|
|
y: 150,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 10,
|
|
maxAbsorption: 50,
|
|
inflow: 0,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'starved',
|
|
externalFlow: 0,
|
|
isOverflowSink: false,
|
|
},
|
|
{
|
|
id: 'node2',
|
|
name: 'Node 2',
|
|
x: 350,
|
|
y: 150,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 10,
|
|
maxAbsorption: 50,
|
|
inflow: 0,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'starved',
|
|
externalFlow: 0,
|
|
isOverflowSink: false,
|
|
},
|
|
{
|
|
id: 'node3',
|
|
name: 'Node 3',
|
|
x: 250,
|
|
y: 300,
|
|
width: 120,
|
|
height: 100,
|
|
minAbsorption: 10,
|
|
maxAbsorption: 50,
|
|
inflow: 0,
|
|
absorbed: 0,
|
|
outflow: 0,
|
|
status: 'starved',
|
|
externalFlow: 0,
|
|
isOverflowSink: false,
|
|
},
|
|
]
|
|
|
|
return calculateFlowNetworkTotals({
|
|
name: 'Empty Network (Set flows to begin)',
|
|
nodes: nodes.map(updateFlowNodeProperties),
|
|
allocations: [],
|
|
totalInflow: 0,
|
|
totalAbsorbed: 0,
|
|
totalOutflow: 0,
|
|
overflowNodeId: null,
|
|
})
|
|
}
|
|
|
|
export const flowSampleNetworks = {
|
|
linear: createLinearFlowNetwork(),
|
|
split: createSplitFlowNetwork(),
|
|
circular: createCircularFlowNetwork(),
|
|
empty: createEmptyFlowNetwork(),
|
|
}
|
|
|
|
export const flowNetworkOptions = [
|
|
{ value: 'linear', label: 'Linear Flow (A → B → C)' },
|
|
{ value: 'split', label: 'Split Flow (Projects + Commons)' },
|
|
{ value: 'circular', label: 'Circular Flow (A ↔ B ↔ C)' },
|
|
{ value: 'empty', label: 'Empty Network' },
|
|
]
|
|
|
|
export function getFlowSampleNetwork(key: keyof typeof flowSampleNetworks): FlowNetwork {
|
|
return flowSampleNetworks[key]
|
|
}
|