Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nsi processor #29

Merged
merged 32 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
917bb16
initial DepthHazard
jackschonherr Aug 16, 2024
6d63b42
renaming in Result, added unit test file
jackschonherr Aug 16, 2024
a0559c2
added parameter checking to Get
jackschonherr Aug 16, 2024
cbf06d8
implemented Has for LifeLosshazard, need to test more
jackschonherr Aug 16, 2024
2163411
changed unit tests to test individual methods
jackschonherr Aug 19, 2024
e090217
implemented get for LifeLossHazard, added tests #15
jackschonherr Aug 19, 2024
d0ac729
implemented IResultsWriter #16
jackschonherr Aug 19, 2024
bb16055
Implemented ConsoleWriter and unit tests for it #17
jackschonherr Aug 19, 2024
17c84dd
Implemented functionality and tests for first unit test of Structure #18
jackschonherr Aug 19, 2024
e6dced2
Added more tests for Structure, fixed issues with testing console output
jackschonherr Aug 20, 2024
c5d1843
implemented Location and BoundingBox, not sure about GDAL format for …
jackschonherr Aug 21, 2024
72f0d32
implemented IHazardProvider
jackschonherr Aug 21, 2024
a09045c
implemented RandomDepthHazardProvider and tests #21, and removed chec…
jackschonherr Aug 21, 2024
0819886
removed unneeded dependencies auto-generated by visual studio
jackschonherr Aug 21, 2024
a7a1415
added fields to Structure
jackschonherr Aug 21, 2024
7b91ac3
changed floats to doubles to match float64 specification
jackschonherr Aug 21, 2024
92148cd
removed filter from CI
jackschonherr Aug 22, 2024
0c4b9ad
removed no-build
jackschonherr Aug 22, 2024
2cc7a8f
changed unit tests for #17 and #18 to circumvent weird behavior with …
jackschonherr Aug 22, 2024
2d466f4
added initial interfaces and implementations for processors after the…
jackschonherr Aug 22, 2024
b3f0687
added GetLocation to ConsequenceReceptor and changed Location coordin…
jackschonherr Aug 22, 2024
aa7aeee
added auto properties where needed
jackschonherr Aug 22, 2024
f73e7ad
renamed indiviual tests to be more descriptive
jackschonherr Aug 22, 2024
9b9b553
added API functionality
jackschonherr Aug 23, 2024
10ae683
added scratchpaper testing environment
jackschonherr Aug 26, 2024
f11ff66
implemented feature stream processor
jackschonherr Aug 27, 2024
69f8171
added URL construction method + compatiblity with custom bounding boxes
jackschonherr Aug 27, 2024
c6dacc3
added bounding box to test larger area
jackschonherr Aug 27, 2024
611b66e
changed tests
jackschonherr Aug 28, 2024
d4584e8
merge commit
jackschonherr Aug 28, 2024
c390072
various refactors to make code cleaner
jackschonherr Aug 28, 2024
6cb2f02
muted warnings in Process, cleaned up Process test
jackschonherr Aug 28, 2024
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
6 changes: 6 additions & 0 deletions Consequences.sln
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsequencesTest", "ConsequencesTest\ConsequencesTest.csproj", "{95BCC49B-7780-41E9-8365-C51B5E1B3D5E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScratchPaper", "ScratchPaper\ScratchPaper.csproj", "{31071E1B-DA08-40CF-8F16-95982E85B45D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -28,6 +30,10 @@ Global
{95BCC49B-7780-41E9-8365-C51B5E1B3D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95BCC49B-7780-41E9-8365-C51B5E1B3D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95BCC49B-7780-41E9-8365-C51B5E1B3D5E}.Release|Any CPU.Build.0 = Release|Any CPU
{31071E1B-DA08-40CF-8F16-95982E85B45D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31071E1B-DA08-40CF-8F16-95982E85B45D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31071E1B-DA08-40CF-8F16-95982E85B45D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{31071E1B-DA08-40CF-8F16-95982E85B45D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
1 change: 1 addition & 0 deletions Consequences/Consequences.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<IsAotCompatible>true</IsAotCompatible>
<PublishAot>true</PublishAot>
<RootNamespace>USACE.HEC</RootNamespace>
<AssemblyName>USACE.HEC.Consequences</AssemblyName>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion Consequences/Consequences/IBBoxStreamingProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
namespace USACE.HEC.Consequences;
public interface IBBoxStreamingProcessor
{
public void Process(BoundingBox boundingBox, Action<IConsequencesReceptor> consequenceReceptorProcess);
public Task Process(BoundingBox boundingBox, Action<IConsequencesReceptor> consequenceReceptorProcess);
}
108 changes: 79 additions & 29 deletions Consequences/Consequences/NSIStreamingProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,51 +1,101 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text;
using System.Text.Json;
using USACE.HEC.Geography;

namespace USACE.HEC.Consequences;

public class NSIStreamingProcessor : IBBoxStreamingProcessor
{
public void Process(BoundingBox boundingBox, Action<IConsequencesReceptor> ConsequenceReceptorProcess)
public async Task Process(BoundingBox boundingBox, Action<IConsequencesReceptor> ConsequenceReceptorProcess)
{
Structure s = new Structure();
ConsequenceReceptorProcess(s);
await ProcessStream(boundingBox, ConsequenceReceptorProcess);
}

private static string ConstructURL(BoundingBox boundingBox, string directive)
{
StringBuilder url = new();

url.Append("https://nsi.sec.usace.army.mil/nsiapi/structures?bbox=");
url.Append(boundingBox.NSIFormat());

// directive to specify collection or stream
url.Append(directive);

return url.ToString();
}


/*
static async Task Test()
// this method processes an entire batch from the NSI at once rather than streaming them one by one
// was tested against ProcessStream and took used significantly more memory with similar times, so we opted to use ProcessStream instead
private static async Task ProcessCollection(BoundingBox boundingBox, Action<IConsequencesReceptor> ConsequenceReceptorProcess)
{
// Define the API endpoint
string apiEndpoint = "https://nsi.sec.usace.army.mil/nsiapi/structures?bbox=-81.58418,30.25165,-81.58161,30.26939,-81.55898,30.26939,-81.55281,30.24998,-81.58418,30.25165";
string apiUrl = ConstructURL(boundingBox, "&fmt=fc");

// Create an instance of HttpClient
using (HttpClient client = new HttpClient())
using HttpClient client = new();
try
{
try
{
// Make the GET request
HttpResponseMessage response = await client.GetAsync(apiEndpoint);
string jsonResponse = await client.GetStringAsync(apiUrl);

using JsonDocument doc = JsonDocument.Parse(jsonResponse);

// Check if the request was successful
response.EnsureSuccessStatusCode();
JsonElement featureCollection = doc.RootElement.GetProperty("features");
foreach (JsonElement structure in featureCollection.EnumerateArray())
{
// access the properties of each structure
JsonElement propertiesElement = structure.GetProperty("properties");

// Read and process the response content
string responseBody = await response.Content.ReadAsStringAsync();
// disable the warnings generated by Deserialize
#pragma warning disable IL2026
#pragma warning disable IL3050
Structure s = JsonSerializer.Deserialize<Structure>(propertiesElement.GetRawText());
#pragma warning restore IL2026
Copy link
Contributor

Choose a reason for hiding this comment

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

Look into how to ignore this warning

#pragma warning restore IL3050

// Output the response content (for demonstration purposes)
Console.WriteLine("API Response:");
Console.WriteLine(responseBody);
// apply the action to the deserialized structure
ConsequenceReceptorProcess(s);
}
catch (HttpRequestException e)
}
catch (Exception e)
{
Console.WriteLine($"Request error: {e.Message}");
}
}

// processes a stream of JSONs from the NSI one by one as opposed to loading in the entire batch
private static async Task ProcessStream(BoundingBox boundingBox, Action<IConsequencesReceptor> ConsequenceReceptorProcess)
{
string apiURL = ConstructURL(boundingBox, "&fmt=fs");

using HttpClient httpClient = new();
try
{
HttpResponseMessage response = await httpClient.GetAsync(apiURL);
response.EnsureSuccessStatusCode();

using StreamReader reader = new(await response.Content.ReadAsStreamAsync());

// read in a line from the stream on by one
// each individual structure JSON is contained in one line
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
// Handle any errors that occur during the request
Console.WriteLine($"Request error: {e.Message}");
using JsonDocument structure = JsonDocument.Parse(line);
JsonElement propertiesElement = structure.RootElement.GetProperty("properties");

// disable the warnings generated by Deserialize
#pragma warning disable IL2026
#pragma warning disable IL3050
Structure s = JsonSerializer.Deserialize<Structure>(propertiesElement.GetRawText());
#pragma warning restore IL2026
#pragma warning restore IL3050

// apply the action to the deserialized structure
ConsequenceReceptorProcess(s);
}
}
catch (Exception e)
{
Console.WriteLine($"Request error: {e.Message}");
}
}
*/
}
4 changes: 2 additions & 2 deletions Consequences/Consequences/Structure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public Location GetLocation()

public Result Compute(IHazard hazard)
{
List<ResultItem> resultItems = new List<ResultItem>();
List<ResultItem> resultItems = [];

if (hazard.Has(HazardParameter.Depth))
{
Expand Down Expand Up @@ -101,6 +101,6 @@ public Result Compute(IHazard hazard)
});
}

return new Result(resultItems.ToArray());
return new Result([.. resultItems]);
}
}
2 changes: 1 addition & 1 deletion Consequences/Results/ConsoleWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private void CheckIfSameHeaders(Result res)

public string WriteString(Result res)
{
StringBuilder output = new StringBuilder();
StringBuilder output = new();
if (!hasHeaderWritten)
{
// write the headers to the top of the file
Expand Down
4 changes: 1 addition & 3 deletions Consequences/Results/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ public ResultItem Fetch(string name)
if (ResultItems[i].ResultName == name)
return ResultItems[i];
// return empty ResultItem if not found
ResultItem item = new ResultItem();
item.ResultName = name;
return item;
return new ResultItem { ResultName = name };
}
}
37 changes: 28 additions & 9 deletions ConsequencesTest/NSIStreamingProcessorTest.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serialization;
using System.Text.Json;
using USACE.HEC.Consequences;
using USACE.HEC.Geography;
using USACE.HEC.Hazards;
using USACE.HEC.Results;

namespace ConsequencesTest;

public class NSIStreamingProcessorTest
{
[Fact]
public void Test()
public async Task Test()
{
IBBoxStreamingProcessor sp = new NSIStreamingProcessor();
// int i = 0;
IHazardProvider depthHazardProvider = new RandomDepthHazardProvider(25);
Location upperLeft1 = new Location { X = -122.475275, Y = 37.752394 };
Location lowerRight1 = new Location { X = -122.473523, Y = 37.750642 };
depthHazardProvider.Extent = new BoundingBox(upperLeft1, lowerRight1);
IResultsWriter consoleWriter = new ConsoleWriter();

sp.Process(depthHazardProvider.Extent, (IConsequencesReceptor s) => {
await sp.Process(depthHazardProvider.Extent, (IConsequencesReceptor s) => {
Result r = s.Compute(depthHazardProvider.Hazard(s.GetLocation()));
consoleWriter.Write(r);
});
Copy link
Contributor

Choose a reason for hiding this comment

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

await sp.Process

}

[Fact]
public void JSON_Deserialize()
{
string jsonString = """{"type": "Feature","geometry": {"type": "Point","coordinates": [-81.563689, 30.265468]},"properties":{"fd_id":498054345,"bid":"862W7C8P+5GM-0-0-0-0","occtype":"RES1-1SNB","st_damcat":"RES","bldgtype":"M","found_type":"S","cbfips":"120310159233002","pop2amu65":2,"pop2amo65":0,"pop2pmu65":1,"pop2pmo65":0,"sqft":1195,"num_story":1,"ftprntid":"none_242828","ftprntsrc":null,"students":0,"found_ht":0.5,"val_struct":124643.72,"val_cont":62321.8604,"val_vehic":27000,"source":"P","med_yr_blt":2004,"firmzone":null,"o65disable":0.26,"u65disable":0.05,"x":-81.56368862,"y":30.265468241,"ground_elv":27.445583771209716,"ground_elv_m":8.365413665771484}}""";
Structure? s = new Structure();
using (JsonDocument doc = JsonDocument.Parse(jsonString))
{
// Extract the "properties" section
JsonElement root = doc.RootElement;
JsonElement propertiesElement = root.GetProperty("properties");

// Convert the "properties" section to a JSON string
string propertiesJson = propertiesElement.GetRawText();

// Deserialize the "properties" section into the Properties class
s = JsonSerializer.Deserialize<Structure>(propertiesJson);

}
Assert.Equal(498054345, s?.Name);
}
}
33 changes: 33 additions & 0 deletions ScratchPaper/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using USACE.HEC.Consequences;
using USACE.HEC.Geography;

internal class Program
{
private static async Task Main(string[] args)
{
// city block in Sunset District, SF
Location upperLeft1 = new Location { X = -122.475275, Y = 37.752394 };
Location lowerRight1 = new Location { X = -122.473523, Y = 37.750642 };
BoundingBox boundingBox1 = new BoundingBox(upperLeft1, lowerRight1);


Location upperLeft2 = new Location { X = -122.5, Y = 37.8 };
Location lowerRight2 = new Location { X = -122, Y = 37.3 };
BoundingBox boundingBox2 = new BoundingBox(upperLeft2, lowerRight2);

IBBoxStreamingProcessor sp = new NSIStreamingProcessor();

int count = 0;
var watch = System.Diagnostics.Stopwatch.StartNew();
await sp.Process(boundingBox2, (IConsequencesReceptor s) => {
//Console.WriteLine(((Structure)s).Name);
count++;
});
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;

Console.WriteLine(count);
Console.WriteLine("Time elapsed: " + elapsedMs.ToString() + " milliseconds");
Console.Read();
}
}
14 changes: 14 additions & 0 deletions ScratchPaper/ScratchPaper.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Consequences\Consequences.csproj" />
</ItemGroup>

</Project>
Loading