Skip to content

Commit 365fba0

Browse files
authored
reinstate ext-int (#1312)
1 parent dce0d2d commit 365fba0

10 files changed

Lines changed: 505 additions & 142 deletions

File tree

HEC.FDA.Model/compute/ImpactAreaScenarioSimulation.cs

Lines changed: 69 additions & 29 deletions
Large diffs are not rendered by default.

HEC.FDA.ModelTest/unittests/AlternativeComparisonReportConsolidationTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
namespace HEC.FDA.ModelTest.unittests;
1111

12+
[Trait("RunsOn","Remote")]
1213
/// <summary>
1314
/// Tests that the consolidated EAD methods correctly return life loss (AALL) reduced results
1415
/// alongside damage reduced results, verifying that the separate AALL computation path is no longer needed.

HEC.FDA.ModelTest/unittests/MessagingTests/ImpactAreaScenarioSimulationShould.cs

Lines changed: 278 additions & 57 deletions
Large diffs are not rendered by default.

HEC.FDA.TestingUtility/ComputeRunner.cs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,10 @@ public async Task<int> RunAsync()
9090
switch (compute.Type.ToLowerInvariant())
9191
{
9292
case "stagedamage":
93-
List<UncertainPairedData> sdCurves = StageDamageRunner.RunStageDamage(compute.ElementName);
94-
SaveStageDamageResults(compute.ElementName, sdCurves);
95-
_csvReportFactory.AddStageDamageSummary(study.StudyId, compute.ElementName, sdCurves);
93+
StageDamageResult sdResult = StageDamageRunner.RunStageDamage(compute.ElementName);
94+
SaveStageDamageResults(compute.ElementName, sdResult.StageDamageFunctions);
95+
WriteStructureDetails(study.StudyId, compute.ElementName, sdResult);
96+
_csvReportFactory.AddStageDamageSummary(study.StudyId, compute.ElementName, sdResult.StageDamageFunctions);
9697
break;
9798

9899
case "scenario":
@@ -323,4 +324,45 @@ private static void SaveStageDamageResults(string elementName, List<UncertainPai
323324
PersistenceFactory.GetElementManager<AggregatedStageDamageElement>().SaveExisting(element);
324325
Console.WriteLine($" Saved {curves.Count} curves to temp database.");
325326
}
327+
328+
private void WriteStructureDetails(string studyId, string elementName, StageDamageResult sdResult)
329+
{
330+
if (sdResult.ScenarioStageDamage == null)
331+
{
332+
Console.WriteLine($" Skipping structure details for manual stage damage '{elementName}'.");
333+
return;
334+
}
335+
336+
string detailsDir = Path.Combine(_outputDir, studyId, "StructureDetails");
337+
Directory.CreateDirectory(detailsDir);
338+
339+
Dictionary<int, string> iaNames = [];
340+
List<ImpactAreaRowItem> iaRows = sdResult.ImpactAreaElement.ImpactAreaRows;
341+
for (int i = 0; i < iaRows.Count; i++)
342+
{
343+
iaNames[i] = iaRows[i].Name;
344+
}
345+
346+
string detailsPath = Path.Combine(detailsDir, $"{elementName}_StructureStageDamageDetails.csv");
347+
List<string> structureDetails = sdResult.ScenarioStageDamage.ProduceStructureDetails(iaNames);
348+
using (StreamWriter writer = new(File.Create(detailsPath)))
349+
{
350+
foreach (string line in structureDetails)
351+
{
352+
writer.WriteLine(line);
353+
}
354+
}
355+
Console.WriteLine($" Wrote structure details to {detailsPath}");
356+
357+
string damagedElesPath = Path.Combine(detailsDir, $"{elementName}_DamagedElementCountsByStage.csv");
358+
List<string> damagedElementCounts = UncertainPairedData.ConvertDamagedElementCountToText(sdResult.DamagedElementCounts, iaNames);
359+
using (StreamWriter writer = new(File.Create(damagedElesPath)))
360+
{
361+
foreach (string line in damagedElementCounts)
362+
{
363+
writer.WriteLine(line);
364+
}
365+
}
366+
Console.WriteLine($" Wrote damaged element counts to {damagedElesPath}");
367+
}
326368
}

HEC.FDA.TestingUtility/Program.cs

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,19 @@ public static async Task<int> Main(string[] args)
1717
// ============ COMPUTE COMMAND ============
1818
Command computeCommand = new("compute", "Run computations on FDA studies and generate CSV result reports");
1919

20-
Option<FileInfo> computeConfigOption = new(
20+
Option<FileInfo?> computeConfigOption = new(
2121
name: "--config",
22-
description: "Path to JSON configuration file")
23-
{ IsRequired = true };
22+
description: "Path to JSON configuration file");
2423
computeConfigOption.AddAlias("-c");
2524

26-
Option<DirectoryInfo> computeOutputOption = new(
25+
Option<FileInfo?> studyPathOption = new(
26+
name: "--study-path",
27+
description: "Path to a .sqlite study file (runs all computations)");
28+
studyPathOption.AddAlias("-sp");
29+
30+
Option<DirectoryInfo?> computeOutputOption = new(
2731
name: "--output",
28-
description: "Output directory for generated files",
29-
getDefaultValue: () => new DirectoryInfo(Environment.CurrentDirectory));
32+
description: "Output directory for generated files");
3033
computeOutputOption.AddAlias("-o");
3134

3235
Option<string[]> computeStudyOption = new(
@@ -36,34 +39,83 @@ public static async Task<int> Main(string[] args)
3639
computeStudyOption.AddAlias("-s");
3740

3841
computeCommand.AddOption(computeConfigOption);
42+
computeCommand.AddOption(studyPathOption);
3943
computeCommand.AddOption(computeOutputOption);
4044
computeCommand.AddOption(computeStudyOption);
4145

42-
computeCommand.SetHandler(async (configFile, outputDir, studyFilter) =>
46+
computeCommand.SetHandler(async (configFile, studyPath, outputDir, studyFilter) =>
4347
{
4448
try
4549
{
4650
Console.WriteLine("FDA Testing Utility - Compute");
4751
Console.WriteLine("=============================");
4852
Console.WriteLine();
4953

50-
if (!configFile.Exists)
54+
if (configFile != null && studyPath != null)
55+
{
56+
Console.WriteLine("Error: Cannot specify both --config and --study-path. Use one or the other.");
57+
return;
58+
}
59+
60+
if (configFile == null && studyPath == null)
5161
{
52-
Console.WriteLine($"Error: Configuration file not found: {configFile.FullName}");
62+
Console.WriteLine("Error: Must specify either --config or --study-path.");
5363
return;
5464
}
5565

56-
Console.WriteLine($"Loading configuration: {configFile.FullName}");
57-
TestConfiguration config = TestConfiguration.LoadFromFile(configFile.FullName);
66+
TestConfiguration config;
67+
string outputPath;
5868

59-
if (!outputDir.Exists)
69+
if (studyPath != null)
70+
{
71+
if (!studyPath.Exists)
72+
{
73+
Console.WriteLine($"Error: Study file not found: {studyPath.FullName}");
74+
return;
75+
}
76+
77+
string studyName = Path.GetFileNameWithoutExtension(studyPath.Name);
78+
string studyDir = studyPath.DirectoryName!;
79+
80+
Console.WriteLine($"Direct study mode: {studyPath.FullName}");
81+
config = new TestConfiguration
82+
{
83+
TestSuiteId = $"direct-{studyName}",
84+
Studies = new List<StudyConfiguration>
85+
{
86+
new()
87+
{
88+
StudyId = studyName,
89+
StudyName = studyName,
90+
NetworkSourcePath = studyDir,
91+
RunAllStageDamage = true,
92+
RunAllScenarios = true,
93+
RunAllAlternatives = true,
94+
RunAllAlternativeComparisons = true,
95+
}
96+
}
97+
};
98+
99+
outputPath = outputDir?.FullName ?? studyDir;
100+
}
101+
else
60102
{
61-
outputDir.Create();
103+
if (!configFile!.Exists)
104+
{
105+
Console.WriteLine($"Error: Configuration file not found: {configFile.FullName}");
106+
return;
107+
}
108+
109+
Console.WriteLine($"Loading configuration: {configFile.FullName}");
110+
config = TestConfiguration.LoadFromFile(configFile.FullName);
111+
outputPath = outputDir?.FullName ?? Environment.CurrentDirectory;
62112
}
63113

114+
Directory.CreateDirectory(outputPath);
115+
64116
ComputeRunner runner = new(
65117
config,
66-
outputDir.FullName,
118+
outputPath,
67119
studyFilter?.Length > 0 ? studyFilter : null);
68120

69121
await runner.RunAsync();
@@ -73,12 +125,12 @@ public static async Task<int> Main(string[] args)
73125
Console.WriteLine($"Fatal error: {ex.Message}");
74126
Console.WriteLine(ex.StackTrace);
75127
}
76-
}, computeConfigOption, computeOutputOption, computeStudyOption);
128+
}, computeConfigOption, studyPathOption, computeOutputOption, computeStudyOption);
77129

78130
// Add subcommands to root
79131
rootCommand.AddCommand(computeCommand);
80132

81133
// Run
82134
return await rootCommand.InvokeAsync(args);
83135
}
84-
}
136+
}

HEC.FDA.TestingUtility/Services/StageDamageRunner.cs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,19 @@
77
using HEC.FDA.ViewModel.ImpactArea;
88
using HEC.FDA.ViewModel.Inventory;
99
using HEC.FDA.ViewModel.Utilities;
10+
using Utility.Progress;
1011

1112
namespace HEC.FDA.TestingUtility.Services;
1213

14+
public record StageDamageResult(
15+
List<UncertainPairedData> StageDamageFunctions,
16+
List<UncertainPairedData> DamagedElementCounts,
17+
ScenarioStageDamage? ScenarioStageDamage,
18+
ImpactAreaElement ImpactAreaElement);
19+
1320
public static class StageDamageRunner
1421
{
15-
public static List<UncertainPairedData> RunStageDamage(string elementName)
22+
public static StageDamageResult RunStageDamage(string elementName)
1623
{
1724
if (string.IsNullOrWhiteSpace(elementName))
1825
{
@@ -23,19 +30,19 @@ public static List<UncertainPairedData> RunStageDamage(string elementName)
2330

2431
AggregatedStageDamageElement element = ScenarioRunner.FindElement<AggregatedStageDamageElement>(elementName);
2532

26-
if (element.IsManual)
27-
{
28-
Console.WriteLine($" Stage damage '{elementName}' is manual - returning existing curves.");
29-
return ConvertCurvesToUPD(element.Curves);
30-
}
31-
3233
var impactAreaElements = BaseViewModel.StudyCache.GetChildElementsOfType<ImpactAreaElement>();
3334
if (impactAreaElements.Count == 0)
3435
{
3536
throw new InvalidOperationException("No impact area element found in study.");
3637
}
3738
ImpactAreaElement impactAreaElement = impactAreaElements[0];
3839

40+
if (element.IsManual)
41+
{
42+
Console.WriteLine($" Stage damage '{elementName}' is manual - returning existing curves.");
43+
return new StageDamageResult(ConvertCurvesToUPD(element.Curves), [], null, impactAreaElement);
44+
}
45+
3946
HydraulicElement hydraulicElement = ScenarioRunner.FindElementById<HydraulicElement>(element.SelectedWSE);
4047
InventoryElement inventoryElement = ScenarioRunner.FindElementById<InventoryElement>(element.SelectedStructures);
4148

@@ -72,11 +79,11 @@ public static List<UncertainPairedData> RunStageDamage(string elementName)
7279

7380
Console.WriteLine($" Computing stage damage with {totalStructureCount} structures...");
7481

75-
(List<UncertainPairedData> stageDamageFunctions, _) = scenarioStageDamage.Compute();
82+
(List<UncertainPairedData> stageDamageFunctions, List<UncertainPairedData> damagedElementCounts) = scenarioStageDamage.Compute(false,ProgressReporter.ConsoleWrite());
7683

7784
Console.WriteLine($" Stage damage computation complete. Generated {stageDamageFunctions.Count} curves.");
7885

79-
return stageDamageFunctions;
86+
return new StageDamageResult(stageDamageFunctions, damagedElementCounts, scenarioStageDamage, impactAreaElement);
8087
}
8188

8289
private static List<UncertainPairedData> ConvertCurvesToUPD(List<StageDamageCurve> curves)

HEC.FDA.TestingUtility/Services/StudyLoader.cs

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ private static void CopyDirectory(string sourceDir, string destDir)
7878

7979
private static string FindDatabaseFile(string studyPath)
8080
{
81-
// Look for .sqlite or .db files
81+
// Look for .sqlite or .db files recursively
8282
string[] dbExtensions = { "*.sqlite", "*.db" };
8383

8484
foreach (string pattern in dbExtensions)
8585
{
86-
string[] files = Directory.GetFiles(studyPath, pattern);
86+
string[] files = Directory.GetFiles(studyPath, pattern, SearchOption.AllDirectories);
8787
if (files.Length > 0)
8888
{
8989
return files[0];
@@ -130,30 +130,29 @@ private static void LoadElementType<T>(string displayName) where T : ChildElemen
130130

131131
public void Cleanup()
132132
{
133-
if (_localStudyPath != null && Directory.Exists(_localStudyPath))
133+
try
134134
{
135-
try
135+
// Close the connection first
136+
if (!Connection.Instance.IsConnectionNull && Connection.Instance.IsOpen)
136137
{
137-
// Close the connection first
138-
if (!Connection.Instance.IsConnectionNull && Connection.Instance.IsOpen)
139-
{
140-
Connection.Instance.Close();
141-
}
138+
Connection.Instance.Close();
139+
}
142140

143-
// Clear SQLite connection pool to release file handles
144-
SQLiteConnection.ClearAllPools();
141+
// Clear SQLite connection pool to release file handles
142+
SQLiteConnection.ClearAllPools();
145143

146-
// Force garbage collection to release any remaining handles
147-
GC.Collect();
148-
GC.WaitForPendingFinalizers();
144+
// Force garbage collection to release any remaining handles
145+
GC.Collect();
146+
GC.WaitForPendingFinalizers();
147+
}
148+
catch (Exception ex)
149+
{
150+
Console.WriteLine($" Warning: Failed to close connections: {ex.Message}");
151+
}
149152

150-
Directory.Delete(_localStudyPath, recursive: true);
151-
Console.WriteLine($" Cleaned up temp study folder: {_localStudyPath}");
152-
}
153-
catch (Exception ex)
154-
{
155-
Console.WriteLine($" Warning: Failed to cleanup temp folder: {ex.Message}");
156-
}
153+
if (_localStudyPath != null)
154+
{
155+
Console.WriteLine($" Temp study folder retained at: {_localStudyPath}");
157156
}
158157
}
159158

HEC.FDA.View/ImpactAreaScenario/Editor/SpecificIASControl.xaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,16 @@
103103
DisplayMemberPath="Name"
104104
SelectedItem="{Binding SelectedLeveeFeatureElement}" />
105105

106-
<!--<Label Grid.Column="2"
106+
<Label Grid.Column="2"
107107
Content="{x:Static utilVM:StringConstants.EXT_INT_SHORT_LABEL}"
108108
Visibility="{Binding HasNonFailureStageDamage,Converter={StaticResource BoolToInverseVisibilityConverter}}"
109-
HorizontalAlignment="Right" />-->
110-
<!--<ComboBox Grid.Column="3"
109+
HorizontalAlignment="Right" />
110+
<ComboBox Grid.Column="3"
111111
HorizontalAlignment="Stretch"
112112
ItemsSource="{Binding ExteriorInteriorElements}"
113113
DisplayMemberPath="Name"
114114
SelectedItem="{Binding SelectedExteriorInteriorElement}"
115-
Visibility="{Binding HasNonFailureStageDamage,Converter={StaticResource BoolToInverseVisibilityConverter}}" />-->
115+
Visibility="{Binding HasNonFailureStageDamage,Converter={StaticResource BoolToInverseVisibilityConverter}}" />
116116

117117

118118
</Grid>

HEC.FDA.ViewModel/ImpactAreaScenario/Editor/SpecificIASEditorVM.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ private void PreviewCompute()
550550
else if(_SelectedStageDamage() == null && _HasFailureStageDamage == true){
551551
}
552552

553-
ChildElementComboItem selectedStageDamage = _SelectedStageDamage();
553+
ChildElementComboItem selectedStageDamage = _SelectedStageDamage();
554554
FrequencyElement freqElem = SelectedFrequencyElement.ChildElement as FrequencyElement;
555555
InflowOutflowElement inOutElem = SelectedInflowOutflowElement.ChildElement as InflowOutflowElement;
556556
StageDischargeElement ratElem = SelectedRatingCurveElement.ChildElement as StageDischargeElement;
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Amazon.Auth.AccessControlPolicy;
12
using System;
23
using System.IO;
34
using System.Threading.Tasks;
@@ -7,14 +8,14 @@ namespace ScratchSpace.Beam;
78
public static class ValidationAndVerification
89
{
910
private static readonly string ConfigPath = Path.GetFullPath(
10-
Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "Beam", "west-sac-config.json"));
11+
Path.Combine(@"C:\Programs\Source\HEC-FDA2\HEC.FDA.TestingUtility\all_case_studies.json"));
1112

1213
private static readonly string OutputPath = Path.GetFullPath(
1314
Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "Beam", "output"));
1415

1516
public static async Task<int> RunValidationAndVerificationReport()
1617
{
17-
string[] args = ["compute", "-c", ConfigPath, "-o", OutputPath];
18+
string[] args = ["compute", "-c", ConfigPath];
1819
return await HEC.FDA.TestingUtility.Program.Main(args);
1920
}
2021
}

0 commit comments

Comments
 (0)