1package events
  2
  3import (
  4	"ewdetect/config"
  5	"ewdetect/locate"
  6	"ewdetect/stations"
  7	"math"
  8	"strings"
  9	"time"
 10
 11	"github.com/rs/zerolog/log"
 12)
 13
 14var Events []*Event
 15
 16type Detection struct {
 17	PWaveArrival time.Time
 18	SWaveArrival time.Time
 19}
 20
 21type Event struct {
 22	FirstDetectionLat      float64 //rad
 23	FirstDetectionLon      float64 //rad
 24	FirstPWaveDetection    time.Time
 25	Detections             map[string]Detection
 26	LastPWaveArrival       time.Time
 27	FinalConclusionReached bool
 28}
 29
 30func IsEventOver(time time.Time, index int) bool {
 31	return time.Sub(Events[index].LastPWaveArrival) > config.EventTimeout
 32}
 33
 34func FinalConclusionCheck(index int) {
 35	if IsEventOver(time.Now(), index) {
 36		if !Events[index].FinalConclusionReached {
 37			Events[index].FinalConclusionReached = true
 38			log.Info().Msgf("Final conclusion reached for event %d", index)
 39			Predict(index, true)
 40		}
 41	}
 42}
 43
 44func Predict(index int, finalPrediction bool) {
 45	log.Info().Int("index", index).Bool("isFinalPrediction", finalPrediction).Msg("Predicting")
 46	formattedObservationList := []locate.Observation{}
 47	for detection := range Events[index].Detections {
 48		currentDetection := Events[index].Detections[detection]
 49		splitString := strings.Split(detection, "@")
 50		connection := splitString[0]
 51		stationID := splitString[1]
 52		formattedObservationList = append(formattedObservationList, locate.Observation{
 53			StationName:  detection,
 54			Lat:          (*stations.Stations[connection])[stationID].Lat * math.Pi / 180,
 55			Lon:          (*stations.Stations[connection])[stationID].Lon * math.Pi / 180,
 56			PWaveArrival: Events[index].FirstPWaveDetection.Sub(currentDetection.PWaveArrival).Seconds(),
 57			SWaveArrival: Events[index].FirstPWaveDetection.Sub(currentDetection.SWaveArrival).Seconds(),
 58		})
 59	}
 60	if len(formattedObservationList) >= config.NumberOfDetectionsThreshold {
 61		log.Debug().Interface("observations", formattedObservationList).Msg("Formatted observation list")
 62		eventName := GetEventName(index)
 63		finalGuess := locate.NelderMeadOptimization(eventName, &formattedObservationList, finalPrediction)
 64		dateOfEarthquake := Events[index].FirstPWaveDetection.Add(time.Duration(int64(finalGuess.Epoch) * 1e9))
 65
 66		guessType := "Partial Earthquake Guess"
 67		if finalPrediction {
 68			guessType = "Final Earthquake Guess"
 69		}
 70
 71		log.Info().
 72			Str("type", guessType).
 73			Int("detections", len(Events[index].Detections)).
 74			Str("date", dateOfEarthquake.Format("2006-01-02T15:04:05.000")).
 75			Float64("latitude", finalGuess.Lat*180/math.Pi).
 76			Float64("longitude", finalGuess.Lon*180/math.Pi).
 77			Float64("depth_km", finalGuess.Depth).
 78			Msg("Earthquake prediction")
 79	}
 80}
 81
 82func GetEventName(index int) string {
 83	return Events[index].FirstPWaveDetection.Format("2006-01-02T15:04:05.000")
 84}
 85
 86func NewDetection(connection, stationID string, pWaveArrival, sWaveArrival time.Time) (string, bool) {
 87	stationLat := (*stations.Stations[connection])[stationID].Lat * math.Pi / 180
 88	stationLon := (*stations.Stations[connection])[stationID].Lon * math.Pi / 180
 89	groupableEvent := false
 90	var index int
 91	for i, event := range Events {
 92		if locate.GreatCircleAngle(event.FirstDetectionLat, event.FirstDetectionLon, stationLat, stationLon) < config.EventExtent && !IsEventOver(pWaveArrival, i) {
 93			groupableEvent = true
 94			index = i
 95			log.Debug().Int("event_index", i).Msg("Found groupable event")
 96			break
 97		}
 98	}
 99	if !groupableEvent {
100		Events = append(Events, &Event{
101			FirstDetectionLat:      stationLat,
102			FirstDetectionLon:      stationLon,
103			FirstPWaveDetection:    pWaveArrival,
104			Detections:             make(map[string]Detection),
105			LastPWaveArrival:       pWaveArrival,
106			FinalConclusionReached: false,
107		})
108		index = len(Events) - 1
109		log.Info().
110			Int("event_index", index).
111			Float64("lat", stationLat*180/math.Pi).
112			Float64("lon", stationLon*180/math.Pi).
113			Msg("Created new event")
114	}
115
116	_, ok := Events[index].Detections[connection+"@"+stationID]
117	if !ok {
118		Events[index].LastPWaveArrival = pWaveArrival
119		go FinalConclusionCheck(index)
120	}
121	Events[index].Detections[connection+"@"+stationID] = Detection{
122		PWaveArrival: pWaveArrival,
123		SWaveArrival: sWaveArrival,
124	}
125
126	Predict(index, false)
127	return GetEventName(index), !ok
128}