diff --git a/compute/simulation_test.go b/compute/simulation_test.go index fdc919c..8791c08 100644 --- a/compute/simulation_test.go +++ b/compute/simulation_test.go @@ -102,6 +102,58 @@ func Test_StreamAbstract_MultiFrequency(t *testing.T) { StreamAbstractMultiFrequency(hazardProviders, frequencies, nsp, w) } +func Test_StreamAbstract_MultiFrequencyHazard(t *testing.T) { + //initialize the NSI API structure provider + dataset := "HP" + nsp := structureprovider.InitNSISP() + + //initialize a set of frequencies + frequencies := []float64{.10, .04, .02, .01, .002} + //specify a working directory for data + //root := fmt.Sprintf("/vsis3/mmc-storage-6/nsi/Kansas_Silver_Jackets/kansas_ble/%v/", dataset) + root := fmt.Sprintf("/workspaces/Go_Consequences/data/kc_silverjackets/%v/", dataset) + //identify the depth grids to represent the frequencies. + hazardProviders := make([]hazardproviders.HazardProvider, len(frequencies)) + + hp1, err := hazardproviders.Init_CustomFunction(fmt.Sprint(root, "Depth_10pct.tif"), DepthHazardFunctionModified()) + if err != nil { + t.Fail() + } + hazardProviders[0] = hp1 + + hp2, err := hazardproviders.Init_CustomFunction(fmt.Sprint(root, "Depth_04pct.tif"), DepthHazardFunctionModified()) + if err != nil { + t.Fail() + } + hazardProviders[1] = hp2 + + hp3, err := hazardproviders.Init_CustomFunction(fmt.Sprint(root, "Depth_02pct.tif"), DepthHazardFunctionModified()) + if err != nil { + t.Fail() + } + hazardProviders[2] = hp3 + + hp4, err := hazardproviders.Init_CustomFunction(fmt.Sprint(root, "Depth_01pct.tif"), DepthHazardFunctionModified()) + if err != nil { + t.Fail() + } + hazardProviders[3] = hp4 + + hp5, err := hazardproviders.Init_CustomFunction(fmt.Sprint(root, "Depth_0_2pct.tif"), DepthHazardFunctionModified()) + if err != nil { + t.Fail() + } + hazardProviders[4] = hp5 + + //create a result writer based on the name of the depth grid. + //write local + path := fmt.Sprintf("/workspaces/Go_Consequences/data/kc_silverjackets/%v/%v_consequences_nsi.gpkg", dataset, dataset) + w, _ := resultswriters.InitSpatialResultsWriter(path, "nsi_result", "GPKG") + defer w.Close() + //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") diff --git a/hazards/coastal.go b/hazards/coastal.go index 31ea63b..0ecd95f 100644 --- a/hazards/coastal.go +++ b/hazards/coastal.go @@ -1,7 +1,9 @@ package hazards import ( + "errors" "fmt" + "sort" "time" ) @@ -106,3 +108,130 @@ func (ad CoastalEvent) Has(p Parameter) bool { adp := ad.Parameters() return adp&p != 0 } + +type MultiFrequencyCoastalEvent struct { + index int + Frequencies []float64 + Events []CoastalEvent +} + +func (h MultiFrequencyCoastalEvent) Depth() float64 { + return h.Events[h.index].Depth() +} + +func (h MultiFrequencyCoastalEvent) Velocity() float64 { + return h.Events[h.index].Velocity() +} + +func (h MultiFrequencyCoastalEvent) ArrivalTime() time.Time { + return h.Events[h.index].ArrivalTime() +} + +func (h MultiFrequencyCoastalEvent) Erosion() float64 { + return h.Events[h.index].Erosion() +} + +func (h MultiFrequencyCoastalEvent) Duration() float64 { + return h.Events[h.index].Duration() +} + +func (h MultiFrequencyCoastalEvent) WaveHeight() float64 { + return h.Events[h.index].WaveHeight() +} + +func (h MultiFrequencyCoastalEvent) Salinity() bool { + return h.Events[h.index].Salinity() +} + +func (h MultiFrequencyCoastalEvent) Qualitative() string { + return h.Events[h.index].Qualitative() +} + +func (h MultiFrequencyCoastalEvent) DV() float64 { + return h.Events[h.index].DV() +} + +func (h MultiFrequencyCoastalEvent) Frequency() float64 { + return h.Frequencies[h.index] +} + +func (h MultiFrequencyCoastalEvent) Parameters() Parameter { + return h.Events[h.index].Parameters() +} + +func (h MultiFrequencyCoastalEvent) Has(p Parameter) bool { + return h.Events[h.index].Has(p) +} + +func (h MultiFrequencyCoastalEvent) Index() int { + return h.index +} + +func (h MultiFrequencyCoastalEvent) HasNext() bool { + return h.index < (len(h.Events) - 1) +} + +func (h MultiFrequencyCoastalEvent) HasPrevious() bool { + return h.index > 0 +} + +func (h MultiFrequencyCoastalEvent) This() HazardEvent { + return h.Events[h.index] +} + +func (h MultiFrequencyCoastalEvent) Next() (HazardEvent, error) { + var err error = nil + if h.HasNext() { + return h.Events[h.index+1], err + } else { + return ArrivalDepthandDurationEvent{}, errors.New("hazards: MultiFrequencyCoastalEvent does not have Next event") + } +} + +func (h MultiFrequencyCoastalEvent) Previous() (HazardEvent, error) { + var err error = nil + if h.HasPrevious() { + return h.Events[h.index-1], err + } else { + return ArrivalDepthandDurationEvent{}, errors.New("hazards: MultiFrequencyCoastalEvent does not have Previous event") + } +} + +func (h *MultiFrequencyCoastalEvent) Increment() { + if h.HasNext() { + h.index++ + } +} + +func (h *MultiFrequencyCoastalEvent) ResetIndex() { + h.index = 0 +} + +func (h *MultiFrequencyCoastalEvent) Append(n HazardEvent) { + newEvent := n.(CoastalEvent) + h.Events = append(h.Events, newEvent) +} + +func (h MultiFrequencyCoastalEvent) Sort() { // ensure the hazard events are in order of arrival time + sort.Sort(h) +} + +func (h MultiFrequencyCoastalEvent) IsSorted() bool { + return sort.IsSorted(h) +} + +// Len is part of sort.Interface. +func (h MultiFrequencyCoastalEvent) Len() int { + return len(h.Events) +} + +// Swap is part of sort.Interface. +func (h MultiFrequencyCoastalEvent) Swap(i, j int) { + h.Events[i], h.Events[j] = h.Events[j], h.Events[i] +} + +// Less is part of sort.Interface +func (h MultiFrequencyCoastalEvent) Less(i, j int) bool { + return h.Frequencies[i] < h.Frequencies[j] // This means the 500-year flood is "Less" than the 100-year event because we are sorting on frequency + +} diff --git a/hazards/flood.go b/hazards/flood.go index e099a03..b8a3cfb 100644 --- a/hazards/flood.go +++ b/hazards/flood.go @@ -571,3 +571,134 @@ func (h ArrivalDepthandDurationEventMulti) Swap(i, j int) { func (h ArrivalDepthandDurationEventMulti) Less(i, j int) bool { return h.Events[i].ArrivalTime().Before(h.Events[j].ArrivalTime()) } + +type DepthEventMultiFrequency struct { + index int + Frequencies []float64 + Events []DepthEvent +} + +func (h DepthEventMultiFrequency) Depth() float64 { + return h.Events[h.index].Depth() +} + +func (h DepthEventMultiFrequency) Velocity() float64 { + return h.Events[h.index].Velocity() +} + +func (h DepthEventMultiFrequency) ArrivalTime() time.Time { + return h.Events[h.index].ArrivalTime() +} + +func (h DepthEventMultiFrequency) Erosion() float64 { + return h.Events[h.index].Erosion() +} + +func (h DepthEventMultiFrequency) Duration() float64 { + return h.Events[h.index].Duration() +} + +func (h DepthEventMultiFrequency) WaveHeight() float64 { + return h.Events[h.index].WaveHeight() +} + +func (h DepthEventMultiFrequency) Salinity() bool { + return h.Events[h.index].Salinity() +} + +func (h DepthEventMultiFrequency) Qualitative() string { + return h.Events[h.index].Qualitative() +} + +func (h DepthEventMultiFrequency) DV() float64 { + return h.Events[h.index].DV() +} + +func (h DepthEventMultiFrequency) Parameters() Parameter { + return h.Events[h.index].Parameters() +} + +func (h DepthEventMultiFrequency) Has(p Parameter) bool { + return h.Events[h.index].Has(p) +} + +func (h DepthEventMultiFrequency) Index() int { + return h.index +} + +func (h DepthEventMultiFrequency) HasNext() bool { + return h.index < (len(h.Events) - 1) +} + +func (h DepthEventMultiFrequency) HasPrevious() bool { + return h.index > 0 +} + +func (h DepthEventMultiFrequency) This() HazardEvent { + return h.Events[h.index] +} + +func (h DepthEventMultiFrequency) 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 DepthEventMultiFrequency) 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 *DepthEventMultiFrequency) Increment() { + if h.HasNext() { + h.index++ + } +} + +func (h *DepthEventMultiFrequency) ResetIndex() { + h.index = 0 +} + +func (h *DepthEventMultiFrequency) Append(n HazardEvent) { + newEvent := n.(DepthEvent) + h.Events = append(h.Events, newEvent) +} + +func (h DepthEventMultiFrequency) Sort() { // ensure the hazard events are in order of arrival time + sort.Sort(h) +} + +func (h DepthEventMultiFrequency) IsSorted() bool { + return sort.IsSorted(h) +} + +// Len is part of sort.Interface. +func (h DepthEventMultiFrequency) Len() int { + return len(h.Events) +} + +// Swap is part of sort.Interface. +func (h DepthEventMultiFrequency) Swap(i, j int) { + h.Events[i], h.Events[j] = h.Events[j], h.Events[i] +} + +// Less is part of sort.Interface +func (h DepthEventMultiFrequency) Less(i, j int) bool { + // Sort order is most to least frequent + return h.Frequencies[i] > h.Frequencies[j] +} + +func (h *DepthEventMultiFrequency) SetIndex(i int) error { + if i < (len(h.Events) - 1) { + h.index = i + return nil + } + return errors.New("hazards: Attempted to set out of bounds index on DepthEventMultiFrequency event.") +} diff --git a/hazards/interfaces.go b/hazards/interfaces.go index 3255115..e644b89 100644 --- a/hazards/interfaces.go +++ b/hazards/interfaces.go @@ -25,6 +25,28 @@ type HazardEvent interface { Parameters() Parameter Has(p Parameter) bool } + +type MultiHazardEvent interface { + HazardEvent + Index() int + HasNext() bool + HasPrevious() bool + This() HazardEvent + Next() (HazardEvent, error) + Previous() (HazardEvent, error) + Increment() + ResetIndex() + Append(HazardEvent) + Sort() + IsSorted() bool +} + +type MultiFrequencyHazardEvent interface { + MultiHazardEvent + SetIndex(index int) error + Frequencies() []float64 +} + type HazardData struct { Depth float64 Velocity float64 @@ -233,23 +255,3 @@ func (p *Parameter) UnmarshalJSON(b []byte) error { *p = toParameter(s) return nil } - -type MultiHazardEvent interface { - HazardEvent - Index() int - HasNext() bool - HasPrevious() bool - This() HazardEvent - Next() (HazardEvent, error) - Previous() (HazardEvent, error) - Increment() - ResetIndex() - Append(HazardEvent) - Sort() - IsSorted() bool -} - -type MultiHazardFrequencyEvent interface { - MultiHazardEvent - Frequency() float64 -}