Skip to content

Commit b96420f

Browse files
committed
Initial work to allow variable water level in glass gauge
1 parent ade0195 commit b96420f

File tree

1 file changed

+106
-1
lines changed

1 file changed

+106
-1
lines changed

Source/Orts.Simulation/Simulation/RollingStocks/MSTSSteamLocomotive.cs

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@ public class MSTSSteamLocomotive : MSTSLocomotive
258258
// eng file configuration parameters
259259

260260
float BoilerVolumeFT3; // total space in boiler that can hold water and steam
261+
float MSTSBoilerLengthM;
262+
float ORBoilerLengthM;
263+
float BoilerLengthM;
264+
public float GradientBoilerLevelPercent;
261265
public int MSTSNumCylinders = 2; // Number of Cylinders
262266
public float MSTSCylinderStrokeM; // High pressure cylinders
263267
public float MSTSCylinderDiameterM; // High pressure cylinders
@@ -455,7 +459,11 @@ public float TenderFuelMassKG // Decreased by firing and increased
455459
float WaterGlassMinLevel = 0.73f; // min height of water gauge as a fraction of boiler level
456460
float WaterGlassLengthIN = 8.0f; // nominal length of water gauge
457461
float WaterGlassLevelIN; // Water glass level in inches
462+
float ORSteamGaugeGlassHeightM;
463+
float MSTSSteamGaugeGlassHeightM;
464+
float WaterGlassLengthM;
458465
float waterGlassPercent; // Water glass level in percent
466+
bool WaterGlassLevelGradientEnabled = false;
459467
float MEPFactor = 0.7f; // Factor to determine the MEP
460468
float GrateAreaDesignFactor = 500.0f; // Design factor for determining Grate Area
461469
float EvapAreaDesignFactor = 10.0f; // Design factor for determining Evaporation Area
@@ -945,6 +953,10 @@ public override void Parse(string lowercasetoken, STFReader stf)
945953
case "engine(lpcylinderdiameter": MSTSLPCylinderDiameterM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
946954
case "engine(ortscylinderportopening": CylinderPortOpeningFactor = stf.ReadFloatBlock(STFReader.UNITS.None, null); break;
947955
case "engine(boilervolume": BoilerVolumeFT3 = stf.ReadFloatBlock(STFReader.UNITS.VolumeDefaultFT3, null); break;
956+
case "engine(boilerlength": MSTSBoilerLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
957+
case "engine(ortsboilerlength": ORBoilerLengthM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
958+
case "engine(steamgaugeglassheight": MSTSSteamGaugeGlassHeightM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
959+
case "engine(ortswatergaugeglassheight": ORSteamGaugeGlassHeightM = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); break;
948960
case "engine(maxboilerpressure": MaxBoilerPressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, null); break;
949961
case "engine(ortsmaxsuperheattemperature": MaxSuperheatRefTempF = stf.ReadFloatBlock(STFReader.UNITS.Temperature, null); break;
950962
case "engine(ortsmaxindicatedhorsepower":
@@ -1091,6 +1103,10 @@ public override void Copy(MSTSWagon copy)
10911103
CylinderExhaustOpenFactor = locoCopy.CylinderExhaustOpenFactor;
10921104
CylinderPortOpeningFactor = locoCopy.CylinderPortOpeningFactor;
10931105
BoilerVolumeFT3 = locoCopy.BoilerVolumeFT3;
1106+
MSTSBoilerLengthM = locoCopy.MSTSBoilerLengthM;
1107+
ORBoilerLengthM = locoCopy.ORBoilerLengthM;
1108+
MSTSSteamGaugeGlassHeightM = locoCopy.MSTSSteamGaugeGlassHeightM;
1109+
ORSteamGaugeGlassHeightM = locoCopy.ORSteamGaugeGlassHeightM;
10941110
MaxBoilerPressurePSI = locoCopy.MaxBoilerPressurePSI;
10951111
SteamLocomotiveFeedWaterType = locoCopy.SteamLocomotiveFeedWaterType;
10961112
MaxSuperheatRefTempF = locoCopy.MaxSuperheatRefTempF;
@@ -1461,6 +1477,57 @@ public override void Initialize()
14611477
BoilerEvapRateLbspFt2 = MathHelper.Clamp(BoilerEvapRateLbspFt2, 7.5f, 30.0f); // Clamp BoilerEvap Rate to between 7.5 & 30 - some modern locomotives can go as high as 30, but majority are around 15.
14621478
TheoreticalMaxSteamOutputLBpS = pS.FrompH(Me2.ToFt2(EvaporationAreaM2) * BoilerEvapRateLbspFt2); // set max boiler theoretical steam output
14631479

1480+
// Initialise Boiler parameters
1481+
1482+
// Boiler Length - always use OR entered value as first preference
1483+
BoilerLengthM = ORBoilerLengthM;
1484+
1485+
/*
1486+
// If OR value hasn't been set, then use MSTS value if present
1487+
if (BoilerLengthM == 0 && MSTSBoilerLengthM > 0)
1488+
{
1489+
if (MSTSBoilerLengthM > 0.4f * CarLengthM && MSTSBoilerLengthM < CarLengthM)
1490+
{
1491+
BoilerLengthM = MSTSBoilerLengthM;
1492+
1493+
if (Simulator.Settings.VerboseConfigurationMessages)
1494+
{
1495+
Trace.TraceInformation("Boiler Length set as per MSTS default = {0}", FormatStrings.FormatDistance(BoilerLengthM, IsMetric));
1496+
}
1497+
}
1498+
}
1499+
*/
1500+
1501+
// Water Gauge Length - always use OR entered value as first preference
1502+
WaterGlassLengthM = ORSteamGaugeGlassHeightM;
1503+
1504+
/*
1505+
// If OR value hasn't been set, then use MSTS value if present
1506+
if (WaterGlassLengthM == 0 && MSTSSteamGaugeGlassHeightM > 0)
1507+
{
1508+
var defaultGlassLength = Me.FromIn(12);
1509+
1510+
if (MSTSSteamGaugeGlassHeightM < defaultGlassLength)
1511+
{
1512+
WaterGlassLengthM = MSTSSteamGaugeGlassHeightM;
1513+
WaterGlassLengthIN = Me.ToIn(WaterGlassLengthM);
1514+
1515+
if (Simulator.Settings.VerboseConfigurationMessages)
1516+
{
1517+
Trace.TraceInformation("Water Glass Length set as per MSTS default = {0}", FormatStrings.FormatDistance(WaterGlassLengthM, IsMetric));
1518+
}
1519+
}
1520+
}
1521+
*/
1522+
1523+
1524+
if (WaterGlassLengthM > 0 && BoilerLengthM > 0 )
1525+
{
1526+
WaterGlassLevelGradientEnabled = true;
1527+
}
1528+
1529+
// Trace.TraceInformation("Boiler Water Level - MSTSLength {0} ORLength {1} MSTSGlass {2} OR Glass {3} Enabled {4}, WaterGlass {5} BoilerLength {6}", MSTSBoilerLengthM, ORBoilerLengthM, MSTSSteamGaugeGlassHeightM, ORSteamGaugeGlassHeightM, WaterGlassLevelGradientEnabled, WaterGlassLengthM, BoilerLengthM);
1530+
14641531
float BoilerVolumeCheck = Me2.ToFt2(EvaporationAreaM2) / BoilerVolumeFT3; //Calculate the Boiler Volume Check value.
14651532
if (BoilerVolumeCheck > 15) // If boiler volume is not in ENG file or less then a viable figure (ie high ratio figure), then set to a default value
14661533
{
@@ -7056,6 +7123,36 @@ private void UpdateWaterGauge()
70567123
Simulator.Confirmer.Message(ConfirmLevel.Information, Simulator.Catalog.GetString("Boiler no longer priming."));
70577124
BoilerIsPriming = false;
70587125
}
7126+
7127+
// Calculate water glass level when on gradient
7128+
if (WaterGlassLevelGradientEnabled)
7129+
{
7130+
var boilerangleRad = Math.Atan(CurrentElevationPercent / 100);
7131+
var waterVariationLevelM = (float)Math.Sin(boilerangleRad) * BoilerLengthM / 2.0f;
7132+
7133+
// Assume that reference glass height is 50% of glass
7134+
var maxWaterVariationIN = Me.ToIn(WaterGlassLengthM) / 2.0f;
7135+
7136+
float glasslevelIN = 0;
7137+
float glassLevelFraction = 0;
7138+
7139+
if (CurrentElevationPercent > 0) // Downslope - -ve water slope
7140+
{
7141+
glasslevelIN -= Me.ToIn(waterVariationLevelM) * -1.0f;
7142+
}
7143+
else // up slope - +ve water level
7144+
{
7145+
glasslevelIN += Me.ToIn(waterVariationLevelM) * -1.0f;
7146+
}
7147+
7148+
glassLevelFraction = glasslevelIN / maxWaterVariationIN;
7149+
7150+
GradientBoilerLevelPercent = glassLevelFraction * 100;
7151+
7152+
// Trace.TraceInformation("Gradient - Current {0} BoilAng {1} GlassIN {2} Glass% {3}", CurrentElevationPercent, boilerangleRad, glasslevelIN, GradientBoilerLevelPercent);
7153+
}
7154+
7155+
70597156
}
70607157

70617158
private void UpdateWaterInjection(float elapsedClockSeconds)
@@ -7828,7 +7925,15 @@ public override string GetStatus()
78287925
SteamGearRatio, SteamGearPosition == 0 ? Simulator.Catalog.GetParticularString("Gear", "N") : SteamGearPosition.ToString());
78297926
status.AppendFormat("{0}{2} = {1}/{3}{2}\n", Simulator.Catalog.GetString("Steam usage"), FormatStrings.FormatMass(pS.TopH(Kg.FromLb(PreviousTotalSteamUsageLBpS)), MainPressureUnit != PressureUnit.PSI), steamusagesafety, FormatStrings.h);
78307927
status.AppendFormat("{0}{2} = {1}{2}\n", Simulator.Catalog.GetString("Boiler pressure"), FormatStrings.FormatPressure(BoilerPressurePSI, PressureUnit.PSI, MainPressureUnit, true), boilerPressureSafety);
7831-
status.AppendFormat("{0}{2} = {1:F0}% {3}{2}\n", Simulator.Catalog.GetString("Boiler water glass"), 100 * waterGlassPercent, boilerWaterSafety, FiringIsManual ? Simulator.Catalog.GetString("(safe range)") : "");
7928+
7929+
if (WaterGlassLevelGradientEnabled)
7930+
{
7931+
status.AppendFormat("{0}{2} = {1:F0}% {3}{2}\n", Simulator.Catalog.GetString("Boiler water glass"), GradientBoilerLevelPercent, boilerWaterSafety, FiringIsManual ? Simulator.Catalog.GetString("(safe range)") : "");
7932+
}
7933+
else
7934+
{
7935+
status.AppendFormat("{0}{2} = {1:F0}% {3}{2}\n", Simulator.Catalog.GetString("Boiler water glass"), 100 * waterGlassPercent, boilerWaterSafety, FiringIsManual ? Simulator.Catalog.GetString("(safe range)") : "");
7936+
}
78327937

78337938
if (FiringIsManual)
78347939
{

0 commit comments

Comments
 (0)