Skip to content

Commit 9f5bc7e

Browse files
Merge pull request #129 from USACE/reconstruction-lifecycle
Reconstruction lifecycle
2 parents 7eee6af + 81dbe95 commit 9f5bc7e

12 files changed

Lines changed: 1380 additions & 46 deletions

compute/simulation_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,30 @@ func Test_StreamAbstract_MultiFrequency(t *testing.T) {
101101
//compute consequences.
102102
StreamAbstractMultiFrequency(hazardProviders, frequencies, nsp, w)
103103
}
104+
105+
func Test_StreamAbstract_MultiHazard(t *testing.T) {
106+
//initialize the NSI API structure provider
107+
nsp := structureprovider.InitNSISPwithOcctypeFilePath("/workspaces/go-consequences/data/lifecycle/occtypes_reconstruction.json")
108+
now := time.Now()
109+
fmt.Println(now)
110+
111+
root := "/workspaces/go-consequences/data/lifecycle/"
112+
filepath := root + "test_arrival-depth-duration_hazards.json"
113+
w, _ := resultswriters.InitSpatialResultsWriter(root+"multihazardtest_consequences.json", "results", "GeoJSON")
114+
//w := consequences.InitSummaryResultsWriterFromFile(root + "_consequences_SUMMARY.json")
115+
//create a result writer based on the name of the depth grid.
116+
//w, _ := resultswriters.InitGpkResultsWriter(root+"_consequences_nsi.gpkg", "nsi_result")
117+
defer w.Close()
118+
//initialize a hazard provider based on the depth grid.
119+
dfr, err := hazardproviders.InitADDMHP(filepath)
120+
if err != nil {
121+
panic(err)
122+
}
123+
//compute consequences.
124+
StreamAbstract(dfr, nsp, w)
125+
fmt.Println(time.Since(now))
126+
}
127+
104128
func Test_Config(t *testing.T) {
105129
config := Config{
106130
StructureProviderInfo: structureprovider.StructureProviderInfo{
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package hazardproviders
2+
3+
import (
4+
"encoding/csv"
5+
"fmt"
6+
"os"
7+
"strconv"
8+
"strings"
9+
"time"
10+
11+
"github.com/USACE/go-consequences/geography"
12+
"github.com/USACE/go-consequences/hazards"
13+
)
14+
15+
type csvArrivalDepthDurationMultiHazardProvider struct {
16+
f *os.File
17+
arrivals []time.Time
18+
depths []float64
19+
durations []float64
20+
process HazardFunction
21+
bbox geography.BBox
22+
}
23+
24+
func InitCSV(fp string, b geography.BBox) (csvArrivalDepthDurationMultiHazardProvider, error) {
25+
fmt.Println("Connecting to: " + fp)
26+
file, err := os.Open(fp)
27+
if err != nil {
28+
panic(err)
29+
}
30+
31+
reader := csv.NewReader(file)
32+
33+
rows, err := reader.ReadAll()
34+
if err != nil {
35+
panic(err)
36+
}
37+
arrivals := make([]time.Time, len(rows)-1)
38+
depths := make([]float64, len(rows)-1)
39+
durations := make([]float64, len(rows)-1)
40+
41+
for i, row := range rows[1:] {
42+
year, err := strconv.Atoi(row[2])
43+
if err != nil {
44+
panic(err)
45+
}
46+
month, err := strconv.Atoi(strings.TrimSpace(row[3]))
47+
if err != nil {
48+
panic(err)
49+
}
50+
day, err := strconv.Atoi(strings.TrimSpace(row[4]))
51+
if err != nil {
52+
panic(err)
53+
}
54+
at := time.Date(year, time.Month(month), int(day), 0, 0, 0, 0, time.UTC)
55+
depth, err := strconv.ParseFloat(row[5], 64)
56+
if err != nil {
57+
panic(err)
58+
}
59+
dur, err := strconv.ParseFloat(row[6], 64)
60+
if err != nil {
61+
panic(err)
62+
}
63+
64+
arrivals[i] = at
65+
depths[i] = depth
66+
durations[i] = dur
67+
}
68+
69+
return csvArrivalDepthDurationMultiHazardProvider{
70+
f: file,
71+
arrivals: arrivals,
72+
depths: depths,
73+
durations: durations,
74+
process: ArrivalDepthAndDurationHazardFunction(),
75+
bbox: b,
76+
}, nil
77+
78+
}
79+
80+
func (c csvArrivalDepthDurationMultiHazardProvider) Close() {
81+
c.f.Close()
82+
}
83+
84+
func (c csvArrivalDepthDurationMultiHazardProvider) Hazard(l geography.Location) (hazards.HazardEvent, error) {
85+
var hm hazards.ArrivalDepthandDurationEventMulti
86+
if c.bbox.Contains(l) {
87+
for i, d := range c.depths {
88+
hd := hazards.HazardData{
89+
Depth: d,
90+
Velocity: 0,
91+
ArrivalTime: c.arrivals[i],
92+
Erosion: 0,
93+
Duration: c.durations[i],
94+
WaveHeight: 0,
95+
Salinity: false,
96+
Qualitative: "",
97+
}
98+
var h hazards.HazardEvent
99+
h, err := c.process(hd, h)
100+
if err != nil {
101+
panic(err)
102+
}
103+
hm.Append(h.(hazards.ArrivalDepthandDurationEvent))
104+
}
105+
}
106+
return &hm, nil
107+
}
108+
109+
func (c csvArrivalDepthDurationMultiHazardProvider) HazardBoundary() (geography.BBox, error) {
110+
return c.bbox, nil
111+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package hazardproviders
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/USACE/go-consequences/geography"
8+
"github.com/USACE/go-consequences/hazards"
9+
)
10+
11+
func TestInitCSV(t *testing.T) {
12+
file := "/workspaces/go-consequences/data/lifecycle/test_arrival-depth-duration_hazards.csv"
13+
14+
expectedDepths := []float64{1.0, 1.0, 1.0, 2.0, 2.0}
15+
expectedDurations := []float64{0.0, 5.0, 0.0, 0.0, 0.0}
16+
et1 := time.Date(1984, time.Month(1), 1, 0, 0, 0, 0, time.UTC)
17+
et2 := time.Date(1984, time.Month(1), 11, 0, 0, 0, 0, time.UTC)
18+
et3 := time.Date(1984, time.Month(1), 21, 0, 0, 0, 0, time.UTC)
19+
et4 := time.Date(1985, time.Month(1), 1, 0, 0, 0, 0, time.UTC)
20+
et5 := time.Date(1985, time.Month(1), 11, 0, 0, 0, 0, time.UTC)
21+
expectedArrivals := []time.Time{et1, et2, et3, et4, et5}
22+
23+
b := geography.BBox{
24+
// xMin, yMin, xMax, yMax
25+
Bbox: []float64{-71.1, 43, -71, 43.1},
26+
}
27+
ADDMHP, err := InitCSV(file, b)
28+
if err != nil {
29+
panic(err)
30+
}
31+
defer ADDMHP.Close()
32+
33+
loc := geography.Location{
34+
X: -71.05,
35+
Y: 43.05,
36+
SRID: "",
37+
}
38+
39+
haz, err := ADDMHP.Hazard(loc)
40+
h := haz.(*hazards.ArrivalDepthandDurationEventMulti)
41+
if err != nil {
42+
panic(err)
43+
}
44+
45+
for {
46+
edepth := expectedDepths[h.Index()]
47+
edur := expectedDurations[h.Index()]
48+
earr := expectedArrivals[h.Index()]
49+
50+
if h.Depth() != edepth {
51+
t.Errorf("Event at index %d had Depth = %v. Expected: %3.2f", h.Index(), h.Depth(), edepth)
52+
}
53+
if h.Duration() != edur {
54+
t.Errorf("Event at index %d had Duration = %v. Expected: %3.2f", h.Index(), h.Duration(), edur)
55+
}
56+
if h.Depth() != edepth {
57+
t.Errorf("Event at index %d had ArrivalTime = %v. Expected: %v", h.Index(), h.ArrivalTime(), earr)
58+
}
59+
60+
if h.HasNext() {
61+
h.Increment()
62+
} else {
63+
break
64+
}
65+
}
66+
}

hazardproviders/interfaces.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,25 @@ func ArrivalAndDurationHazardFunction() HazardFunction {
4848
}
4949
}
5050

51+
func ArrivalDepthAndDurationHazardFunction() HazardFunction {
52+
return func(valueIn hazards.HazardData, hazard hazards.HazardEvent) (hazards.HazardEvent, error) {
53+
d := hazards.ArrivalDepthandDurationEvent{}
54+
d.SetDepth(valueIn.Depth)
55+
d.SetDuration(valueIn.Duration)
56+
d.SetArrivalTime(valueIn.ArrivalTime)
57+
return d, nil
58+
}
59+
}
60+
61+
func DepthAndDurationHazardFunction() HazardFunction {
62+
return func(valueIn hazards.HazardData, hazard hazards.HazardEvent) (hazards.HazardEvent, error) {
63+
d := hazards.ArrivalDepthandDurationEvent{}
64+
d.SetDepth(valueIn.Depth)
65+
d.SetDuration(valueIn.Duration)
66+
return d, nil
67+
}
68+
}
69+
5170
// NoHazardFoundError is an error for a situation where no hazard could be computed for the given args
5271
type NoHazardFoundError struct {
5372
Input string
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package hazardproviders
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"time"
8+
9+
"github.com/USACE/go-consequences/geography"
10+
"github.com/USACE/go-consequences/hazards"
11+
)
12+
13+
type jsonArrivalDepthDurationMultiHazardProvider struct {
14+
arrivals []time.Time
15+
depthCRs []cogReader
16+
durations []float64
17+
process HazardFunction
18+
}
19+
20+
type ADDProperties struct {
21+
Year float64 `json:"year"`
22+
Month float64 `json:"month"`
23+
Day float64 `json:"day"`
24+
Depth float64 `json:"depth"`
25+
Depthgrid string `json:"depthgrid"`
26+
Duration float64 `json:"duration"`
27+
Xmin float64 `json:"xmin"`
28+
Xmax float64 `json:"xmax"`
29+
Ymin float64 `json:"ymin"`
30+
Ymax float64 `json:"ymax"`
31+
}
32+
33+
type ADDEvents struct {
34+
Events []ADDProperties `json:"events"`
35+
}
36+
37+
func InitADDMHP(fp string) (jsonArrivalDepthDurationMultiHazardProvider, error) {
38+
fmt.Println("Connecting to: " + fp)
39+
c, err := os.ReadFile(fp)
40+
if err != nil {
41+
panic(err)
42+
}
43+
44+
var events ADDEvents
45+
json.Unmarshal(c, &events)
46+
47+
arrivalTimes := make([]time.Time, len(events.Events))
48+
durations := make([]float64, len(events.Events))
49+
depthCRs := make([]cogReader, len(events.Events))
50+
51+
for i, e := range events.Events {
52+
at := time.Date(int(e.Year), time.Month(e.Month), int(e.Day), 0, 0, 0, 0, time.UTC)
53+
cr, err := initCR(e.Depthgrid)
54+
if err != nil {
55+
panic(err)
56+
}
57+
58+
arrivalTimes[i] = at
59+
durations[i] = e.Duration
60+
depthCRs[i] = cr
61+
}
62+
63+
return jsonArrivalDepthDurationMultiHazardProvider{
64+
arrivals: arrivalTimes,
65+
depthCRs: depthCRs,
66+
durations: durations,
67+
process: ArrivalDepthAndDurationHazardFunction(),
68+
}, nil
69+
}
70+
71+
func (j jsonArrivalDepthDurationMultiHazardProvider) Close() {
72+
for _, c := range j.depthCRs {
73+
c.Close()
74+
}
75+
}
76+
77+
func (j jsonArrivalDepthDurationMultiHazardProvider) Hazard(l geography.Location) (hazards.HazardEvent, error) {
78+
var hm hazards.ArrivalDepthandDurationEventMulti
79+
for i, cr := range j.depthCRs {
80+
d, err := cr.ProvideValue(l)
81+
if err != nil {
82+
return hm, err
83+
}
84+
hd := hazards.HazardData{
85+
Depth: d,
86+
Velocity: 0,
87+
ArrivalTime: j.arrivals[i],
88+
Erosion: 0,
89+
Duration: j.durations[i],
90+
WaveHeight: 0,
91+
Salinity: false,
92+
Qualitative: "",
93+
}
94+
var h hazards.HazardEvent
95+
h, err = j.process(hd, h)
96+
if err != nil {
97+
panic(err)
98+
}
99+
hm.Append(h.(hazards.ArrivalDepthandDurationEvent))
100+
}
101+
return &hm, nil
102+
}
103+
104+
func (j jsonArrivalDepthDurationMultiHazardProvider) HazardBoundary() (geography.BBox, error) {
105+
// We'll probably want to do something different here.
106+
// Probably allow user to define study bbox with a
107+
// shapefile/geojson/directly entering bbox coords
108+
return j.depthCRs[0].GetBoundingBox()
109+
}

0 commit comments

Comments
 (0)