Adding initial Project to git

This commit is contained in:
2025-12-29 19:58:26 +00:00
parent 15f9dce88c
commit b54c9bbb1c
24 changed files with 1396 additions and 0 deletions

View File

@@ -0,0 +1,154 @@
namespace MyBWRSimulator.Core.Components.Abstract
{
using MyBWRSimulator.Core.Interfaces;
using MyBWRSimulator.Core.Ports;
using System.Collections.Generic;
using System.Linq; // Needed for .ToList()
/// <summary>
/// Abstract base class for all simulated physical components.
/// Implements ISimulatable, IFluidConnectable, and IThermalConnectable.
/// </summary>
public abstract class Component : ISimulatable, IFluidConnectable, IThermalConnectable
{
/// <summary>
/// Unique identifier for the component.
/// </summary>
public string ID { get; protected set; }
/// <summary>
/// Human-readable name of the component.
/// </summary>
public string Name { get; protected set; }
/// <summary>
/// Detailed description of the component.
/// </summary>
public string Description { get; protected set; }
/// <summary>
/// An integer value indicating the order in which components should be updated.
/// Lower numbers mean higher priority (updated first).
/// </summary>
public int UpdatePriority { get; protected set; }
/// <summary>
/// Indicates if the component is receiving sufficient Thermal power.
/// </summary>
public bool IsPowered { get; protected set; }
/// <summary>
/// Collection of fluid ports belonging to this component, accessible by their ID.
/// </summary>
protected Dictionary<string, FluidPort> FluidPorts { get; set; } = new Dictionary<string, FluidPort>();
/// <summary>
/// Collection of Thermal ports belonging to this component, accessible by their ID.
/// </summary>
protected Dictionary<string, ThermalPort> ThermalPorts { get; set; } = new Dictionary<string, ThermalPort>();
/// <summary>
/// Constructor for the Component base class.
/// </summary>
/// <param name="id">Unique identifier.</param>
/// <param name="name">Human-readable name.</param>
/// <param name="description">Description of the component.</param>
/// <param name="updatePriority">Priority for simulation updates.</param>
protected Component(string id, string name, string description, int updatePriority)
{
ID = id;
Name = name;
Description = description;
UpdatePriority = updatePriority;
}
/// <summary>
/// Initializes the component. Called once when the simulation starts or component is added.
/// </summary>
public virtual void Initialize()
{
Console.WriteLine($"Initializing {Name} ({ID})...");
// Placeholder for component-specific initialization logic
}
/// <summary>
/// Shuts down the component. Called once when the simulation ends or component is removed.
/// </summary>
public virtual void Shutdown()
{
Console.WriteLine($"Shutting down {Name} ({ID})...");
// Placeholder for component-specific cleanup logic
}
/// <summary>
/// Abstract method to update the component's state over a time step.
/// Must be implemented by concrete component classes.
/// </summary>
/// <param name="deltaTime">The time elapsed.</param>
public abstract void Update(double deltaTime);
/// <summary>
/// Returns a list of all fluid ports for this component.
/// </summary>
/// <returns>A list of FluidPort objects.</returns>
public List<FluidPort> GetFluidPorts() => FluidPorts.Values.ToList();
/// <summary>
/// Gets a fluid port by its unique ID.
/// </summary>
/// <param name="id">The ID of the fluid port.</param>
/// <returns>The FluidPort object if found, otherwise null.</returns>
public FluidPort GetFluidPortById(string id)
{
FluidPorts.TryGetValue(id, out FluidPort port);
return port;
}
/// <summary>
/// Returns a list of all Thermal ports for this component.
/// </summary>
/// <returns>A list of Thermal objects.</returns>
public List<ThermalPort> GetThermalPorts() => ThermalPorts.Values.ToList();
/// <summary>
/// Gets an Thermal port by its unique ID.
/// </summary>
/// <param name="id">The ID of the Thermal port.</param>
/// <returns>The ThermalPort object if found, otherwise null.</returns>
public ThermalPort GetThermalPortById(string id)
{
ThermalPorts.TryGetValue(id, out ThermalPort port);
return port;
}
/// <summary>
/// Helper method to add a fluid port to this component.
/// </summary>
/// <param name="port">The FluidPort to add.</param>
/// <exception cref="ArgumentException">Thrown if a port with the same ID already exists.</exception>
protected void AddFluidPort(FluidPort port)
{
if (FluidPorts.ContainsKey(port.ID))
{
throw new ArgumentException($"A fluid port with ID '{port.ID}' already exists on component '{Name}' ({ID}).");
}
port.ParentComponent = this;
FluidPorts.Add(port.ID, port);
}
/// <summary>
/// Helper method to add an Thermal port to this component.
/// </summary>
/// <param name="port">The ThermalPort to add.</param>
/// <exception cref="ArgumentException">Thrown if an Thermal port with the same ID already exists.</exception>
protected void AddThermalPort(ThermalPort port)
{
if (ThermalPorts.ContainsKey(port.ID))
{
throw new ArgumentException($"An Thermal port with ID '{port.ID}' already exists on component '{Name}' ({ID}).");
}
port.ParentComponent = this;
ThermalPorts.Add(port.ID, port);
}
}
}

View File

@@ -0,0 +1,77 @@
// MyBWRSimulator.Core/Components/Abstract/Port.cs
namespace MyBWRSimulator.Core.Components.Abstract
{
/// <summary>
/// Abstract base class for all types of connection points on components.
/// </summary>
public abstract class Port
{
/// <summary>
/// Unique ID for the port (e.g., "Inlet1", "OutletA").
/// </summary>
public string ID { get; protected set; }
/// <summary>
/// A reference to the Port it's connected to. Null if not connected.
/// </summary>
public Port ConnectedPort { get; protected set; }
/// <summary>
/// A reference back to the component this port belongs to.
/// </summary>
public Component ParentComponent { get; internal set; } // Internal set by AddPort methods
/// <summary>
/// Constructor for the Port base class.
/// </summary>
/// <param name="id">Unique identifier for the port.</param>
protected Port(string id)
{
ID = id;
}
/// <summary>
/// Establishes a connection between this port and another port.
/// </summary>
/// <param name="otherPort">The port to connect to.</param>
public virtual void Connect(Port otherPort)
{
if (otherPort == null)
{
Console.WriteLine($"Error: Cannot connect {ID} to null port.");
return;
}
if (ConnectedPort != null && ConnectedPort != otherPort)
{
Console.WriteLine($"Warning: {ID} is already connected to {ConnectedPort.ID}. Disconnecting first.");
Disconnect();
}
ConnectedPort = otherPort;
// For bidirectional connection, the other port should also connect to this one
if (otherPort.ConnectedPort != this)
{
otherPort.Connect(this);
}
Console.WriteLine($"Port {ID} connected to {otherPort.ID}.");
}
/// <summary>
/// Breaks the connection of this port.
/// </summary>
public virtual void Disconnect()
{
if (ConnectedPort != null)
{
Port oldConnectedPort = ConnectedPort;
ConnectedPort = null;
// Ensure the other port also disconnects from this one
if (oldConnectedPort.ConnectedPort == this)
{
oldConnectedPort.Disconnect();
}
Console.WriteLine($"Port {ID} disconnected from {oldConnectedPort.ID}.");
}
}
}
}

View File

@@ -0,0 +1,67 @@
// MyBWRSimulator.Core/Components/Concrete/FluidTank.cs
namespace MyBWRSimulator.Core.Components.Concrete
{
using MyBWRSimulator.Core.Components.Abstract;
//using MyBWRSimulator.Core.Components.Enums;
using MyBWRSimulator.Core.Ports;
using System;
using System.Collections.Generic;
/// <summary>
/// Represents a Fluid Tank component in the BWR simulation.
/// </summary>
public class FluidTank : Component
{
public double MaxVolume { get; private set; } // Maximum capacity of the tank (m^3)
public double CurrentVolume { get; private set; } // Current fluid volume in the tank (m^3)
public double CurrentLevel => CurrentVolume / MaxVolume; // 0.0 to 1.0 (0% to 100%)
public double ContentsTemperature { get; private set; } // Average temperature of fluid in tank
public FluidPort Inlet => GetFluidPortById("Inlet");
public FluidPort Outlet => GetFluidPortById("Outlet");
public FluidTank(string id, string name, double maxVolume, int numInlets, int numOutlets, double initialVolume = 0.0, double initialTemp = 293.15)
: base(id, name, $"A fluid tank with max volume {maxVolume} m^3.", 5) // Priority 5 (updates last)
{
MaxVolume = maxVolume;
CurrentVolume = Math.Clamp(initialVolume, 0.0, MaxVolume);
ContentsTemperature = initialTemp;
AddFluidPort(new FluidPort("Inlet"));
AddFluidPort(new FluidPort("Outlet"));
}
public override void Update(double deltaTime)
{
double FlowVolume = 0.0;
double InletEnergy = 0.0; // For temperature calculation
FlowVolume += Inlet.FlowRate * deltaTime; // FlowRate is volume/time, so FlowRate * deltaTime = volume
InletEnergy += Inlet.FlowRate * Inlet.Temperature * deltaTime; // Simple energy balance
// Sum outgoing flow (assuming outlets draw based on their connected components)
// For a tank, outlets typically "demand" flow, and the tank supplies it if available.
// For simplicity here, we'll assume outlets simply remove fluid.
// In a real system, outlet flow depends on downstream pressure and tank level.
FlowVolume -= Outlet.FlowRate * deltaTime;
// Update volume
double newVolume = CurrentVolume + FlowVolume;
CurrentVolume = Math.Clamp(newVolume, 0.0, MaxVolume);
// Update outlet port properties (e.g., pressure based on level)
// This is a simplification; in reality, outlet pressure also depends on downstream pressure
double pressureFromLevel = CurrentLevel * 100000; // Example: 100kPa at full level
Outlet.Pressure = pressureFromLevel; // Or a more complex calculation
Outlet.Temperature = ContentsTemperature;
// Mirror values to connected ports
Outlet.MirrorToConnectedPort();
Console.WriteLine($"{Name} ({ID}) - Volume: {CurrentVolume:F2} m^3 ({CurrentLevel * 100:F1}%), Temp: {ContentsTemperature:F1} K");
}
}
}

View File

@@ -0,0 +1,74 @@
// MyBWRSimulator.Core/Components/Concrete/Pump.cs
namespace MyBWRSimulator.Core.Components.Concrete
{
using MyBWRSimulator.Core.Components.Abstract;
using MyBWRSimulator.Core.Ports;
using System;
using System.Collections.Generic;
/// <summary>
/// Represents a Pump component in the BWR simulation.
/// </summary>
public class Pump : Component
{
public double PumpSpeed { get; set; } // 0.0 to 1.0 (0% to 100%)
public double MaxFlowRate { get; private set; } // Max flow at 100% speed
public double MaxHeadPressure { get; private set; } // Max pressure at 100% speed
// Publicly expose ports for easier named access if needed, but GetFluidPortById is preferred
public FluidPort Inlet => GetFluidPortById("Inlet");
public FluidPort Outlet => GetFluidPortById("Outlet");
public Pump(string id, string name, double maxFlowRate, double maxHeadPressure)
: base(id, name, $"A pump component with max flow {maxFlowRate} and max head {maxHeadPressure}.", 1) // Priority 1
{
MaxFlowRate = maxFlowRate;
MaxHeadPressure = maxHeadPressure;
PumpSpeed = 0.0; // Initially off
// Use descriptive IDs for ports
AddFluidPort(new FluidPort("Inlet"));
AddFluidPort(new FluidPort("Outlet"));
}
public override void Update(double deltaTime)
{
if (PumpSpeed > 0)
{
// Simple pump model: Flow proportional to speed, pressure based on head
double actualFlowRate = PumpSpeed * MaxFlowRate;
double actualPressureIncrease = PumpSpeed * MaxHeadPressure;
// Read from inlet
double inletPressure = Inlet.Pressure;
double inletTemperature = Inlet.Temperature;
// Calculate outlet properties
Outlet.FlowRate = actualFlowRate;
Outlet.Pressure = inletPressure + actualPressureIncrease;
Outlet.Temperature = inletTemperature; // Assuming no temperature change by pump
// Mirror values to connected ports
Outlet.MirrorToConnectedPort();
Console.WriteLine($"{Name} ({ID}) - Flow: {actualFlowRate:F2} kg/s, Outlet P: {Outlet.Pressure:F2} Pa");
}
else
{
// If not powered or off, no flow
Outlet.FlowRate = 0.0;
Outlet.Pressure = Inlet.Pressure; // Outlet pressure equals inlet if no pumping
Outlet.Temperature = Inlet.Temperature;
Outlet.MirrorToConnectedPort();
Console.WriteLine($"{Name} ({ID}) - Off/No Power.");
}
}
public void SetPumpSpeed(double speed)
{
PumpSpeed = Math.Clamp(speed, 0.0, 1.0);
Console.WriteLine($"{Name} ({ID}) - Pump speed set to {PumpSpeed * 100:F0}%.");
}
}
}

View File

@@ -0,0 +1,25 @@
// MyBWRSimulator.Core/Components/Concrete/Pump.cs
namespace MyBWRSimulator.Core.Components.Concrete
{
using MyBWRSimulator.Core.Components.Abstract;
//using MyBWRSimulator.Core.Components.Enums;
using MyBWRSimulator.Core.Ports;
using System;
using System.Collections.Generic;
/// <summary>
/// Represents a Pump component in the BWR simulation.
/// </summary>
public class ReactorCore : Component
{
public ReactorCore(string id, string name, int priority)
: base(id, name, "Simulates all fuel rods and control rods", priority)
{
AddFluidPort(new FluidPort("FeedwaterInlet"));
}
public override void Update(double dt)
{
}
}
}

View File

@@ -0,0 +1,63 @@
// MyBWRSimulator.Core/Components/Concrete/Pipe.cs
namespace MyBWRSimulator.Core.Components.Concrete
{
using MyBWRSimulator.Core.Components.Abstract;
using MyBWRSimulator.Core.Ports;
using System;
using System.Collections.Generic;
/// <summary>
/// Represents a Pipe component in the BWR simulation.
/// </summary>
public class Pipe : Component
{
public double Length { get; private set; } // Length of the pipe (m)
public double Diameter { get; private set; } // Inner diameter of the pipe (m)
public double Roughness { get; private set; } = 0.000045; // Example roughness for steel (m)
// Publicly expose ports for easier named access if needed
public FluidPort Inlet => GetFluidPortById("Inlet");
public FluidPort Outlet => GetFluidPortById("Outlet");
public Pipe(string id, string name, double length, double diameter)
: base(id, name, $"A pipe of length {length}m and diameter {diameter}m.", 4) // Priority 4
{
Length = length;
Diameter = diameter;
// Use descriptive IDs for ports
AddFluidPort(new FluidPort("Inlet"));
AddFluidPort(new FluidPort("Outlet"));
}
public override void Update(double deltaTime)
{
// Read properties from the inlet port (which should have been updated by upstream component)
double inletFlowRate = Inlet.FlowRate;
double inletPressure = Inlet.Pressure;
double inletTemperature = Inlet.Temperature;
// Simple pressure drop calculation (e.g., Darcy-Weisbach or simpler linear drop)
// This is very simplified. For high fidelity, you'd need fluid properties (density, viscosity).
double pressureDrop = 0.0;
if (inletFlowRate > 0)
{
// A very basic linear pressure drop for demonstration
pressureDrop = (inletFlowRate * Length * 10.0) / (Diameter * Diameter);
}
// Simple heat loss/gain (e.g., based on ambient temperature, not modeled here)
double outletTemperature = inletTemperature; // Assuming no heat loss for now
// Update outlet port properties
Outlet.FlowRate = inletFlowRate;
Outlet.Pressure = inletPressure - pressureDrop;
Outlet.Temperature = outletTemperature;
// Mirror values to connected ports
Outlet.MirrorToConnectedPort();
Console.WriteLine($"{Name} ({ID}) - Flow: {inletFlowRate:F2} kg/s, Pressure Drop: {pressureDrop:F2} Pa");
}
}
}

View File

@@ -0,0 +1,14 @@
// MyBWRSimulator.Core/Components/Enums/FluidPortType.cs
/*
namespace MyBWRSimulator.Core.Components.Enums
{
/// <summary>
/// Represents the type of a fluid port (e.g., inlet or outlet).
/// </summary>
public enum FluidPortType
{
Inlet,
Outlet
}
}
*/

View File

@@ -0,0 +1,167 @@
// MyBWRSimulator.Core/Data/ConfigurationLoader.cs
namespace MyBWRSimulator.Core.Data
{
using MyBWRSimulator.Core.Components.Abstract;
using MyBWRSimulator.Core.Components.Concrete;
using MyBWRSimulator.Core.Ports;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
/// <summary>
/// Helper class for deserializing component and connection configurations.
/// </summary>
public class ComponentConfig
{
public string Type { get; set; }
public string ID { get; set; }
public string Name { get; set; }
public int UpdatePriority { get; set; }
public JsonElement InitialState { get; set; } // Use JsonElement to handle dynamic properties
}
/// <summary>
/// Helper class for deserializing connection configurations.
/// </summary>
public class PortReference
{
public string ComponentID { get; set; }
public string PortID { get; set; }
}
/// <summary>
/// Overall configuration structure.
/// </summary>
public class PlantConfiguration
{
public List<ComponentConfig> Components { get; set; }
public List<ConnectionConfig> Connections { get; set; }
}
/// <summary>
/// Helper class for deserializing connection configurations.
/// </summary>
public class ConnectionConfig
{
public PortReference PortA { get; set; }
public PortReference PortB { get; set; }
}
/// <summary>
/// Handles loading simulation configuration from a JSON file.
/// </summary>
public class ConfigurationLoader
{
/// <summary>
/// Loads components and establishes connections from a JSON configuration file.
/// </summary>
/// <param name="filePath">The path to the JSON configuration file.</param>
/// <param name="components">An output list to populate with instantiated components.</param>
public static void LoadConfiguration(string filePath, out List<Component> components)
{
components = new List<Component>();
if (!File.Exists(filePath))
{
Console.WriteLine($"Error: Configuration file not found at {filePath}");
return;
}
try
{
string jsonString = File.ReadAllText(filePath);
var config = JsonSerializer.Deserialize<PlantConfiguration>(jsonString, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
if (config?.Components == null)
{
Console.WriteLine("Error: No components found in configuration.");
return;
}
// 1. Instantiate Components
foreach (var compConfig in config.Components)
{
Component newComponent = null;
switch (compConfig.Type)
{
case "Pump":
// Example: Deserialize specific properties for Pump
var pumpProps = compConfig.InitialState.Deserialize<Dictionary<string, double>>();
newComponent = new Pump(compConfig.ID, compConfig.Name, pumpProps["MaxFlowRate"], pumpProps["MaxHeadPressure"]);
if (pumpProps.TryGetValue("PumpSpeed", out double pumpSpeed))
{
((Pump)newComponent).SetPumpSpeed(pumpSpeed);
}
break;
case "FluidTank":
// Example: Deserialize specific properties for FluidTank
var tankProps = compConfig.InitialState.Deserialize<Dictionary<string, double>>();
newComponent = new FluidTank(compConfig.ID, compConfig.Name, tankProps["MaxVolume"], (int)tankProps["NumInlets"], (int)tankProps["NumOutlets"], tankProps["InitialVolume"]);
break;
case "Pipe":
var pipeProps = compConfig.InitialState.Deserialize<Dictionary<string, double>>();
newComponent = new Pipe(compConfig.ID, compConfig.Name, pipeProps["Length"], pipeProps["Diameter"]);
break;
case "ReactorCore":
newComponent = new ReactorCore(compConfig.ID, compConfig.Name, compConfig.UpdatePriority);
// ReactorCore might have no specific initial state beyond base properties
break;
// Add more component types here
default:
Console.WriteLine($"Warning: Unknown component type '{compConfig.Type}' for ID '{compConfig.ID}'. Skipping.");
break;
}
if (newComponent != null)
{
components.Add(newComponent);
newComponent.Initialize(); // Initialize after creation
}
}
// 2. Establish Connections
if (config.Connections != null)
{
foreach (var connConfig in config.Connections)
{
var compA = components.FirstOrDefault(c => c.ID == connConfig.PortA.ComponentID);
var compB = components.FirstOrDefault(c => c.ID == connConfig.PortB.ComponentID);
if (compA == null || compB == null)
{
Console.WriteLine($"Warning: Could not find one or both components for connection: {connConfig.PortA.ComponentID}.{connConfig.PortA.PortID} <-> {connConfig.PortB.ComponentID}.{connConfig.PortB.PortID}");
continue;
}
// Use the new GetPortById methods for more robust lookup
Port portA = compA.GetFluidPortById(connConfig.PortA.PortID) as Port ??
compA.GetThermalPortById(connConfig.PortA.PortID) as Port;
Port portB = compB.GetFluidPortById(connConfig.PortB.PortID) as Port ??
compB.GetThermalPortById(connConfig.PortB.PortID) as Port;
if (portA != null && portB != null)
{
portA.Connect(portB);
}
else
{
Console.WriteLine($"Warning: Could not find one or both ports for connection: {connConfig.PortA.ComponentID}.{connConfig.PortA.PortID} <-> {connConfig.PortB.ComponentID}.{connConfig.PortB.PortID}");
}
}
}
}
catch (JsonException ex)
{
Console.WriteLine($"Error parsing JSON configuration: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"An unexpected error occurred during configuration loading: {ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,18 @@
// MyBWRSimulator.Core/Interfaces/IFluidConnectable.cs
namespace MyBWRSimulator.Core.Interfaces
{
using MyBWRSimulator.Core.Ports;
using System.Collections.Generic;
/// <summary>
/// Defines the contract for components that have fluid connections.
/// </summary>
public interface IFluidConnectable
{
/// <summary>
/// Gets a list of fluid ports associated with this component.
/// </summary>
/// <returns>A list of FluidPort objects.</returns>
List<FluidPort> GetFluidPorts();
}
}

View File

@@ -0,0 +1,15 @@
// MyBWRSimulator.Core/Interfaces/ISimulatable.cs
namespace MyBWRSimulator.Core.Interfaces
{
/// <summary>
/// Defines the contract for any object that can participate in the simulation's time-stepping.
/// </summary>
public interface ISimulatable
{
/// <summary>
/// Updates the state of the object over a given time step.
/// </summary>
/// <param name="deltaTime">The time elapsed since the last update.</param>
void Update(double deltaTime);
}
}

View File

@@ -0,0 +1,18 @@
// MyBWRSimulator.Core/Interfaces/IThermalConnectable.cs
namespace MyBWRSimulator.Core.Interfaces
{
using MyBWRSimulator.Core.Ports;
using System.Collections.Generic;
/// <summary>
/// Defines the contract for components that have Thermal connections.
/// </summary>
public interface IThermalConnectable
{
/// <summary>
/// Gets a list of Thermal ports associated with this component.
/// </summary>
/// <returns>A list of ThermalPort objects.</returns>
List<ThermalPort> GetThermalPorts();
}
}

View File

@@ -0,0 +1,71 @@
// MyBWRSimulator.Core/Ports/FluidPort.cs
namespace MyBWRSimulator.Core.Ports
{
//using MyBWRSimulator.Core.Components.Enums;
using MyBWRSimulator.Core.Components.Abstract;
/// <summary>
/// Represents a fluid connection point on a component.
/// </summary>
public class FluidPort : Port
{
/// <summary>
/// Current fluid flow rate through this port (e.g., kg/s).
/// </summary>
public double FlowRate { get; set; }
/// <summary>
/// Current fluid pressure at this port (e.g., Pa).
/// </summary>
public double Pressure { get; set; }
/// <summary>
/// Current fluid temperature at this port (e.g., K or C).
/// </summary>
public double Temperature { get; set; }
/// <summary>
/// Current volume of fluid within the port itself (optional, for more detailed modeling).
/// </summary>
public double CurrentVolume { get; set; }
/// <summary>
/// Constructor for a FluidPort.
/// </summary>
/// <param name="id">Unique identifier for the port.</param>
/// <param name="type">The type of fluid port (Inlet or Outlet).</param>
public FluidPort(string id) : base(id)
{
FlowRate = 0.0;
Pressure = 0.0;
Temperature = 0.0;
CurrentVolume = 0.0;
}
/// <summary>
/// Connects this fluid port to another fluid port.
/// Includes basic type checking.
/// </summary>
/// <param name="otherPort">The port to connect to.</param>
public override void Connect(Port otherPort)
{
base.Connect(otherPort);
}
/// <summary>
/// Mirrors fluid properties from this port to its connected port.
/// This is for the direct property assignment data flow model.
/// </summary>
public void MirrorToConnectedPort()
{
if (ConnectedPort is FluidPort connectedFluidPort)
{
connectedFluidPort.FlowRate = this.FlowRate;
connectedFluidPort.Pressure = this.Pressure;
connectedFluidPort.Temperature = this.Temperature;
// Optionally, mirror CurrentVolume if applicable
// connectedFluidPort.CurrentVolume = this.CurrentVolume;
}
}
}
}

View File

@@ -0,0 +1,68 @@
// MyBWRSimulator.Core/Ports/ThermalPort.cs
namespace MyBWRSimulator.Core.Ports
{
using MyBWRSimulator.Core.Components.Abstract;
/// <summary>
/// Represents an Thermal connection point on a component.
/// </summary>
public class ThermalPort : Port
{
/// <summary>
/// Current voltage at this port (e.g., Volts).
/// </summary>
public double Voltage { get; set; }
/// <summary>
/// Current amperage at this port (e.g., Amperes).
/// </summary>
public double Amperage { get; set; }
/// <summary>
/// True if this port is actively supplying power.
/// </summary>
public bool IsSupplyingPower { get; set; }
/// <summary>
/// Constructor for an ThermalPort.
/// </summary>
/// <param name="id">Unique identifier for the port.</param>
public ThermalPort(string id) : base(id)
{
Voltage = 0.0;
Amperage = 0.0;
IsSupplyingPower = false;
}
/// <summary>
/// Connects this Thermal port to another Thermal port.
/// Includes basic type checking.
/// </summary>
/// <param name="otherPort">The port to connect to.</param>
public override void Connect(Port otherPort)
{
if (otherPort is ThermalPort)
{
base.Connect(otherPort);
}
else
{
Console.WriteLine($"Error: Cannot connect ThermalPort {ID} to non-ThermalPort {otherPort.ID}.");
}
}
/// <summary>
/// Mirrors Thermal properties from this port to its connected port.
/// This is for the direct property assignment data flow model.
/// </summary>
public void MirrorToConnectedPort()
{
if (ConnectedPort is ThermalPort connectedThermalPort)
{
connectedThermalPort.Voltage = this.Voltage;
connectedThermalPort.Amperage = this.Amperage;
connectedThermalPort.IsSupplyingPower = this.IsSupplyingPower;
}
}
}
}

141
BWR.core/Simulator.cs Normal file
View File

@@ -0,0 +1,141 @@
// MyBWRSimulator.Core/Simulation/Simulator.cs
namespace MyBWRSimulator.Core.Simulation
{
using MyBWRSimulator.Core.Components.Abstract;
using MyBWRSimulator.Core.Data;
using System;
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// The orchestrator of the simulation. Manages components, runs the simulation loop, and provides data.
/// </summary>
public class Simulator
{
private List<Component> _components;
private double _simulationTime;
private bool _isPaused;
public Simulator()
{
_components = new List<Component>();
_simulationTime = 0.0;
_isPaused = false;
}
/// <summary>
/// Adds a component to the simulation.
/// </summary>
/// <param name="component">The component to add.</param>
public void AddComponent(Component component)
{
if (component != null && !_components.Contains(component))
{
_components.Add(component);
_components = _components.OrderBy(c => c.UpdatePriority).ToList(); // Re-sort after adding
component.Initialize();
Console.WriteLine($"Component '{component.Name}' ({component.ID}) added.");
}
}
/// <summary>
/// Removes a component from the simulation.
/// </summary>
/// <param name="component">The component to remove.</param>
public void RemoveComponent(Component component)
{
if (component != null && _components.Remove(component))
{
_components = _components.OrderBy(c => c.UpdatePriority).ToList(); // Re-sort after removing
component.Shutdown();
Console.WriteLine($"Component '{component.Name}' ({component.ID}) removed.");
}
}
/// <summary>
/// Loads components and connections from a configuration file.
/// </summary>
/// <param name="filePath">The path to the configuration JSON file.</param>
public void LoadPlantConfiguration(string filePath)
{
ConfigurationLoader.LoadConfiguration(filePath, out _components);
_components = _components.OrderBy(c => c.UpdatePriority).ToList(); // Ensure sorted after load
Console.WriteLine($"Loaded { _components.Count} components from configuration.");
}
/// <summary>
/// Runs the simulation for a specified duration with a given time step.
/// </summary>
/// <param name="duration">Total simulation duration (e.g., in seconds).</param>
/// <param name="timeStep">Time step for each update iteration (e.g., in seconds).</param>
public void RunSimulation(double duration, double timeStep)
{
Console.WriteLine($"Starting simulation for {duration} seconds with a time step of {timeStep} seconds...");
_isPaused = false;
while (_simulationTime < duration && !_isPaused)
{
Console.WriteLine($"\n--- Simulation Time: {_simulationTime:F2} s ---");
foreach (var component in _components)
{
component.Update(timeStep);
}
_simulationTime += timeStep;
// For console output, add a small delay to see updates
System.Threading.Thread.Sleep(100);
}
if (_simulationTime >= duration)
{
Console.WriteLine("\nSimulation finished.");
}
else if (_isPaused)
{
Console.WriteLine("\nSimulation paused.");
}
// Call shutdown for all components at the end of the simulation
foreach (var component in _components)
{
component.Shutdown();
}
}
/// <summary>
/// Pauses the simulation.
/// </summary>
public void PauseSimulation()
{
_isPaused = true;
}
/// <summary>
/// Resumes the simulation.
/// </summary>
public void ResumeSimulation()
{
_isPaused = false;
}
/// <summary>
/// Gets current simulation data from all components.
/// (Placeholder - you'll define the structure of this data more concretely later)
/// </summary>
/// <returns>A dictionary containing simulation data.</returns>
public Dictionary<string, object> GetSimulationData()
{
var data = new Dictionary<string, object>();
data["SimulationTime"] = _simulationTime;
data["ComponentStates"] = _components.Select(c => new
{
c.ID,
c.Name
// Add specific properties for each component type here
// Example for Pump: (c as Pump)?.PumpSpeed
// Example for FluidTank: (c as FluidTank)?.CurrentVolume
}).ToList();
return data;
}
}
}

View File