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 30 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: 91 additions & 17 deletions Consequences/Consequences/NSIStreamingProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,51 +1,125 @@
using System;
using System.Collections.Generic;
Brennan1994 marked this conversation as resolved.
Show resolved Hide resolved
using System.Linq;
using System.Net.Http;
using System.Reflection.Emit;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
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);
//await ProcessCollection(boundingBox, ConsequenceReceptorProcess);
Brennan1994 marked this conversation as resolved.
Show resolved Hide resolved
}

public async Task TestProcessStream(BoundingBox boundingBox, Action<IConsequencesReceptor> ConsequenceReceptorProcess)
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks like leftover from testing. Should probably be removed. Any testing specific logic should be in the test classes.

{
await ProcessStream(boundingBox, ConsequenceReceptorProcess);
}

public async Task TestProcessCollection(BoundingBox boundingBox, Action<IConsequencesReceptor> ConsequenceReceptorProcess)
Brennan1994 marked this conversation as resolved.
Show resolved Hide resolved
{
await ProcessCollection(boundingBox, ConsequenceReceptorProcess);
}

/*
static async Task Test()
private string ConstructURL(BoundingBox boundingBox, string directive)
{
// 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";
StringBuilder url = new StringBuilder();

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();
}

private async Task ProcessCollection(BoundingBox boundingBox, Action<IConsequencesReceptor> ConsequenceReceptorProcess)
{
// endpoint URL
string apiUrl = ConstructURL(boundingBox, "&fmt=fc");

// Create an instance of HttpClient
using (HttpClient client = new HttpClient())
Brennan1994 marked this conversation as resolved.
Show resolved Hide resolved
{
try
{
// Make the GET request
HttpResponseMessage response = await client.GetAsync(apiEndpoint);
// send HTTP GET request, read in the entire json into a string
string jsonResponse = await client.GetStringAsync(apiUrl);

using (JsonDocument doc = JsonDocument.Parse(jsonResponse))
{
// access the FeatureCollection
JsonElement featureCollection = doc.RootElement.GetProperty("features");

// iterate through the FeatureCollection
foreach (JsonElement structure in featureCollection.EnumerateArray())
{
// access the properties of each structure
JsonElement propertiesElement = structure.GetProperty("properties");

// deserialize the properties JSON and create new Structure() object
Structure s = JsonSerializer.Deserialize<Structure>(propertiesElement.GetRawText());

Check warning on line 70 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.

Check warning on line 70 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

Check warning on line 70 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.

Check warning on line 70 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

Check warning on line 70 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.

Check warning on line 70 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

// apply the action to the deserialized structure
ConsequenceReceptorProcess(s);
}
}
}
catch (Exception e)
{
Console.WriteLine($"Request error: {e.Message}");
}
}
}

private async Task ProcessStream(BoundingBox boundingBox, Action<IConsequencesReceptor> ConsequenceReceptorProcess)
{
// endpoint URL
Brennan1994 marked this conversation as resolved.
Show resolved Hide resolved
string apiURL = ConstructURL(boundingBox, "&fmt=fs");

// Check if the request was successful
using (HttpClient httpClient = new HttpClient())
{
try
{
// send HTTP GET request
Copy link
Contributor

Choose a reason for hiding this comment

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

remove comment. self evident.

HttpResponseMessage response = await httpClient.GetAsync(apiURL);
response.EnsureSuccessStatusCode();

// Read and process the response content
string responseBody = await response.Content.ReadAsStringAsync();
using (StreamReader reader = new StreamReader(await response.Content.ReadAsStreamAsync()))
{
// read in a line from the stream on by one
// each individual structure JSON is contained in one line
Brennan1994 marked this conversation as resolved.
Show resolved Hide resolved
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
//Console.WriteLine(line);
Copy link
Contributor

Choose a reason for hiding this comment

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

remove commented code.

//Console.WriteLine("********************");
using (JsonDocument structure = JsonDocument.Parse(line))
{
JsonElement propertiesElement = structure.RootElement.GetProperty("properties");
// deserialize the properties JSON and create new Structure() object
Brennan1994 marked this conversation as resolved.
Show resolved Hide resolved
Structure s = JsonSerializer.Deserialize<Structure>(propertiesElement.GetRawText());

Check warning on line 110 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.

Check warning on line 110 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

Check warning on line 110 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.

Check warning on line 110 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

Check warning on line 110 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. JSON serialization and deserialization might require types that cannot be statically analyzed and might need runtime code generation. Use System.Text.Json source generation for native AOT applications.

Check warning on line 110 in Consequences/Consequences/NSIStreamingProcessor.cs

View workflow job for this annotation

GitHub Actions / CI

Using member 'System.Text.Json.JsonSerializer.Deserialize<TValue>(String, JsonSerializerOptions)' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. JSON serialization and deserialization might require types that cannot be statically analyzed. Use the overload that takes a JsonTypeInfo or JsonSerializerContext, or make sure all of the required types are preserved.

// 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)
{
// Handle any errors that occur during the request
Console.WriteLine($"Request error: {e.Message}");
}
}
}
*/
}
95 changes: 95 additions & 0 deletions ConsequencesTest/NSIStreamingProcessorTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Transactions;
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.Serialization;
using USACE.HEC.Consequences;
using USACE.HEC.Geography;
Expand All @@ -25,4 +27,97 @@ public void Test()
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);
}

[Fact]
public void ProcessCollection()
{;
IBBoxStreamingProcessor sp = new NSIStreamingProcessor();
sp.Process(null, (IConsequencesReceptor s) => {

});

}
/*
[Fact]
Copy link
Contributor

Choose a reason for hiding this comment

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

This can probably be deleted so long as the test above covers our bases.

public static async Task Ping()
{
// endpoint URL
string apiUrl = "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";

using (var client = new HttpClient())
{
// get the json from the NSI
string jsonResponse = await client.GetStringAsync(apiUrl);

int count = 0;
using (JsonDocument doc = JsonDocument.Parse(jsonResponse))
{
// access the FeatureCollection
JsonElement featureCollection = doc.RootElement.GetProperty("features");

// iterate through the FeatureCollection
foreach (JsonElement structure in featureCollection.EnumerateArray())
{
// access the properties of each structure
JsonElement propertiesElement = structure.GetProperty("properties");

// deserialize the properties JSON and create new Structure() object
Structure? s = JsonSerializer.Deserialize<Structure>(propertiesElement.GetRawText());
count++;
}
}
Assert.Equal(2735, count);
}
}

[Fact]
public static async Task ProcessCollection()
{
// endpoint URL
string apiUrl = "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";

using (var client = new HttpClient())
{
// get the json from the NSI
string jsonResponse = await client.GetStringAsync(apiUrl);

using (JsonDocument doc = JsonDocument.Parse(jsonResponse))
{
// access the FeatureCollection
JsonElement featureCollection = doc.RootElement.GetProperty("features");

// iterate through the FeatureCollection
foreach (JsonElement structure in featureCollection.EnumerateArray())
{
// access the properties of each structure
JsonElement propertiesElement = structure.GetProperty("properties");

// deserialize the properties JSON and create new Structure() object
Structure? s = JsonSerializer.Deserialize<Structure>(propertiesElement.GetRawText());
}
}
}
}
*/
}
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