Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ WPF network simulator for modelling multi-traffic movement across producer, cons
## What It Does

- Loads a JSON network file.
- Lets users create a new network and edit traffic types, nodes, node roles, and edges directly in the app.
- Draws the network on a draggable canvas.
- Auto-positions nodes when `x` and `y` are omitted from the input file.
- Includes an `Auto Arrange` action to regenerate node positions for the whole network.
Expand All @@ -18,6 +19,20 @@ WPF network simulator for modelling multi-traffic movement across producer, cons
- Simulates routed movements from producers to consumers through valid transhipment nodes.
- Saves the current network, including updated node positions, back to JSON.

## Editing In App

- Use `New Network` to start from an empty model.
- Maintain traffic types in the `Network Editor` tab, including routing preference and optional `capacityBidPerUnit`.
- Add and remove nodes in the main editor grid.
- Open `Open Node Editor...` to edit one node in a dedicated window.
- In the node editor, choose the node, then choose one of its traffic-role entries, then set:
- `Traffic Type`
- `Role`
- `Production`
- `Consumption`
- Add and remove edges in the `Edges` grid. `From` and `To` are chosen from the existing node list rather than typed freehand.
- Drag nodes on the canvas to refine the layout visually, or use `Auto Arrange` to regenerate positions.

## Run It

```powershell
Expand Down Expand Up @@ -95,3 +110,14 @@ The app uses a simple custom JSON format:
- Omit `capacity` on an edge when you want it to behave as unlimited.
- The consumer-cost view shows local and imported movement costs separately, plus the blended movement cost seen at each consumer node.
- Routing is path-based and allocates producer supply to consumer demand using the best available routes under the chosen traffic preference and capacity bidding.
- `Auto Arrange` only updates node positions. It does not throw away in-memory edits to nodes, roles, or traffic types.

## Code Structure

- [MainWindow.xaml](/C:/Users/jdwil/source/repos/Codex/MedWNetworkSim/src/MedWNetworkSim.App/MainWindow.xaml) defines the main shell: canvas, summary panes, simulation results, and the in-app editor grids.
- [MainWindowViewModel.cs](/C:/Users/jdwil/source/repos/Codex/MedWNetworkSim/src/MedWNetworkSim.App/ViewModels/MainWindowViewModel.cs) is the application coordinator. It loads/saves networks, keeps editor selections in sync, and triggers simulation.
- [NodeEditorWindow.xaml](/C:/Users/jdwil/source/repos/Codex/MedWNetworkSim/src/MedWNetworkSim.App/NodeEditorWindow.xaml) provides the dedicated dropdown-driven node editing workflow.
- [NetworkFileService.cs](/C:/Users/jdwil/source/repos/Codex/MedWNetworkSim/src/MedWNetworkSim.App/Services/NetworkFileService.cs) normalizes and validates JSON data and applies automatic layout.
- [NetworkSimulationEngine.cs](/C:/Users/jdwil/source/repos/Codex/MedWNetworkSim/src/MedWNetworkSim.App/Services/NetworkSimulationEngine.cs) performs routing, capacity competition, bid-cost calculation, and consumer-cost summarization.
Comment on lines +117 to +121
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The links in the 'Code Structure' section use absolute file paths specific to your local environment (e.g., /C:/Users/...). These links will not function correctly for other users or within the repository's hosting environment. Please use relative paths starting from the repository root.

Suggested change
- [MainWindow.xaml](/C:/Users/jdwil/source/repos/Codex/MedWNetworkSim/src/MedWNetworkSim.App/MainWindow.xaml) defines the main shell: canvas, summary panes, simulation results, and the in-app editor grids.
- [MainWindowViewModel.cs](/C:/Users/jdwil/source/repos/Codex/MedWNetworkSim/src/MedWNetworkSim.App/ViewModels/MainWindowViewModel.cs) is the application coordinator. It loads/saves networks, keeps editor selections in sync, and triggers simulation.
- [NodeEditorWindow.xaml](/C:/Users/jdwil/source/repos/Codex/MedWNetworkSim/src/MedWNetworkSim.App/NodeEditorWindow.xaml) provides the dedicated dropdown-driven node editing workflow.
- [NetworkFileService.cs](/C:/Users/jdwil/source/repos/Codex/MedWNetworkSim/src/MedWNetworkSim.App/Services/NetworkFileService.cs) normalizes and validates JSON data and applies automatic layout.
- [NetworkSimulationEngine.cs](/C:/Users/jdwil/source/repos/Codex/MedWNetworkSim/src/MedWNetworkSim.App/Services/NetworkSimulationEngine.cs) performs routing, capacity competition, bid-cost calculation, and consumer-cost summarization.
- [MainWindow.xaml](src/MedWNetworkSim.App/MainWindow.xaml) defines the main shell: canvas, summary panes, simulation results, and the in-app editor grids.
- [MainWindowViewModel.cs](src/MedWNetworkSim.App/ViewModels/MainWindowViewModel.cs) is the application coordinator. It loads/saves networks, keeps editor selections in sync, and triggers simulation.
- [NodeEditorWindow.xaml](src/MedWNetworkSim.App/NodeEditorWindow.xaml) provides the dedicated dropdown-driven node editing workflow.
- [NetworkFileService.cs](src/MedWNetworkSim.App/Services/NetworkFileService.cs) normalizes and validates JSON data and applies automatic layout.
- [NetworkSimulationEngine.cs](src/MedWNetworkSim.App/Services/NetworkSimulationEngine.cs) performs routing, capacity competition, bid-cost calculation, and consumer-cost summarization.

- The `Models` folder contains the persisted JSON shape.
- The `ViewModels` folder contains the editable UI state and display helpers used by WPF binding.
1 change: 1 addition & 0 deletions src/MedWNetworkSim.App/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ private void AddNode_Click(object sender, RoutedEventArgs e)

private void EditSelectedNode_Click(object sender, RoutedEventArgs e)
{
// The dedicated window keeps node-role editing simpler than trying to fit every selector into the main pane.
var window = new NodeEditorWindow(ViewModel)
{
Owner = this
Expand Down
24 changes: 24 additions & 0 deletions src/MedWNetworkSim.App/Models/EdgeModel.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,42 @@
namespace MedWNetworkSim.App.Models;

/// <summary>
/// Represents a connection between two nodes, including routing attributes and optional capacity.
/// </summary>
public sealed class EdgeModel
{
/// <summary>
/// Gets or sets the unique identifier for the edge.
/// </summary>
public string Id { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the source node identifier.
/// </summary>
public string FromNodeId { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the destination node identifier.
/// </summary>
public string ToNodeId { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the time cost used when traffic prioritizes speed or total cost.
/// </summary>
public double Time { get; set; }

/// <summary>
/// Gets or sets the monetary or general routing cost used when traffic prioritizes cost or total cost.
/// </summary>
public double Cost { get; set; }

/// <summary>
/// Gets or sets the optional shared capacity of the edge. Null means unlimited capacity.
/// </summary>
public double? Capacity { get; set; }

/// <summary>
/// Gets or sets a value indicating whether traffic can travel in both directions on this edge.
/// </summary>
public bool IsBidirectional { get; set; } = true;
}
18 changes: 18 additions & 0 deletions src/MedWNetworkSim.App/Models/NetworkModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,33 @@

namespace MedWNetworkSim.App.Models;

/// <summary>
/// Represents a complete persisted network, including traffic-type definitions, nodes, and edges.
/// </summary>
public sealed class NetworkModel
{
/// <summary>
/// Gets or sets the display name of the network.
/// </summary>
public string Name { get; set; } = "Untitled Network";

/// <summary>
/// Gets or sets an optional free-text description shown in the editor.
/// </summary>
public string Description { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the declared traffic types that can move through the network.
/// </summary>
public List<TrafficTypeDefinition> TrafficTypes { get; set; } = [];

/// <summary>
/// Gets or sets the nodes that can produce, consume, or transship traffic.
/// </summary>
public List<NodeModel> Nodes { get; set; } = [];

/// <summary>
/// Gets or sets the edges that connect nodes and define time, cost, and optional capacity.
/// </summary>
public List<EdgeModel> Edges { get; set; } = [];
}
18 changes: 18 additions & 0 deletions src/MedWNetworkSim.App/Models/NodeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,33 @@

namespace MedWNetworkSim.App.Models;

/// <summary>
/// Represents a node in the network graph.
/// </summary>
public sealed class NodeModel
{
/// <summary>
/// Gets or sets the unique identifier used by edges to reference this node.
/// </summary>
public string Id { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the user-facing name shown on the canvas and in editors.
/// </summary>
public string Name { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the optional horizontal canvas position of the node center.
/// </summary>
public double? X { get; set; }

/// <summary>
/// Gets or sets the optional vertical canvas position of the node center.
/// </summary>
public double? Y { get; set; }

/// <summary>
/// Gets or sets the per-traffic roles and quantities for this node.
/// </summary>
public List<NodeTrafficProfile> TrafficProfiles { get; set; } = [];
}
15 changes: 15 additions & 0 deletions src/MedWNetworkSim.App/Models/NodeTrafficProfile.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
namespace MedWNetworkSim.App.Models;

/// <summary>
/// Describes how a single node participates in one traffic type.
/// </summary>
public sealed class NodeTrafficProfile
{
/// <summary>
/// Gets or sets the traffic type this profile applies to.
/// </summary>
public string TrafficType { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the amount of this traffic type produced at the node.
/// </summary>
public double Production { get; set; }

/// <summary>
/// Gets or sets the amount of this traffic type consumed at the node.
/// </summary>
public double Consumption { get; set; }

/// <summary>
/// Gets or sets a value indicating whether this node may be used as an intermediate transhipment point.
/// </summary>
public bool CanTransship { get; set; }
}
14 changes: 14 additions & 0 deletions src/MedWNetworkSim.App/Models/RoutingPreference.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
namespace MedWNetworkSim.App.Models;

/// <summary>
/// Describes how a traffic type scores alternative routes.
/// </summary>
public enum RoutingPreference
{
/// <summary>
/// Prefer routes with the lowest total edge time.
/// </summary>
Speed,

/// <summary>
/// Prefer routes with the lowest total edge cost.
/// </summary>
Cost,

/// <summary>
/// Prefer routes with the lowest combined time plus cost score.
/// </summary>
TotalCost
}
15 changes: 15 additions & 0 deletions src/MedWNetworkSim.App/Models/TrafficTypeDefinition.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
namespace MedWNetworkSim.App.Models;

/// <summary>
/// Defines how one traffic type behaves when the simulator routes it through the network.
/// </summary>
public sealed class TrafficTypeDefinition
{
/// <summary>
/// Gets or sets the name of the traffic type.
/// </summary>
public string Name { get; set; } = string.Empty;

/// <summary>
/// Gets or sets an optional description shown in the editor.
/// </summary>
public string Description { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the route-scoring preference for this traffic type.
/// </summary>
public RoutingPreference RoutingPreference { get; set; } = RoutingPreference.TotalCost;

/// <summary>
/// Gets or sets the optional per-unit bid used when competing for constrained edge capacity.
/// </summary>
public double? CapacityBidPerUnit { get; set; }
}
1 change: 1 addition & 0 deletions src/MedWNetworkSim.App/NodeEditorWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public NodeEditorWindow(MainWindowViewModel viewModel)
{
InitializeComponent();
ViewModel = viewModel;
// The window edits the same shared view model as the main screen, so changes are live immediately.
DataContext = ViewModel;
}

Expand Down
30 changes: 30 additions & 0 deletions src/MedWNetworkSim.App/Services/ConsumerCostSummary.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,52 @@
namespace MedWNetworkSim.App.Services;

/// <summary>
/// Summarizes the delivered movement cost seen by a consumer node for one traffic type.
/// </summary>
public sealed class ConsumerCostSummary
{
/// <summary>
/// Gets the traffic type summarized by this row.
/// </summary>
public string TrafficType { get; init; } = string.Empty;

/// <summary>
/// Gets the consumer node identifier.
/// </summary>
public string ConsumerNodeId { get; init; } = string.Empty;

/// <summary>
/// Gets the consumer node name.
/// </summary>
public string ConsumerName { get; init; } = string.Empty;

/// <summary>
/// Gets the quantity satisfied by same-node local production.
/// </summary>
public double LocalQuantity { get; init; }

/// <summary>
/// Gets the average movement cost per unit for locally satisfied demand.
/// </summary>
public double LocalUnitCost { get; init; }

/// <summary>
/// Gets the quantity satisfied by imported flow from other nodes.
/// </summary>
public double ImportedQuantity { get; init; }

/// <summary>
/// Gets the average movement cost per unit for imported flow.
/// </summary>
public double ImportedUnitCost { get; init; }

/// <summary>
/// Gets the average movement cost per unit across local and imported supply together.
/// </summary>
public double BlendedUnitCost { get; init; }

/// <summary>
/// Gets the total movement cost accumulated by all delivered supply in this summary row.
/// </summary>
public double TotalMovementCost { get; init; }
}
Loading
Loading