Skip to content

Commit

Permalink
feat: add a deltadb version of the dart-config app
Browse files Browse the repository at this point in the history
This aims to use the sql database for dart configuration
  • Loading branch information
ozym committed Jan 18, 2025
1 parent bbe0fc2 commit ade0a47
Show file tree
Hide file tree
Showing 4 changed files with 438 additions and 0 deletions.
47 changes: 47 additions & 0 deletions cmd/dart-db-config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package main

import (
"encoding/json"
"io"
"time"
)

// Constituent values need by the de-tiding algorithm
type Constituent struct {
Name string `json:"name"`
Number int `json:"number"`
Amplitude float64 `json:"amplitude"`
Lag float64 `json:"lag"`
}

// Detide parameters need by the de-tiding algorithm
type Detide struct {
TimeZone float64 `json:"timezone"`
Latitude float64 `json:"latitude"`

Constituents []Constituent `json:"constituents,omitempty"`
}

// Deployment documents an individual DART operational period with optional de-tiding parameters.
type Deployment struct {
Network string `json:"network"`
Buoy string `json:"buoy"`
Location string `json:"location"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
Depth float64 `json:"depth"`
Detide *Detide `json:"detide,omitempty"`
TimingCorrection time.Duration `json:"timing-correction,omitempty"`
Start time.Time `json:"start"`
End time.Time `json:"end"`
}

func Encode(wr io.Writer, d []Deployment) error {

// build an encoder
enc := json.NewEncoder(wr)
enc.SetIndent("", " ")

// do the encoding
return enc.Encode(d)
}
116 changes: 116 additions & 0 deletions cmd/dart-db-config/detide.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package main

import (
"context"
"time"

"github.com/GeoNet/delta"
)

func QueryDetide(db *delta.DB, buoy string, on, off time.Time) (*Detide, error) {

detide, err := QueryGauge(db, buoy, on, off)
if err != nil {
return nil, err
}

constituents, err := QueryConsituents(db, buoy, on, off)
if err != nil {
return nil, err
}

detide.Constituents = constituents

return detide, nil
}

func QueryGauge(db *delta.DB, buoy string, on, off time.Time) (*Detide, error) {

ctx := context.Background()

query := `
SELECT
gauge.analysis_time_zone,
gauge.analysis_latitude
FROM
gauge
WHERE
gauge.gauge = ?
AND
datetime(gauge.end_date) > ?
AND
datetime(gauge.start_date) <= ?
LIMIT 1
`
stmt, err := db.PrepareContext(ctx, query)
if err != nil {
return nil, err
}
defer stmt.Close()

row := stmt.QueryRowContext(ctx, buoy, on, off)

var detide Detide
if err := row.Scan(
&detide.TimeZone,
&detide.Latitude,
); err != nil {
return nil, err
}

return &detide, nil
}

// Find constituent values need by the de-tiding algorithm
func QueryConsituents(db *delta.DB, buoy string, on, off time.Time) ([]Constituent, error) {

ctx := context.Background()

query := `
SELECT
constituent.constituent,
constituent.number,
constituent.amplitude,
constituent.lag
FROM
constituent
INNER JOIN gauge ON gauge.gauge_id = constituent.gauge_id
WHERE
gauge.gauge = ? AND
datetime(constituent.end_date) > ? AND
datetime(constituent.start_date) <= ?
ORDER BY
CAST(constituent.number AS INTEGER)
;`
stmt, err := db.PrepareContext(ctx, query)
if err != nil {
return nil, err
}
defer stmt.Close()

results, err := stmt.QueryContext(ctx, buoy, on, off)
if err != nil {
return nil, err
}
defer results.Close()

constituents := make([]Constituent, 0)
for results.Next() {
var constituent Constituent
if err := results.Scan(
&constituent.Name,
&constituent.Number,
&constituent.Amplitude,
&constituent.Lag,
); err != nil {
return nil, err
}
constituents = append(constituents, constituent)
}

if err := results.Err(); err != nil {
return nil, err
}

return constituents, nil
}
109 changes: 109 additions & 0 deletions cmd/dart-db-config/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package main

import (
"flag"
"fmt"
"log"
"os"

"github.com/GeoNet/delta"
)

type Settings struct {
path string // delta database file
network string // dart buoy network code
output string // optional output file
}

func main() {

var settings Settings

flag.Usage = func() {
fmt.Fprintf(os.Stderr, "\n")
fmt.Fprintf(os.Stderr, "Build a dart deployment config file\n")
fmt.Fprintf(os.Stderr, "\n")
fmt.Fprintf(os.Stderr, "Usage:\n")
fmt.Fprintf(os.Stderr, "\n")
fmt.Fprintf(os.Stderr, " %s [options]\n", os.Args[0])
fmt.Fprintf(os.Stderr, "\n")
fmt.Fprintf(os.Stderr, "Options:\n")
fmt.Fprintf(os.Stderr, "\n")
flag.PrintDefaults()
fmt.Fprintf(os.Stderr, "\n")
}

flag.StringVar(&settings.path, "path", "delta.db", "delta database file")
flag.StringVar(&settings.network, "network", "TD", "dart buoy network code")
flag.StringVar(&settings.output, "output", "", "output dart configuration file")

flag.Parse()

db, err := delta.NewDB(settings.path)
if err != nil {
log.Fatalf("unable to read delta db: %v", err)
}

sites, err := QuerySites(db, settings.network)
if err != nil {
log.Fatalf("unable to query delta db: %v", err)
}

// avoids the json null
deployments := make([]Deployment, 0)

for _, site := range sites {

// get the site detiding details
detide, err := QueryDetide(db, site.Buoy, site.Start, site.End)
if err != nil {
log.Fatalf("unable to query delta db: %v", err)
}

// will be sorted as per delta
deployments = append(deployments, Deployment{
Network: site.Network,
Buoy: site.Buoy,
Location: site.Location,
Latitude: site.Latitude,
Longitude: site.Longitude,
Detide: detide,
Depth: site.Depth,
TimingCorrection: site.Correction,
Start: site.Start,
End: site.End,
})

//TODO: remove for production deployment
// for completeness do it again!
deployments = append(deployments, Deployment{
Network: site.Network,
Buoy: site.Buoy,
Location: site.Location,
Latitude: site.Latitude,
Longitude: site.Longitude,
Detide: detide,
Depth: site.Depth,
TimingCorrection: site.Correction,
Start: site.Start,
End: site.End,
})
}

switch {
case settings.output != "":
file, err := os.Create(settings.output)
if err != nil {
log.Fatalf("unable to create output file %q: %v", settings.output, err)
}
defer file.Close()

if err := Encode(file, deployments); err != nil {
log.Fatalf("unable to write output to %q: %v", settings.output, err)
}
default:
if err := Encode(os.Stdout, deployments); err != nil {
log.Fatalf("unable to write output: %v", err)
}
}
}
Loading

0 comments on commit ade0a47

Please sign in to comment.