Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
24 changes: 24 additions & 0 deletions compute/simulation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,30 @@ func Test_StreamAbstract_MultiFrequency(t *testing.T) {
//compute consequences.
StreamAbstractMultiFrequency(hazardProviders, frequencies, nsp, w)
}

func Test_StreamAbstract_MultiHazard(t *testing.T) {
//initialize the NSI API structure provider
nsp := structureprovider.InitNSISPwithOcctypeFilePath("/workspaces/go-consequences/data/lifecycle/occtypes_reconstruction.json")
now := time.Now()
fmt.Println(now)

root := "/workspaces/go-consequences/data/lifecycle/"
filepath := root + "test_arrival-depth-duration_hazards.json"
w, _ := resultswriters.InitSpatialResultsWriter(root+"multihazardtest_consequences.json", "results", "GeoJSON")
//w := consequences.InitSummaryResultsWriterFromFile(root + "_consequences_SUMMARY.json")
//create a result writer based on the name of the depth grid.
//w, _ := resultswriters.InitGpkResultsWriter(root+"_consequences_nsi.gpkg", "nsi_result")
defer w.Close()
//initialize a hazard provider based on the depth grid.
dfr, err := hazardproviders.InitADDMHP(filepath)
if err != nil {
panic(err)
}
//compute consequences.
StreamAbstract(dfr, nsp, w)
fmt.Println(time.Since(now))
}

func Test_Config(t *testing.T) {
config := Config{
StructureProviderInfo: structureprovider.StructureProviderInfo{
Expand Down
19 changes: 19 additions & 0 deletions hazardproviders/interfaces.go
Copy link
Contributor

Choose a reason for hiding this comment

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

huh. did you write this code? it is a pretty neat idea.

Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ func ArrivalAndDurationHazardFunction() HazardFunction {
}
}

func ArrivalDepthAndDurationHazardFunction() HazardFunction {
return func(valueIn hazards.HazardData, hazard hazards.HazardEvent) (hazards.HazardEvent, error) {
d := hazards.ArrivalDepthandDurationEvent{}
d.SetDepth(valueIn.Depth)
d.SetDuration(valueIn.Duration)
d.SetArrivalTime(valueIn.ArrivalTime)
return d, nil
}
}

func DepthAndDurationHazardFunction() HazardFunction {
return func(valueIn hazards.HazardData, hazard hazards.HazardEvent) (hazards.HazardEvent, error) {
d := hazards.ArrivalDepthandDurationEvent{}
d.SetDepth(valueIn.Depth)
d.SetDuration(valueIn.Duration)
return d, nil
}
}

// NoHazardFoundError is an error for a situation where no hazard could be computed for the given args
type NoHazardFoundError struct {
Input string
Expand Down
106 changes: 106 additions & 0 deletions hazardproviders/json_multi_hazard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package hazardproviders

import (
"encoding/json"
"fmt"
"os"
"time"

"github.com/USACE/go-consequences/geography"
"github.com/USACE/go-consequences/hazards"
)

type jsonArrivalDepthDurationMultiHazardProvider struct {
arrivals []time.Time
depthCRs []cogReader
durations []float64
process HazardFunction
}

type ADDProperties struct { // will try to not use this
Year float64 `json:"year"`
Month float64 `json:"month"`
Day float64 `json:"day"`
Depth float64 `json:"depth"`
Depthgrid string `json:"depthgrid"`
Duration float64 `json:"duration"`
Xmin float64 `json:"xmin"`
Xmax float64 `json:"xmax"`
Ymin float64 `json:"ymin"`
Ymax float64 `json:"ymax"`
}

type ADDEvents struct {
Events []ADDProperties `json:"events"`
}

func InitADDMHP(fp string) (jsonArrivalDepthDurationMultiHazardProvider, error) {
fmt.Println("Connecting to: " + fp)
c, err := os.ReadFile(fp)
if err != nil {
panic(err)
}

var events ADDEvents
json.Unmarshal(c, &events)

arrivalTimes := make([]time.Time, len(events.Events))
durations := make([]float64, len(events.Events))
depthCRs := make([]cogReader, len(events.Events))

for i, e := range events.Events {
at := time.Date(int(e.Year), time.Month(e.Month), int(e.Day), 0, 0, 0, 0, time.UTC)
cr, err := initCR(e.Depthgrid)
if err != nil {
panic(err)
}

arrivalTimes[i] = at
durations[i] = e.Duration
depthCRs[i] = cr
}

return jsonArrivalDepthDurationMultiHazardProvider{
arrivals: arrivalTimes,
depthCRs: depthCRs,
durations: durations,
process: ArrivalDepthAndDurationHazardFunction(),
}, nil
}

func (j jsonArrivalDepthDurationMultiHazardProvider) Close() {
for _, c := range j.depthCRs {
c.Close()
}
}

func (j jsonArrivalDepthDurationMultiHazardProvider) Hazard(l geography.Location) (hazards.HazardEvent, error) {
var hm hazards.ArrivalDepthandDurationEventMulti
for i, cr := range j.depthCRs {
d, err := cr.ProvideValue(l)
if err != nil {
return hm, err
}
hd := hazards.HazardData{
Depth: d,
Velocity: 0,
ArrivalTime: j.arrivals[i],
Erosion: 0,
Duration: j.durations[i],
WaveHeight: 0,
Salinity: false,
Qualitative: "",
}
var h hazards.HazardEvent
h, err = j.process(hd, h)
hm.Append(h.(hazards.ArrivalDepthandDurationEvent))
}
return &hm, nil
}

func (j jsonArrivalDepthDurationMultiHazardProvider) HazardBoundary() (geography.BBox, error) {
// We'll probably want to do something different here.
// Probably allow user to define study bbox with a
// shapefile/geojson/directly entering bbox coords
return j.depthCRs[0].GetBoundingBox()
}
42 changes: 42 additions & 0 deletions hazardproviders/json_multi_hazard_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package hazardproviders

import (
"fmt"
"testing"

"github.com/USACE/go-consequences/geography"
"github.com/USACE/go-consequences/hazards"
)

func TestInitADDMHP(t *testing.T) {
file := "/workspaces/go-consequences/data/lifecycle/test_arrival-depth-duration_hazards.json"

ADDMHP, err := InitADDMHP(file)
if err != nil {
panic(err)
}

loc := geography.Location{
X: -71.481,
Y: 43.001,
SRID: "",
}

haz, err := ADDMHP.Hazard(loc)
h := haz.(hazards.ArrivalDepthandDurationEventMulti)
if err != nil {
panic(err)
}

for {
fmt.Printf(
"%d: Depth: %3.2f, Duration: %3.2f, Arrival: %v\n",
h.Index(), h.Depth(), h.Duration(), h.ArrivalTime(),
)
if h.HasNext() {
h.Increment()
} else {
break
}
}
}
124 changes: 124 additions & 0 deletions hazards/flood.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package hazards

import (
"errors"
"fmt"
"sort"
"strings"
"time"
)
Expand Down Expand Up @@ -443,3 +445,125 @@ func (d MultiParameterEvent) MarshalJSON() ([]byte, error) {
s += "}}"
return []byte(s), nil
}

// ArrivalandDurationEventMulti describes a series of events with an arrival time, depth and a duration in days
type ArrivalDepthandDurationEventMulti struct {
index int
Events []ArrivalDepthandDurationEvent
}

func (h ArrivalDepthandDurationEventMulti) Depth() float64 {
return h.Events[h.index].Depth()
}

func (h ArrivalDepthandDurationEventMulti) Velocity() float64 {
return h.Events[h.index].Velocity()
}

func (h ArrivalDepthandDurationEventMulti) ArrivalTime() time.Time {
return h.Events[h.index].ArrivalTime()
}

func (h ArrivalDepthandDurationEventMulti) Erosion() float64 {
return h.Events[h.index].Erosion()
}

func (h ArrivalDepthandDurationEventMulti) Duration() float64 {
return h.Events[h.index].Duration()
}

func (h ArrivalDepthandDurationEventMulti) WaveHeight() float64 {
return h.Events[h.index].WaveHeight()
}

func (h ArrivalDepthandDurationEventMulti) Salinity() bool {
return h.Events[h.index].Salinity()
}

func (h ArrivalDepthandDurationEventMulti) Qualitative() string {
return h.Events[h.index].Qualitative()
}

func (h ArrivalDepthandDurationEventMulti) DV() float64 {
return h.Events[h.index].DV()
}

func (h ArrivalDepthandDurationEventMulti) Parameters() Parameter {
return h.Events[h.index].Parameters()
}

func (h ArrivalDepthandDurationEventMulti) Has(p Parameter) bool {
return h.Events[h.index].Has(p)
}

func (h ArrivalDepthandDurationEventMulti) Index() int {
return h.index
}

func (h ArrivalDepthandDurationEventMulti) HasNext() bool {
return h.index < (len(h.Events) - 1)
}

func (h ArrivalDepthandDurationEventMulti) HasPrevious() bool {
return h.index > 0
}

func (h ArrivalDepthandDurationEventMulti) This() HazardEvent {
return h.Events[h.index]
}

func (h ArrivalDepthandDurationEventMulti) Next() (HazardEvent, error) {
var err error = nil
if h.HasNext() {
return h.Events[h.index+1], err
} else {
return ArrivalDepthandDurationEvent{}, errors.New("hazards: ArrivalDepthandDurationEventMulti does not have Next event")
}
}

func (h ArrivalDepthandDurationEventMulti) Previous() (HazardEvent, error) {
var err error = nil
if h.HasPrevious() {
return h.Events[h.index-1], err
} else {
return ArrivalDepthandDurationEvent{}, errors.New("hazards: ArrivalDepthandDurationEventMulti does not have Previous event")
}
}

func (h *ArrivalDepthandDurationEventMulti) Increment() {
if h.HasNext() {
h.index++
}
}

func (h *ArrivalDepthandDurationEventMulti) ResetIndex() {
h.index = 0
}

func (h *ArrivalDepthandDurationEventMulti) Append(n HazardEvent) {
newEvent := n.(ArrivalDepthandDurationEvent)
h.Events = append(h.Events, newEvent)
}

func (h ArrivalDepthandDurationEventMulti) Sort() { // ensure the hazard events are in order of arrival time
sort.Sort(h)
}

func (h ArrivalDepthandDurationEventMulti) IsSorted() bool {
return sort.IsSorted(h)
}

// Len is part of sort.Interface.
func (h ArrivalDepthandDurationEventMulti) Len() int {
return len(h.Events)
}

// Swap is part of sort.Interface.
func (h ArrivalDepthandDurationEventMulti) Swap(i, j int) {
h.Events[i], h.Events[j] = h.Events[j], h.Events[i]
}

// Less is part of sort.Interface
func (h ArrivalDepthandDurationEventMulti) Less(i, j int) bool {
return h.Events[i].ArrivalTime().Before(h.Events[j].ArrivalTime())
}
Loading