Skip to content

Commit

Permalink
Rework CLI for a simpler syntax when using default file names (#29)
Browse files Browse the repository at this point in the history
* rework CLI for simpler syntax
* rename flag `speed`, update README
* fix CI tests for examples
  • Loading branch information
mlange-42 authored May 20, 2024
1 parent 9ffa8d2 commit 9505e7a
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 28 deletions.
14 changes: 7 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ jobs:
go get ./...
- name: Run examples 1
run: |
xvfb-run --auto-servernum --server-num=1 go run . -s 120 -d _examples/base -x params.Termination.MaxTicks=365
go run . -r 5 -d _examples/base -e experiment.json -x params.Termination.MaxTicks=365
xvfb-run --auto-servernum --server-num=1 go run . -s 120 -d _examples/patches -x params.Termination.MaxTicks=365
xvfb-run --auto-servernum --server-num=1 go run . -s 120 -d _examples/weather_file -x params.Termination.MaxTicks=730
xvfb-run --auto-servernum --server-num=1 go run . -s 120 -d _examples/weather_builtin -x params.Termination.MaxTicks=730
xvfb-run --auto-servernum --server-num=1 go run . -s 120 -d _examples/systems --systems systems.json -x params.Termination.MaxTicks=730
go run . -d _examples/systems --systems systems.json -e experiment.json -r 10
xvfb-run --auto-servernum --server-num=1 go run . --tps 120 -d _examples/base -x params.Termination.MaxTicks=365
go run . -r 5 -d _examples/base -e -x params.Termination.MaxTicks=365
xvfb-run --auto-servernum --server-num=1 go run . --tps 120 -d _examples/patches -o -x params.Termination.MaxTicks=365
xvfb-run --auto-servernum --server-num=1 go run . --tps 120 -d _examples/weather_file -o -x params.Termination.MaxTicks=730
xvfb-run --auto-servernum --server-num=1 go run . --tps 120 -d _examples/weather_builtin -o -x params.Termination.MaxTicks=730
xvfb-run --auto-servernum --server-num=1 go run . --tps 120 -d _examples/systems -o -s -x params.Termination.MaxTicks=730
go run . -d _examples/systems -o -s -e -r 10
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Adds support for seasonal and "scripted" patch dynamics (#23)
- Adds support for weather/foraging period files (#24)
- Adds support for adding custom resources/parameters as well as systems (#25)
- Rework of the command line interface for a simpler syntax when using default file names (#29)

### Other

Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ Get CLI help like this:
beecs-cli -h
```

A single, slowed down run of the base example, with live plots:
A single simulation with live plots, at 30 ticks per second:

```
beecs-cli -s 30 -d _examples/base
beecs-cli -d _examples/base --observers --tps 30
```

Run the full base example with parameter variation and 10 runs per parameter set:

```
beecs-cli -r 10 -d _examples/base -e experiment.json
beecs-cli -d _examples/base --experiment -r 10
```

Print all default parameters in the tool's input format:
Expand Down Expand Up @@ -76,7 +76,7 @@ The default is file `parameters.json` in the working directory. Here is an examp

For any kind of output, an **observers file** is required.
It specifies which observers for visualizations or file output should be used.
The default is file `parameters.json` in the working directory. Here is an example:
Here is an example:

```json
{
Expand All @@ -90,6 +90,8 @@ The default is file `parameters.json` in the working directory. Here is an examp
}
```

Observers must be enabled using the `-o` flag. The default is file `observers.json` in the working directory.

These files are sufficient for single simulations with visual of file output.

With a further **experiment file**, parameters can be systematically varied in various ways.
Expand All @@ -114,6 +116,8 @@ Here is an example:
]
```

Experiments must be enabled using the `-e` flag. The default is file `experiments.json` in the working directory.

> Note: The prefix `params.` is required to unambiguously identify the type of the parameter group to modify.
See also the [examples](https://github.com/mlange-42/beecs-cli/tree/main/_examples) for the format of the required JSON files.
59 changes: 43 additions & 16 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ import (
"github.com/mlange-42/beecs/experiment"
baseparams "github.com/mlange-42/beecs/params"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"golang.org/x/exp/rand"
)

const (
_PARAMETERS = "parameters.json"
_OBSERVERS = "observers.json"
_EXPERIMENT = "experiment.json"
_SYSTEMS = "systems.json"
)

func Run() {
Expand All @@ -40,16 +42,17 @@ func rootCommand() *cobra.Command {
var dir string
var outDir string
var paramFiles []string
var expFile string
var obsFile string
var sysFile string
var expFile []string
var obsFile []string
var sysFile []string
var speed float64
var threads int
var runs int
var overwrite []string
var seed int

root := &cobra.Command{
var root cobra.Command
root = cobra.Command{
Use: "beecs-cli",
Short: "beecs-cli provides a command line interface for the beecs model.",
Long: `beecs-cli provides a command line interface for the beecs model.`,
Expand All @@ -64,6 +67,11 @@ func rootCommand() *cobra.Command {
os.Exit(0)
}

flagUsed := map[string]bool{}
root.Flags().Visit(func(f *pflag.Flag) {
flagUsed[f.Name] = true
})

rand.Seed(uint64(time.Now().UTC().Nanosecond()))

if outDir == "" {
Expand All @@ -90,8 +98,11 @@ func rootCommand() *cobra.Command {

var exp experiment.Experiment
var err error
if expFile != "" {
exp, err = util.ExperimentFromFile(path.Join(dir, expFile))
if flagUsed["experiment"] {
if len(expFile) > 1 {
return fmt.Errorf("only one (optional) experiment file can be used")
}
exp, err = util.ExperimentFromFile(path.Join(dir, expFile[0]))
if err != nil {
return err
}
Expand All @@ -103,15 +114,21 @@ func rootCommand() *cobra.Command {
}

var observers util.ObserversDef
if obsFile != "" {
observers, err = util.ObserversDefFromFile(path.Join(dir, obsFile))
if flagUsed["observers"] {
if len(obsFile) > 1 {
return fmt.Errorf("only one (optional) observers file can be used")
}
observers, err = util.ObserversDefFromFile(path.Join(dir, obsFile[0]))
if err != nil {
return err
}
}
var systems []model.System
if sysFile != "" {
systems, err = util.SystemsFromFile(path.Join(dir, sysFile))
if flagUsed["systems"] {
if len(sysFile) > 1 {
return fmt.Errorf("only one (optional) systems file can be used")
}
systems, err = util.SystemsFromFile(path.Join(dir, sysFile[0]))
if err != nil {
return err
}
Expand Down Expand Up @@ -147,11 +164,21 @@ func rootCommand() *cobra.Command {

root.Flags().StringVarP(&dir, "directory", "d", ".", "Working directory")
root.Flags().StringVarP(&outDir, "output", "", "", "Output directory if different from working directory")
root.Flags().StringSliceVarP(&paramFiles, "parameters", "p", []string{_PARAMETERS}, "Parameter files, processed in the given order")
root.Flags().StringVarP(&expFile, "experiment", "e", "", "Experiment file for parameter variation")
root.Flags().StringVarP(&obsFile, "observers", "o", _OBSERVERS, "Observers file for adding observers")
root.Flags().StringVarP(&sysFile, "systems", "", "", "Systems file for using custom systems or changing the scheduling")
root.Flags().Float64VarP(&speed, "speed", "s", 0, "Speed limit in ticks per second. Default: 0 (unlimited)")
root.Flags().StringSliceVarP(&paramFiles, "parameters", "p", []string{_PARAMETERS}, "Parameter files, processed in the given order\n")

root.Flags().StringSliceVarP(&expFile, "experiment", "e", []string{_EXPERIMENT},
"Run experiment. Optionally one experiment file for parameter variation\n")
root.Flag("experiment").NoOptDefVal = _EXPERIMENT

root.Flags().StringSliceVarP(&obsFile, "observers", "o", []string{_OBSERVERS},
"Run with observers. Optionally one observers file for adding observers\n")
root.Flag("observers").NoOptDefVal = _OBSERVERS

root.Flags().StringSliceVarP(&sysFile, "systems", "s", []string{_SYSTEMS},
"Run with custom systems. Optionally one systems file for using custom systems or changing the scheduling\n")
root.Flag("systems").NoOptDefVal = _SYSTEMS

root.Flags().Float64VarP(&speed, "tps", "", 0, "Speed limit in ticks per second. Default: 0 (unlimited)")
root.Flags().IntVarP(&threads, "threads", "t", runtime.NumCPU(), "Number of threads")
root.Flags().IntVarP(&runs, "runs", "r", 1, "Runs per parameter set")
root.Flags().IntVarP(&seed, "seed", "", 0, "Super random seed for seed generation. Default: 0 (unseeded)")
Expand All @@ -160,7 +187,7 @@ func rootCommand() *cobra.Command {
root.AddCommand(initCommand())
root.AddCommand(parametersCommand())

return root
return &root
}

func parametersCommand() *cobra.Command {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/mlange-42/arche-pixel v0.9.0
github.com/mlange-42/beecs v0.1.1-0.20240520193329-cfbd62899b75
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
)

Expand All @@ -31,7 +32,6 @@ require (
github.com/mazznoer/csscolorparser v0.1.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/image v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
gonum.org/v1/gonum v0.15.0 // indirect
Expand Down

0 comments on commit 9505e7a

Please sign in to comment.