Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CSV output for snapshot table observers #45

Merged
merged 1 commit into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions _examples/base/observers.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
"File": "out/WorkerCohorts.csv"
}
],
"StepTables": [
{
"Observer": "obs.ForagingStats",
"File": "out/ForagingStats.csv"
}
],
"TimeSeriesPlots": [
{
"Observer": "obs.WorkerCohorts",
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.22.0
require (
github.com/gopxl/pixel/v2 v2.1.0
github.com/mlange-42/arche v0.13.0
github.com/mlange-42/arche-model v0.8.2-0.20240521193509-06db52d11180
github.com/mlange-42/arche-model v0.8.2-0.20240523143440-11595cc41e11
github.com/mlange-42/arche-pixel v0.9.1-0.20240523102310-958292ff764d
github.com/mlange-42/beecs v0.1.1-0.20240523095106-c543d24d7f9e
github.com/spf13/cobra v1.8.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ github.com/mazznoer/csscolorparser v0.1.2 h1:/UBHuQg792ePmGFzTQAC9u+XbFr7/HzP/Gj
github.com/mazznoer/csscolorparser v0.1.2/go.mod h1:Aj22+L/rYN/Y6bj3bYqO3N6g1dtdHtGfQ32xZ5PJQic=
github.com/mlange-42/arche v0.13.0 h1:ef0fu9qC2KIr8wIlVs+CgeQ5CSUJ8A1Hut6nXYdf+xk=
github.com/mlange-42/arche v0.13.0/go.mod h1:bFktKnvGDj2kP01xar79z0hKwGHdnoaEZR8HWmJkIyU=
github.com/mlange-42/arche-model v0.8.2-0.20240521193509-06db52d11180 h1:R1u8Xj5uG6jwCv0r3eIbhd8SHs9uLbA5vJ0sjxjCWZY=
github.com/mlange-42/arche-model v0.8.2-0.20240521193509-06db52d11180/go.mod h1:5Pzd3iAgdGNTiMgFJxHdc6a7qoaQPBK9xmyhrKTMmV8=
github.com/mlange-42/arche-model v0.8.2-0.20240523143440-11595cc41e11 h1:NfP5jwtHUcqLbYYPJd8pSfihHV0fx6YUyhWl9R6c3Yo=
github.com/mlange-42/arche-model v0.8.2-0.20240523143440-11595cc41e11/go.mod h1:5Pzd3iAgdGNTiMgFJxHdc6a7qoaQPBK9xmyhrKTMmV8=
github.com/mlange-42/arche-pixel v0.9.1-0.20240523102310-958292ff764d h1:RWHbjBrDtb/YJVdOc1/jd5hLPUBfLqxf/AXuKqD1gbI=
github.com/mlange-42/arche-pixel v0.9.1-0.20240523102310-958292ff764d/go.mod h1:UWr4ZfpvreTRWr76dqi30VCax19kEbiSDSNrbZTbMDQ=
github.com/mlange-42/beecs v0.1.1-0.20240523095106-c543d24d7f9e h1:IG6UGhcUyptr+R3U+T2UbN0WOqLM1A2CzWddM5pt2JI=
Expand Down
26 changes: 24 additions & 2 deletions internal/run/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ func runModel(

result := util.Tables{
Index: idx,
Headers: make([][]string, len(obs.Tables)+1),
Data: make([][][]float64, len(obs.Tables)+1),
Headers: make([][]string, len(obs.Tables)+len(obs.StepTables)+1),
Data: make([][][]float64, len(obs.Tables)+len(obs.StepTables)+1),
}

now := time.Now().UnixMilli()
Expand Down Expand Up @@ -91,6 +91,28 @@ func runModel(
m.AddSystem(t)
}

offset := len(obs.Tables)
for i, t := range obs.StepTables {
t.HeaderCallback = func(header []string) {
h := make([]string, len(header)+2)
h[0] = "Run"
h[1] = "Ticks"
copy(h[2:], header)
result.Headers[offset+i+1] = h
}
t.Callback = func(step int, table [][]float64) {
for _, row := range table {
data := make([]float64, len(row)+2)
data[0] = float64(idx)
data[1] = float64(step)
copy(data[2:], row)

result.Data[offset+i+1] = append(result.Data[offset+i+1], data)
}
}
m.AddSystem(t)
}

if !noUi {
for _, p := range obs.Windows {
m.AddUISystem(p)
Expand Down
3 changes: 3 additions & 0 deletions internal/run/parallel.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ func RunParallel(
for _, t := range observers.Tables {
files = append(files, path.Join(dir, t.File))
}
for _, t := range observers.StepTables {
files = append(files, path.Join(dir, t.File))
}
writer, err := util.NewCsvWriter(files, observers.CsvSeparator)
if err != nil {
return err
Expand Down
3 changes: 3 additions & 0 deletions internal/run/sequential.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ func RunSequential(
for _, t := range observers.Tables {
files = append(files, path.Join(dir, t.File))
}
for _, t := range observers.StepTables {
files = append(files, path.Join(dir, t.File))
}
writer, err := util.NewCsvWriter(files, observers.CsvSeparator)
if err != nil {
return err
Expand Down
63 changes: 56 additions & 7 deletions internal/util/observers.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ func (e *entry) UnmarshalJSON(jsonData []byte) error {
}

type Observers struct {
Windows []*window.Window
Tables []*reporter.Callback
Windows []*window.Window
Tables []*reporter.RowCallback
StepTables []*reporter.TableCallback
}

type TimeSeriesPlotDef struct {
Expand Down Expand Up @@ -60,6 +61,14 @@ type TableDef struct {
Final bool
}

type StepTableDef struct {
File string
Observer string
Params entry
UpdateInterval int
Final bool
}

type ViewDef struct {
Drawer string
Params entry
Expand All @@ -76,6 +85,7 @@ type ObserversDef struct {
LinePlots []LinePlotDef // Live line plots.
Views []ViewDef // Live views.
Tables []TableDef // CSV output with one row per update.
StepTables []StepTableDef // CSV output with a full table per update.
}

func (obs *ObserversDef) CreateObservers(withUI bool) (Observers, error) {
Expand Down Expand Up @@ -105,9 +115,15 @@ func (obs *ObserversDef) CreateObservers(withUI bool) (Observers, error) {
return Observers{}, err
}

stepTables, err := createStepTables(obs.StepTables)
if err != nil {
return Observers{}, err
}

return Observers{
Windows: windows,
Tables: tables,
Windows: windows,
Tables: tables,
StepTables: stepTables,
}, nil
}

Expand Down Expand Up @@ -228,8 +244,8 @@ func createViews(views []ViewDef) ([]*window.Window, error) {
return windows, nil
}

func createTables(tabs []TableDef) ([]*reporter.Callback, error) {
tables := []*reporter.Callback{}
func createTables(tabs []TableDef) ([]*reporter.RowCallback, error) {
tables := []*reporter.RowCallback{}
for _, t := range tabs {
tp, ok := registry.GetObserver(t.Observer)
if !ok {
Expand All @@ -248,7 +264,7 @@ func createTables(tabs []TableDef) ([]*reporter.Callback, error) {
if !ok {
return nil, fmt.Errorf("type '%s' is not a Row observer", tp.String())
}
rep := &reporter.Callback{
rep := &reporter.RowCallback{
Observer: obsCast,
UpdateInterval: t.UpdateInterval,
HeaderCallback: func(header []string) {},
Expand All @@ -260,3 +276,36 @@ func createTables(tabs []TableDef) ([]*reporter.Callback, error) {

return tables, nil
}

func createStepTables(tabs []StepTableDef) ([]*reporter.TableCallback, error) {
tables := []*reporter.TableCallback{}
for _, t := range tabs {
tp, ok := registry.GetObserver(t.Observer)
if !ok {
return nil, fmt.Errorf("observer type '%s' is not registered", t.Observer)
}
observerVal := reflect.New(tp).Interface()
if len(t.Params.Bytes) == 0 {
t.Params.Bytes = []byte("{}")
}
decoder := json.NewDecoder(bytes.NewReader(t.Params.Bytes))
decoder.DisallowUnknownFields()
if err := decoder.Decode(&observerVal); err != nil {
return nil, err
}
obsCast, ok := observerVal.(observer.Table)
if !ok {
return nil, fmt.Errorf("type '%s' is not a Table observer", tp.String())
}
rep := &reporter.TableCallback{
Observer: obsCast,
UpdateInterval: t.UpdateInterval,
HeaderCallback: func(header []string) {},
Callback: func(step int, row [][]float64) {},
Final: t.Final,
}
tables = append(tables, rep)
}

return tables, nil
}
Loading